1
0
mirror of https://github.com/google/nomulus synced 2026-07-06 16:16:38 +00:00

Compare commits

...

21 Commits

Author SHA1 Message Date
Pavlo Tkach 71a8579ece Move App Engine cron jobs to cloud scheduler (#1939) 2023-03-01 13:40:56 -05:00
Lai Jiang cda51f13dc Remove dnsRefreshRequestTime from EppResources (#1943)
We have decided to use a separate table (#1940) to track DNS refresh requests
due to performance reasons.

See: go/registry-pull-queue-redesign
2023-03-01 13:40:30 -05:00
Lai Jiang 1de5b5dcc1 Add a process time column to DnsRefreshRequest (#1948)
The value of the column would be set to START_OF_TIME for new entries.
Every time a row is read, the value is updated to the current time. This
allows concurrent reads to not repeatedly read the same entry that has the
earliest request time, because they would only look for rows that have a value
of process time that is before current time - some padding time.

This basically fulfills the same function that LEASE_PADDING gives us
when using a pull queue, whereas a task would be leased for a certain
time, during which time they would not be leased by anyone else.

See: https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/dns/ReadDnsQueueAction.java;l=99?q=readdnsqueue&ss=nomulus%2Fnomulus
2023-02-28 16:52:02 -05:00
sarahcaseybot 32279e42e4 Allow incorrect fee extensions on domain creates with default tokens (#1927)
* Modify fee extension to accept larger costs on creates with default tokens

* Add tests

* Add some comments to tests
2023-02-28 14:24:03 -05:00
Lai Jiang ba0f90bdaf Add support for Nordn upload without using pull queues. (#1925)
This PR adds an alternative method to upload Lordn to Nordn server without
using App Engine pull queue. A new database migration stage is added to control
whether a new task is scheduled with the old or new method. The
NordnUploadAction is configured to process both kind of tasks. Once the tasks
scheduled for the old tasks are all processed, we can start using the
new method exclusively.

See: go/registry-pull-queue-redesign
2023-02-28 12:57:27 -05:00
Lai Jiang 85308eb975 Ignore invalid old CRL when performing update. (#1946)
There is no point comparing the old CRL to the new ones when the old one
is invalid. This could happen when the CA cert rotates, after which the
old CRL stop being valid as it fails signature verification against the
new cert.

This change will allow us to keep updating the CRL after a CA rotation without
having to manually delete the old CRL from the database.

See b/270983553.

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1946)
<!-- Reviewable:end -->
2023-02-28 10:00:18 -05:00
Lai Jiang ed62f27a4a Update kythe vnames mapping (#1944) 2023-02-27 17:09:57 -05:00
Ben McIlwain 75851399ba Remove "letter G with stroke" from Extended Latin IDN table (#1938)
ICANN doesn't like this character because it's confusable with a normal G (the
stroke tends to get lost in the visual clutter of the descender), and .com's
Extended Latin table doesn't use it either. Best to get rid of it.
2023-02-23 16:27:15 -05:00
Lai Jiang 6d54c8d113 Add allowed license for json (#1942)
For some reason `./gradlew clean build` on master is failing for me on
multiple machines due to a new org.json:json version triggering license
violations, even though the lock files are not changing.

Note that the old versions are still present because if I remove
"The JSON license", which the old versions use, the check also fails...
2023-02-23 11:37:31 -05:00
Lai Jiang 34dfa2760e Add a table to record EPP resources needing DNS refresh (#1940) 2023-02-22 14:18:28 -05:00
Lai Jiang ff39a4a763 Change default beam job region (#1937)
For reasons that I cannot explain, the same expand recurring billing
event pipeline would fail in us-east1 but succeed in us-central1.

See:

https://pantheon.corp.google.com/dataflow/jobs/us-central1/2023-02-09_14_52_24-162498476138221714;graphView=0?project=domain-registry

https://pantheon.corp.google.com/dataflow/jobs/us-east1/2023-02-09_14_26_07-4564782062878841960;graphView=1?project=domain-registry

Also improved how the accuracy of the metrics:

It is observed that both counters are consistently higher for the same
start and end times when running in dry run mode. There is no way to
test for consistency when not running in dry run, for obviously reasons.

I can make the recurrings in scope counter consistent by not updating it
in a side-effect-causing transaction, but there is no way around the
other counter. It can only be trusted when running in dry run mode,
unfortunately.
2023-02-13 15:57:32 -05:00
gbrodman b1cd8c5a6f Add a frontend endpoint for retrieving a domain in JSON form (#1916)
We might (likely will) modify some of the fiddly bits around this (maybe
the GSON serialization, where we do the actual authorization, etc) but
this should be a decent basic shell structure for endpoints that the new
registrar console can call to retrieve JSON results.
2023-02-09 15:09:42 -05:00
gbrodman 28c7bc3085 Generate and use an IAP-enabled ID token in the proxy (#1926)
This is only generated and used if "iapClientId" is set in the proxy
config. If so, we use code similar to
https://cloud.google.com/iap/docs/authentication-howto#obtaining_an_oidc_token_for_the_default_service_account
to generate an ID token that is valid for IAP. We set the token on the
Proxy-Authorization header so that we can keep using the pre-existing
access token as well -- IAP allows for us to use either the
Authorization header or the Proxy-Authorization header.
2023-02-09 14:50:35 -05:00
gbrodman f36d22f4b1 Allow null GAIA IDs for User objects (#1933)
We were under the mistaken impression before that there was a reliable
way to, out-of-band, get a GAIA ID for a particular email address.
Unfortunately, that isn't the case (at least, not in a scalable way or
one that support agents could use). As a result, we have to allow null
GAIA IDs in the database.

When we (or the support team) create new users, we will only specify the
email address and not the GAIA ID. Then, when the user logs in for the
first time, we will have the GAIA ID from the provided ID token, and we
can populate it then.
2023-02-08 16:10:34 -05:00
Lai Jiang ef3ce79b8a Install procps in schema-deployer image (#1934)
It turns out this one uses pgrep and pkill as well, go figure...

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1934)
<!-- Reviewable:end -->
2023-02-08 09:59:47 -05:00
Lai Jiang 85317e3982 Update TMCH root certificate (#1918)
See b/260945047.

Also refactored the corresponding tests, which should future updates easier.

This change should be deployed at or around 2023-02-15T16:00:00Z.
2023-02-06 22:39:54 -05:00
Lai Jiang a53b71ecd5 Install procps (#1932)
The schema verifier script needs pgrep and pkill, which do not come with
Debian.
2023-02-06 19:45:04 -05:00
Lai Jiang fc9446876f Install curl (#1931)
Tested by running "docker build .".
2023-02-06 16:45:52 -05:00
dependabot[bot] 654b165dff Bump http-cache-semantics from 4.1.0 to 4.1.1 in /console-webapp (#1929)
Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/kornelski/http-cache-semantics/releases)
- [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: http-cache-semantics
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-06 13:22:50 -05:00
Lai Jiang 14d68d4cb2 Change base image for schema-verifier and schema-deployer (#1930)
Ubuntu 18.04 is entering EOL and the Cloud Build jobs are failing,
seemingly due to connection error to 18.04 repos:

https://pantheon.corp.google.com/cloud-build/builds;region=global/126a7c90-4322-41f1-ba1c-a10e38a32dab;step=5?project=domain-registry-dev

We use Debian 10 for the main builder, so it's better to keep everything
on the same schedule:

https://cs.opensource.google/nomulus/nomulus/+/master:release/builder/Dockerfile

Debian 10 is supported till June 2024:

https://wiki.debian.org/LTS
2023-02-06 13:09:37 -05:00
Lai Jiang bbf405d566 Fix expand recurring billing event pipeline (#1928) 2023-02-06 11:33:57 -05:00
273 changed files with 13559 additions and 10761 deletions
@@ -270,6 +270,10 @@
"moduleLicense": "Public Domain",
"moduleName": "org.tukaani:xz"
},
{
"moduleLicense": "Public Domain",
"moduleName": "org.json:json"
},
{
// "Apache License, Version 2.0".
"moduleLicense": null,
+6 -6
View File
@@ -6824,9 +6824,9 @@
"dev": true
},
"node_modules/http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
"node_modules/http-deceiver": {
@@ -17202,9 +17202,9 @@
"dev": true
},
"http-cache-semantics": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
"dev": true
},
"http-deceiver": {
@@ -138,9 +138,15 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
private final boolean isDryRun;
private final boolean advanceCursor;
private final Counter recurringsInScopeCounter =
Metrics.counter("ExpandBilling", "RecurringsInScope");
private final Counter expandedOneTimeCounter =
Metrics.counter("ExpandBilling", "ExpandedOneTime");
Metrics.counter("ExpandBilling", "Recurrings in scope for expansion");
// Note that this counter is only accurate when running in dry run mode. Because SQL persistence
// is a side effect and not idempotent, a transaction to save OneTimes could be successful but the
// transform that contains it could be still be retried, rolling back the counter increment. The
// same transform, when retried, would skip the already expanded OneTime, causing this counter to
// be lower than it should be when not in dry run mode.
// See: https://beam.apache.org/documentation/programming-guide/#user-code-idempotence
private final Counter oneTimesToExpandCounter =
Metrics.counter("ExpandBilling", "OneTimes that would be expanded");
ExpandRecurringBillingEventsPipeline(
ExpandRecurringBillingEventsPipelineOptions options, Clock clock) {
@@ -182,7 +188,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
+ "AND event_Time < :endTime "
// Recurrence should not close before start time.
+ "AND :startTime < recurrence_end_time "
// Last expansion should happen at least one year before start time.
// Last expansion should happen at least one year before end time.
+ "AND recurrence_last_expansion < :oneYearAgo "
// The recurrence should not close before next expansion time.
+ "AND recurrence_last_expansion + INTERVAL '1 YEAR' < recurrence_end_time",
@@ -195,6 +201,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
endTime.minusYears(1)),
true,
(BigInteger id) -> {
recurringsInScopeCounter.inc();
// Note that because all elements are mapped to the same dummy key, the next
// batching transform will effectively be serial. This however does not matter for
// our use case because the elements were obtained from a SQL read query, which
@@ -239,20 +246,40 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
private void expandOneRecurring(Long recurringId, ImmutableSet.Builder<ImmutableObject> results) {
Recurring recurring = tm().loadByKey(Recurring.createVKey(recurringId));
recurringsInScopeCounter.inc();
Domain domain = tm().loadByKey(Domain.createVKey(recurring.getDomainRepoId()));
Registry tld = Registry.get(domain.getTld());
// Determine the complete set of EventTimes this recurring event should expand to within
// [max(recurrenceLastExpansion + 1 yr, startTime), min(recurrenceEndTime, endTime)).
ImmutableSet<DateTime> eventTimes =
ImmutableSet.copyOf(
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closedOpen(
latestOf(recurring.getRecurrenceLastExpansion().plusYears(1), startTime),
earliestOf(recurring.getRecurrenceEndTime(), endTime))));
//
// This range should always be legal for recurrings that are returned from the query. However,
// it is possible that the recurring has changed between when the read transformation occurred
// and now. This could be caused by some out-of-process mutations (such as a domain deletion
// closing out a previously open-ended recurrence), or more subtly, Beam could execute the same
// work multiple times due to transient communication issues between workers and the scheduler.
// Such opportunistic retries are OK for pure functional transformations, but can cause
// unexpected behavior when side effects are executed more than once. For example, the
// recurrence_last_expansion field could be updated by a worker after a success expansion, which
// failed to report the status to the scheduler in time, which in turn scheduled another worker
// to work on the same batch. The second worker would see a new recurrence_last_expansion that
// causes the range to be illegal.
//
// The best way to handle any unexpected behavior is to simply drop the recurring from
// expansion, if its new state still calls for an expansion, it would be picked up the next time
// the pipeline runs.
ImmutableSet<DateTime> eventTimes;
try {
eventTimes =
ImmutableSet.copyOf(
recurring
.getRecurrenceTimeOfYear()
.getInstancesInRange(
Range.closedOpen(
latestOf(recurring.getRecurrenceLastExpansion().plusYears(1), startTime),
earliestOf(recurring.getRecurrenceEndTime(), endTime))));
} catch (IllegalArgumentException e) {
return;
}
Domain domain = tm().loadByKey(Domain.createVKey(recurring.getDomainRepoId()));
Registry tld = Registry.get(domain.getTld());
// Find the times for which the OneTime billing event are already created, making this expansion
// idempotent. There is no need to match to the domain repo ID as the cancellation matching
@@ -277,7 +304,7 @@ public class ExpandRecurringBillingEventsPipeline implements Serializable {
// Create new OneTime and DomainHistory for EventTimes that needs to be expanded.
for (DateTime eventTime : eventTimesToExpand) {
recurrenceLastExpansionTime = latestOf(recurrenceLastExpansionTime, eventTime);
expandedOneTimeCounter.inc();
oneTimesToExpandCounter.inc();
DateTime billingTime = eventTime.plus(tld.getAutoRenewGracePeriodLength());
// Note that the DomainHistory is created as of transaction time, as opposed to event time.
// This might be counterintuitive because other DomainHistories are created at the time
@@ -106,6 +106,12 @@ public final class RegistryConfig {
return config.gcpProject.projectId;
}
@Provides
@Config("cloudSchedulerServiceAccountEmail")
public static String provideCloudSchedulerServiceAccountEmail(RegistryConfigSettings config) {
return config.gcpProject.cloudSchedulerServiceAccountEmail;
}
@Provides
@Config("projectIdNumber")
public static long provideProjectIdNumber(RegistryConfigSettings config) {
@@ -54,6 +54,7 @@ public class RegistryConfigSettings {
public String backendServiceUrl;
public String toolsServiceUrl;
public String pubapiServiceUrl;
public String cloudSchedulerServiceAccountEmail;
}
/** Configuration options for OAuth settings for authenticating users. */
@@ -22,6 +22,8 @@ gcpProject:
backendServiceUrl: https://localhost
toolsServiceUrl: https://localhost
pubapiServiceUrl: https://localhost
# Service account used by Cloud Scheduler to send authenticated requests.
cloudSchedulerServiceAccountEmail: cloud-scheduler-email@email.com
gSuite:
# Publicly accessible domain name of the running G Suite instance.
@@ -427,7 +429,7 @@ misc:
beam:
# The default region to run Apache Beam (Cloud Dataflow) jobs in.
defaultJobRegion: us-east1
defaultJobRegion: us-central1
# The GCE machine type to use when a job is CPU-intensive (e. g. RDE). Be sure
# to check the VM CPU quota for the job region. In a massively parallel
# pipeline this quota can be easily reached and needs to be raised, otherwise
@@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<taskentries>
<task>
<url>/_dr/task/rdeStaging</url>
<name>rdeStaging</name>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<schedule>7 0 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<name>rdeUpload</name>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<name>tmchDnl</name>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlAction, ClaimsList)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<name>tmchSmdrl</name>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlAction, SignedMarkRevocationList)
</description>
<schedule>15 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<name>tmchCrl</name>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlAction)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<name>syncGroupMembers</name>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<name>syncRegistrarsSheet</name>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<name>resaveAllEppResourcesPipeline</name>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<!--Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
with 1st of the month 09:00 -->
<schedule>0 9 1 * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<name>expandRecurringBillingEvents</name>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>0 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<name>deleteExpiredDomains</name>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<name>deleteProberData</name>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>0 14 * * 1</schedule>
</task>
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<name>exportReservedTerms</name>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>30 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<name>exportPremiumTerms</name>
<description>
Premium terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>0 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<name>readDnsQueue</name>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>*/1 * * * *</schedule>
</task>
</taskentries>
@@ -1,150 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
<cronentries>
<!--
/cron/fanout params:
queue=<QUEUE_NAME>
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
runInEmpty // Run once, with no tld parameter
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
exclude=TLD1[,TLD2] // exclude something otherwise included
-->
<cron>
<url>/_dr/task/rdeStaging</url>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<schedule>every day 00:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlServlet, ClaimsList)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlServlet, SignedMarkRevocationList)
</description>
<schedule>every 12 hours from 00:15 to 12:15</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlServlet)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<schedule>1st monday of month 09:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>every day 03:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>every day 03:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>every monday 14:00</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>every day 05:30</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<description>
Premium terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>every day 05:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>every 1 minutes synchronized</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -94,6 +94,12 @@
<url-pattern>/registry-lock-verify</url-pattern>
</servlet-mapping>
<!-- Registrar console endpoints -->
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/console-api/*</url-pattern>
</servlet-mapping>
<!-- Security config -->
<security-constraint>
<web-resource-collection>
@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="UTF-8"?>
<taskentries>
<!--
/cron/fanout params:
queue=<QUEUE_NAME>
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
runInEmpty // Run once, with no tld parameter
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
exclude=TLD1[,TLD2] // exclude something otherwise included
-->
<task>
<url>/_dr/task/rdeStaging</url>
<name>rdeStaging</name>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date as quickly as
possible. The only job that'll run under normal circumstances is the one that's
close to midnight, since if the cursor is up-to-date, the task is a no-op.
We want it to be close to midnight because that reduces the chance that the
point-in-time code won't have to go to the extra trouble of fetching old
versions of objects from the database. However, we don't want it to run too
close to midnight, because there's always a chance that a change which was
timestamped before midnight hasn't fully been committed to the database. So
we add a 4+ minute grace period to ensure the transactions cool down, since
our queries are not transactional.
-->
<schedule>7 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<name>rdeUpload</name>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
<name>rdeReport</name>
<description>
This job is a no-op unless RdeReportCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<name>tmchDnl</name>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlAction, ClaimsList)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<name>tmchSmdrl</name>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlAction, SignedMarkRevocationList)
</description>
<schedule>15 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<name>tmchCrl</name>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlAction)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<name>syncGroupMembers</name>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<name>syncRegistrarsSheet</name>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<name>deleteProberData</name>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>0 14 * * 1</schedule>
</task>
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<name>exportReservedTerms</name>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>30 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<name>exportPremiumTerms</name>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>0 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<name>readDnsQueue</name>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>*/1 * * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<name>deleteExpiredDomains</name>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
</task>
<!--
The next two wipeout jobs are required when crash has production data.
-->
<task>
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
<name>wipeOutCloudSql</name>
<description>
This job runs an action that deletes all data in Cloud SQL.
</description>
<schedule>7 3 * * 6</schedule>
</task>
</taskentries>
@@ -1,165 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
<cronentries>
<!--
/cron/fanout params:
queue=<QUEUE_NAME>
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
runInEmpty // Run once, with no tld parameter
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
exclude=TLD1[,TLD2] // exclude something otherwise included
-->
<cron>
<url>/_dr/task/rdeStaging</url>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date as quickly as
possible. The only job that'll run under normal circumstances is the one that's
close to midnight, since if the cursor is up-to-date, the task is a no-op.
We want it to be close to midnight because that reduces the chance that the
point-in-time code won't have to go to the extra trouble of fetching old
versions of objects from the database. However, we don't want it to run too
close to midnight, because there's always a chance that a change which was
timestamped before midnight hasn't fully been committed to the database. So
we add a 4+ minute grace period to ensure the transactions cool down, since
our queries are not transactional.
-->
<schedule>every 4 hours from 00:07 to 20:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeReportCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlServlet, ClaimsList)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlServlet, SignedMarkRevocationList)
</description>
<schedule>every 12 hours from 00:15 to 12:15</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlServlet)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>every monday 14:00</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<!-- TODO: Add borgmon job to check that these files are created and updated successfully. -->
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>every day 05:30</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>every day 05:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>every 1 minutes synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>every day 03:07</schedule>
<target>backend</target>
</cron>
<!--
The next two wipeout jobs are required when crash has production data.
-->
<cron>
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
<description>
This job runs an action that deletes all data in Cloud SQL.
</description>
<schedule>every saturday 03:07</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -0,0 +1,288 @@
<?xml version="1.0" encoding="UTF-8"?>
<taskentries>
<task>
<url>/_dr/task/rdeStaging</url>
<name>rdeStaging</name>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date as quickly as
possible. The only job that'll run under normal circumstances is the one that's
close to midnight, since if the cursor is up-to-date, the task is a no-op.
We want it to be close to midnight because that reduces the chance that the
point-in-time code won't have to go to the extra trouble of fetching old
versions of objects from the database. However, we don't want it to run too
close to midnight, because there's always a chance that a change which was
timestamped before midnight hasn't fully been committed to the database. So
we add a 4+ minute grace period to ensure the transactions cool down, since
our queries are not transactional.
-->
<schedule>7 */8 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<name>rdeUpload</name>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
<name>rdeReport</name>
<description>
This job is a no-op unless RdeReportCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<name>tmchDnl</name>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlAction, ClaimsList)
</description>
<schedule>0 0,12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<name>tmchSmdrl</name>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlAction, SignedMarkRevocationList)
</description>
<schedule>15 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<name>tmchCrl</name>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlAction)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<name>syncGroupMembers</name>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<name>syncRegistrarsSheet</name>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/production/default/WEB-INF/cron.xml;l=105 -->
<task>
<url><![CDATA[/_dr/task/updateRegistrarRdapBaseUrls]]></url>
<name>updateRegistrarRdapBaseUrls</name>
<description>
This job reloads all registrar RDAP base URLs from ICANN.
</description>
<schedule>34 2 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
<name>exportDomainLists</name>
<description>
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<name>expandRecurringBillingEvents</name>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>0 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<name>deleteExpiredDomains</name>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/sendExpiringCertificateNotificationEmail]]></url>
<name>sendExpiringCertificateNotificationEmail</name>
<description>
This job runs an action that sends emails to partners if their certificates are expiring soon.
</description>
<schedule>30 4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=sunrise]]></url>
<name>nordnUploadSunrise</name>
<description>
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB. It should be
run at most every three hours, or at absolute minimum every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=claims]]></url>
<name>nordnUploadClaims</name>
<description>
This job uploads LORDN Claims CSV files for each TLD to MarksDB. It should be
run at most every three hours, or at absolute minimum every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=sunrise&pullQueue]]></url>
<name>nordnUploadSunrisePullQueue</name>
<description>
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB using
pull queue. It should be run at most every three hours, or at absolute
minimum every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordnPhase=claims&pullQueue]]></url>
<name>nordnUploadClaimsPullQueue</name>
<description>
This job uploads LORDN Claims CSV files for each TLD to MarksDB using pull
queue. It should be run at most every three hours, or at absolute minimum
every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<name>deleteProberData</name>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>0 14 * * 1</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<name>exportReservedTerms</name>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>30 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<name>exportPremiumTerms</name>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>0 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<name>readDnsQueue</name>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>*/1 * * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingStaging&runInEmpty]]></url>
<name>icannReportingStaging</name>
<description>
Create ICANN activity and transaction reports for last month, storing them in
gs://[PROJECT-ID]-reporting/icann/monthly/yyyy-MM
Upon success, enqueues the icannReportingUpload task to POST these files to ICANN.
</description>
<schedule>0 9 2 * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingUpload&runInEmpty]]></url>
<name>icannReportingUpload</name>
<description>
Checks if the monthly ICANN reports have been successfully uploaded. If they have not, attempts to upload them again.
Most of the time, this job should not do anything since the uploads are triggered when the reports are staged.
However, in the event that an upload failed for any reason (e.g. ICANN server is down, IP allow list issues),
this cron job will continue to retry uploads daily until they succeed.
</description>
<schedule>0 15 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateInvoices?shouldPublish=true&runInEmpty]]></url>
<name>generateInvoices</name>
<description>
Starts the beam/billing/InvoicingPipeline Dataflow template, which creates the overall invoice and
detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM.
Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail
reports to the associated registrars' drive folders.
See GenerateInvoicesAction for more details.
</description>
<!--WARNING: This must occur AFTER expandRecurringBillingEvents and AFTER exportSnapshot, as
it uses Bigquery as the source of truth for billable events. ExportSnapshot usually takes
about 2 hours to complete, so we give 11 hours to be safe. Normally, we give 24+ hours (see
icannReportingStaging), but the invoicing team prefers receiving the e-mail on the first of
each month. -->
<schedule>0 19 1 * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateSpec11&runInEmpty]]></url>
<name>generateSpec11</name>
<description>
Starts the beam/spec11/Spec11Pipeline Dataflow template, which creates today's Spec11
report. This report is stored in gs://[PROJECT-ID]-reporting/icann/spec11/yyyy-MM/.
This job will only send email notifications on the second of every month.
See GenerateSpec11ReportAction for more details.
</description>
<schedule>0 15 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
<name>wipeOutContactHistoryPii</name>
<description>
This job runs weekly to wipe out PII fields of ContactHistory entities
that have been in the database for a certain period of time.
</description>
<schedule>0 15 * * 1</schedule>
</task>
</taskentries>
@@ -1,288 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
<cronentries>
<!--
/cron/fanout params:
queue=<QUEUE_NAME>
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
runInEmpty // Run once, with no tld parameter
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
exclude=TLD1[,TLD2] // exclude something otherwise included
-->
<cron>
<url>/_dr/task/rdeStaging</url>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date as quickly as
possible. The only job that'll run under normal circumstances is the one that's
close to midnight, since if the cursor is up-to-date, the task is a no-op.
We want it to be close to midnight because that reduces the chance that the
point-in-time code won't have to go to the extra trouble of fetching old
versions of objects from the database. However, we don't want it to run too
close to midnight, because there's always a chance that a change which was
timestamped before midnight hasn't fully been committed to the database. So
we add a 4+ minute grace period to ensure the transactions cool down, since
our queries are not transactional.
-->
<schedule>every 8 hours from 00:07 to 20:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-report&endpoint=/_dr/task/rdeReport&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeReportCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlServlet, ClaimsList)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlServlet, SignedMarkRevocationList)
</description>
<schedule>every 12 hours from 00:15 to 12:15</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlServlet)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<!-- TODO(b/249863289): disable until it is safe to run this pipeline
<cron>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<schedule>1st monday of month 09:00</schedule>
<target>backend</target>
</cron>
-->
<cron>
<url><![CDATA[/_dr/task/updateRegistrarRdapBaseUrls]]></url>
<description>
This job reloads all registrar RDAP base URLs from ICANN.
</description>
<schedule>every day 02:34</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
<description>
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>every day 03:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>every day 03:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/sendExpiringCertificateNotificationEmail]]></url>
<description>
This job runs an action that sends emails to partners if their certificates are expiring soon.
</description>
<schedule>every day 04:30</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordn-phase=sunrise]]></url>
<description>
This job uploads LORDN Sunrise CSV files for each TLD to MarksDB. It should be
run at most every three hours, or at absolute minimum every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>every 12 hours synchronized</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=nordn&endpoint=/_dr/task/nordnUpload&forEachRealTld&lordn-phase=claims]]></url>
<description>
This job uploads LORDN Claims CSV files for each TLD to MarksDB. It should be
run at most every three hours, or at absolute minimum every 26 hours.
</description>
<!-- This may be set anywhere between "every 3 hours" and "every 25 hours". -->
<schedule>every 12 hours synchronized</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>every monday 14:00</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>every day 05:30</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>every day 05:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>every 1 minutes synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingStaging&runInEmpty]]></url>
<description>
Create ICANN activity and transaction reports for last month, storing them in
gs://[PROJECT-ID]-reporting/icann/monthly/yyyy-MM
Upon success, enqueues the icannReportingUpload task to POST these files to ICANN.
</description>
<schedule>2 of month 09:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/icannReportingUpload&runInEmpty]]></url>
<description>
Checks if the monthly ICANN reports have been successfully uploaded. If they have not, attempts to upload them again.
Most of the time, this job should not do anything since the uploads are triggered when the reports are staged.
However, in the event that an upload failed for any reason (e.g. ICANN server is down, IP allow list issues),
this cron job will continue to retry uploads daily until they succeed.
</description>
<schedule>every day 15:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateInvoices?shouldPublish=true&runInEmpty]]></url>
<description>
Starts the beam/billing/InvoicingPipeline Dataflow template, which creates the overall invoice and
detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM.
Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail
reports to the associated registrars' drive folders.
See GenerateInvoicesAction for more details.
</description>
<!--WARNING: This must occur AFTER expandRecurringBillingEvents and AFTER exportSnapshot, as
it uses Bigquery as the source of truth for billable events. ExportSnapshot usually takes
about 2 hours to complete, so we give 11 hours to be safe. Normally, we give 24+ hours (see
icannReportingStaging), but the invoicing team prefers receiving the e-mail on the first of
each month. -->
<schedule>1 of month 19:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/generateSpec11&runInEmpty]]></url>
<description>
Starts the beam/spec11/Spec11Pipeline Dataflow template, which creates today's Spec11
report. This report is stored in gs://[PROJECT-ID]-reporting/icann/spec11/yyyy-MM/.
This job will only send email notifications on the second of every month.
See GenerateSpec11ReportAction for more details.
</description>
<schedule>every day 15:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
<description>
This job runs weekly to wipe out PII fields of ContactHistory entities
that have been in the database for a certain period of time.
</description>
<schedule>every monday 15:00</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<taskentries>
<task>
<url>/_dr/task/rdeStaging</url>
<name>rdeStaging</name>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<schedule>7 0 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<name>readDnsQueue</name>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>*/1 * * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<name>syncRegistrarsSheet</name>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<name>resaveAllEppResourcesPipeline</name>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<!--Deviation from cron tasks schedule: 1st monday of month 09:00 is replaced
with 1st of the month 09:00 -->
<schedule>0 9 1 * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<name>syncGroupMembers</name>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<name>deleteExpiredDomains</name>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
<name>wipeOutCloudSql</name>
<description>
This job runs an action that deletes all data in Cloud SQL.
</description>
<schedule>7 3 * * 6</schedule>
</task>
</taskentries>
@@ -1,70 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
<cronentries>
<cron>
<url>/_dr/task/rdeStaging</url>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<schedule>every day 00:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>every 1 minutes synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<schedule>1st monday of month 09:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>every day 03:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
<description>
This job runs an action that deletes all data in Cloud SQL.
</description>
<schedule>every saturday 03:07</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -0,0 +1,156 @@
<?xml version="1.0" encoding="UTF-8"?>
<taskentries>
<task>
<url>/_dr/task/rdeStaging</url>
<name>rdeStaging</name>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date eventually.
See <a href="../../../production/default/WEB-INF/cron.xml">production config</a> for an
explanation of job starting times.
-->
<schedule>7 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<name>rdeUpload</name>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>0 */4 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<name>tmchDnl</name>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlAction, ClaimsList)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<name>tmchSmdrl</name>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlAction, SignedMarkRevocationList)
</description>
<schedule>15 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<name>tmchCrl</name>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlAction)
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<name>syncGroupMembers</name>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<name>syncRegistrarsSheet</name>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>0 */1 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
<name>exportDomainLists</name>
<description>
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
</description>
<schedule>0 */12 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<name>expandRecurringBillingEvents</name>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>0 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<name>deleteExpiredDomains</name>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>7 3 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<name>deleteProberData</name>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>0 14 * * 1</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<name>exportReservedTerms</name>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>30 5 * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<name>exportPremiumTerms</name>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>0 5 * * *</schedule>
</task>
<!-- TODO: @ptkach add resaveAllEppResourcesPipelineAction https://cs.opensource.google/nomulus/nomulus/+/master:core/src/main/java/google/registry/env/sandbox/default/WEB-INF/cron.xml;l=89 -->
<task>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<name>readDnsQueue</name>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>*/1 * * * *</schedule>
</task>
<task>
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
<name>wipeOutContactHistoryPii</name>
<description>
This job runs weekly to wipe out PII fields of ContactHistory entities
that have been in the database for a certain period of time.
</description>
<schedule>0 15 * * 1</schedule>
</task>
</taskentries>
@@ -1,177 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--TODO: ptkach - Remove this file after cloud scheduler is fully up and running -->
<cronentries>
<!--
/cron/fanout params:
queue=<QUEUE_NAME>
endpoint=<ENDPOINT_NAME> // URL Path of servlet, which may contain placeholders:
runInEmpty // Run once, with no tld parameter
forEachRealTld // Run for tlds with getTldType() == TldType.REAL
forEachTestTld // Run for tlds with getTldType() == TldType.TEST
exclude=TLD1[,TLD2] // exclude something otherwise included
-->
<cron>
<url>/_dr/task/rdeStaging</url>
<description>
This job generates a full RDE escrow deposit as a single gigantic XML document
and streams it to cloud storage. When this job has finished successfully, it'll
launch a separate task that uploads the deposit file to Iron Mountain via SFTP.
</description>
<!--
This only needs to run once per day, but we launch additional jobs in case the
cursor is lagging behind, so it'll catch up to the current date eventually.
See <a href="../../../production/default/WEB-INF/cron.xml">production config</a> for an
explanation of job starting times.
-->
<schedule>every 12 hours from 00:07 to 12:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=rde-upload&endpoint=/_dr/task/rdeUpload&forEachRealTld]]></url>
<description>
This job is a no-op unless RdeUploadCursor falls behind for some reason.
</description>
<schedule>every 4 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchDnl&runInEmpty]]></url>
<description>
This job downloads the latest DNL from MarksDB and inserts it into the database.
(See: TmchDnlServlet, ClaimsList)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchSmdrl&runInEmpty]]></url>
<description>
This job downloads the latest SMDRL from MarksDB and inserts it into the database.
(See: TmchSmdrlServlet, SignedMarkRevocationList)
</description>
<schedule>every 12 hours from 00:15 to 12:15</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=marksdb&endpoint=/_dr/task/tmchCrl&runInEmpty]]></url>
<description>
This job downloads the latest CRL from MarksDB and inserts it into the database.
(See: TmchCrlServlet)
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/syncGroupMembers&runInEmpty]]></url>
<description>
Syncs RegistrarContact changes in the past hour to Google Groups.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=sheet&endpoint=/_dr/task/syncRegistrarsSheet&runInEmpty]]></url>
<description>
Synchronize Registrar entities to Google Spreadsheets.
</description>
<schedule>every 1 hours synchronized</schedule>
<target>backend</target>
</cron>
<!-- TODO(b/249863289): disable until it is safe to run this pipeline
<cron>
<url><![CDATA[/_dr/task/resaveAllEppResourcesPipeline?fast=true]]></url>
<description>
This job resaves all our resources, projected in time to "now".
</description>
<schedule>1st monday of month 09:00</schedule>
<target>backend</target>
</cron>
-->
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportDomainLists&runInEmpty]]></url>
<description>
This job exports lists of all active domain names to Google Drive and Google Cloud Storage.
</description>
<schedule>every 12 hours synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/expandRecurringBillingEvents?advanceCursor]]></url>
<description>
This job runs an action that creates synthetic OneTime billing events from Recurring billing
events. Events are created for all instances of Recurring billing events that should exist
between the RECURRING_BILLING cursor's time and the execution time of the action.
</description>
<schedule>every day 03:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/deleteExpiredDomains]]></url>
<description>
This job runs an action that deletes domains that are past their
autorenew end date.
</description>
<schedule>every day 03:07</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/deleteProberData&runInEmpty]]></url>
<description>
This job clears out data from probers and runs once a week.
</description>
<schedule>every monday 14:00</schedule>
<timezone>UTC</timezone>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportReservedTerms&forEachRealTld]]></url>
<description>
Reserved terms export to Google Drive job for creating once-daily exports.
</description>
<schedule>every day 05:30</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/fanout?queue=retryable-cron-tasks&endpoint=/_dr/task/exportPremiumTerms&forEachRealTld]]></url>
<description>
Exports premium price lists to the Google Drive folders for each TLD once per day.
</description>
<schedule>every day 05:00</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/cron/readDnsQueue?jitterSeconds=45]]></url>
<description>
Lease all tasks from the dns-pull queue, group by TLD, and invoke PublishDnsUpdates for each
group.
</description>
<schedule>every 1 minutes synchronized</schedule>
<target>backend</target>
</cron>
<cron>
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
<description>
This job runs weekly to wipe out PII fields of ContactHistory entities
that have been in the database for a certain period of time.
</description>
<schedule>every monday 15:00</schedule>
<target>backend</target>
</cron>
</cronentries>
@@ -86,6 +86,8 @@ import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.billing.BillingEvent.Recurring;
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
import google.registry.model.common.DatabaseMigrationStateSchedule;
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainCommand;
import google.registry.model.domain.DomainCommand.Create;
@@ -123,6 +125,7 @@ import google.registry.model.tmch.ClaimsList;
import google.registry.model.tmch.ClaimsListDao;
import google.registry.persistence.VKey;
import google.registry.tmch.LordnTaskUtils;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -162,6 +165,7 @@ import org.joda.time.Duration;
* @error {@link DomainFlowTmchUtils.NoMarksFoundMatchingDomainException}
* @error {@link DomainFlowTmchUtils.FoundMarkNotYetValidException}
* @error {@link DomainFlowTmchUtils.FoundMarkExpiredException}
* @error {@link DomainFlowTmchUtils.SignedMarkRevokedErrorException}
* @error {@link DomainFlowUtils.NotAuthorizedForTldException}
* @error {@link DomainFlowUtils.AcceptedTooLongAgoException}
* @error {@link DomainFlowUtils.BadDomainNameCharacterException}
@@ -276,8 +280,12 @@ public final class DomainCreateFlow implements TransactionalFlow {
registrarId,
now,
eppInput.getSingleExtension(AllocationTokenExtension.class));
boolean defaultTokenUsed = false;
if (!allocationToken.isPresent() && !registry.getDefaultPromoTokens().isEmpty()) {
allocationToken = checkForDefaultToken(registry, command);
if (allocationToken.isPresent()) {
defaultTokenUsed = true;
}
}
boolean isAnchorTenant =
isAnchorTenant(
@@ -336,7 +344,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
FeesAndCredits feesAndCredits =
pricingLogic.getCreatePrice(
registry, targetId, now, years, isAnchorTenant, allocationToken);
validateFeeChallenge(feeCreate, feesAndCredits);
validateFeeChallenge(feeCreate, feesAndCredits, defaultTokenUsed);
Optional<SecDnsCreateExtension> secDnsCreate =
validateSecDnsExtension(eppInput.getSingleExtension(SecDnsCreateExtension.class));
DateTime registrationExpirationTime = leapSafeAddYears(now, years);
@@ -376,7 +384,7 @@ public final class DomainCreateFlow implements TransactionalFlow {
reservationTypes.contains(NAME_COLLISION)
? ImmutableSet.of(SERVER_HOLD)
: ImmutableSet.of();
Domain domain =
Domain.Builder domainBuilder =
new Domain.Builder()
.setCreationRegistrarId(registrarId)
.setPersistedCurrentSponsorRegistrarId(registrarId)
@@ -396,7 +404,14 @@ public final class DomainCreateFlow implements TransactionalFlow {
.setContacts(command.getContacts())
.addGracePeriod(
GracePeriod.forBillingEvent(GracePeriodStatus.ADD, repoId, createBillingEvent))
.build();
.setLordnPhase(
!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
.equals(MigrationState.NORDN_SQL)
? LordnPhase.NONE
: hasSignedMarks
? LordnPhase.SUNRISE
: hasClaimsNotice ? LordnPhase.CLAIMS : LordnPhase.NONE);
Domain domain = domainBuilder.build();
if (allocationToken.isPresent()
&& allocationToken.get().getTokenType().equals(TokenType.PACKAGE)) {
if (years > 1) {
@@ -696,7 +711,9 @@ public final class DomainCreateFlow implements TransactionalFlow {
if (newDomain.shouldPublishToDns()) {
dnsQueue.addDomainRefreshTask(newDomain.getDomainName());
}
if (hasClaimsNotice || hasSignedMarks) {
if (!DatabaseMigrationStateSchedule.getValueAtTime(tm().getTransactionTime())
.equals(MigrationState.NORDN_SQL)
&& (hasClaimsNotice || hasSignedMarks)) {
LordnTaskUtils.enqueueDomainTask(newDomain);
}
}
@@ -778,12 +778,13 @@ public class DomainFlowUtils {
*/
public static void validateFeeChallenge(
final Optional<? extends FeeTransformCommandExtension> feeCommand,
FeesAndCredits feesAndCredits)
FeesAndCredits feesAndCredits,
boolean defaultTokenUsed)
throws EppException {
if (feesAndCredits.hasAnyPremiumFees() && !feeCommand.isPresent()) {
throw new FeesRequiredForPremiumNameException();
}
validateFeesAckedIfPresent(feeCommand, feesAndCredits);
validateFeesAckedIfPresent(feeCommand, feesAndCredits, defaultTokenUsed);
}
/**
@@ -795,7 +796,8 @@ public class DomainFlowUtils {
*/
public static void validateFeesAckedIfPresent(
final Optional<? extends FeeTransformCommandExtension> feeCommand,
FeesAndCredits feesAndCredits)
FeesAndCredits feesAndCredits,
boolean defaultTokenUsed)
throws EppException {
// Check for the case where a fee command extension was required but not provided.
// This only happens when the total fees are non-zero and include custom fees requiring the
@@ -856,7 +858,9 @@ public class DomainFlowUtils {
// Checking if total amount is expected. Extra fees that we are not expecting may be passed in.
// Or if there is only a single fee type expected.
if (!feeTotal.equals(feesAndCredits.getTotalCost())) {
throw new FeesMismatchException(feesAndCredits.getTotalCost());
if (!defaultTokenUsed || feeTotal.isLessThan(feesAndCredits.getTotalCost())) {
throw new FeesMismatchException(feesAndCredits.getTotalCost());
}
}
}
@@ -199,7 +199,7 @@ public final class DomainRenewFlow implements TransactionalFlow {
now,
years,
existingRecurringBillingEvent);
validateFeeChallenge(feeRenew, feesAndCredits);
validateFeeChallenge(feeRenew, feesAndCredits, false);
flowCustomLogic.afterValidation(
AfterValidationParameters.newBuilder()
.setExistingDomain(existingDomain)
@@ -226,7 +226,7 @@ public final class DomainRestoreRequestFlow implements TransactionalFlow {
if (!existingDomain.getGracePeriodStatuses().contains(GracePeriodStatus.REDEMPTION)) {
throw new DomainNotEligibleForRestoreException();
}
validateFeeChallenge(feeUpdate, feesAndCredits);
validateFeeChallenge(feeUpdate, feesAndCredits, false);
}
private static Domain performRestore(
@@ -210,7 +210,7 @@ public final class DomainTransferRequestFlow implements TransactionalFlow {
}
if (feesAndCredits.isPresent()) {
validateFeeChallenge(feeTransfer, feesAndCredits.get());
validateFeeChallenge(feeTransfer, feesAndCredits.get(), false);
}
HistoryEntryId domainHistoryId = createHistoryEntryId(existingDomain);
historyBuilder
@@ -231,7 +231,7 @@ public final class DomainUpdateFlow implements TransactionalFlow {
Optional<FeeUpdateCommandExtension> feeUpdate =
eppInput.getSingleExtension(FeeUpdateCommandExtension.class);
FeesAndCredits feesAndCredits = pricingLogic.getUpdatePrice(registry, targetId, now);
validateFeesAckedIfPresent(feeUpdate, feesAndCredits);
validateFeesAckedIfPresent(feeUpdate, feesAndCredits, false);
verifyNotInPendingDelete(
add.getContacts(),
command.getInnerChange().getRegistrant(),
@@ -68,7 +68,6 @@ U+011F # LATIN SMALL LETTER G WITH BREVE
U+01E7 # LATIN SMALL LETTER G WITH CARON
U+0121 # LATIN SMALL LETTER G WITH DOT ABOVE
U+0123 # LATIN SMALL LETTER G WITH CEDILLA
U+01E5 # LATIN SMALL LETTER G WITH STROKE
U+0068 # LATIN SMALL LETTER H
U+0127 # LATIN SMALL LETTER H WITH STROKE
U+0069 # LATIN SMALL LETTER I
@@ -16,6 +16,7 @@ package google.registry.model;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.gson.annotations.Expose;
import javax.annotation.Nullable;
import javax.persistence.Column;
import javax.persistence.Embeddable;
@@ -28,6 +29,7 @@ import org.joda.time.DateTime;
public class CreateAutoTimestamp extends ImmutableObject implements UnsafeSerializable {
@Column(nullable = false)
@Expose
DateTime creationTime;
@PrePersist
@@ -31,8 +31,8 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.gson.annotations.Expose;
import google.registry.config.RegistryConfig;
import google.registry.dns.RefreshDnsAction;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.transfer.TransferData;
import google.registry.persistence.VKey;
@@ -41,7 +41,6 @@ import java.time.Duration;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.AttributeOverride;
@@ -67,7 +66,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
*
* @see <a href="https://tools.ietf.org/html/rfc5730">RFC 5730</a>
*/
@Transient String repoId;
@Expose @Transient String repoId;
/**
* The ID of the registrar that is currently sponsoring this resource.
@@ -75,7 +74,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
* resource fields.
*/
String currentSponsorRegistrarId;
@Expose String currentSponsorRegistrarId;
/**
* The ID of the registrar that created this resource.
@@ -83,7 +82,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
* resource fields.
*/
String creationRegistrarId;
@Expose String creationRegistrarId;
/**
* The ID of the registrar that last updated this resource.
@@ -92,7 +91,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
* the resource has never been modified.
*/
String lastEppUpdateRegistrarId;
@Expose String lastEppUpdateRegistrarId;
/**
* The time when this resource was created.
@@ -106,6 +105,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
*/
// Need to override the default non-null column attribute.
@AttributeOverride(name = "creationTime", column = @Column)
@Expose
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
/**
@@ -130,27 +130,10 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
* the resource has never been modified.
*/
DateTime lastEppUpdateTime;
@Expose DateTime lastEppUpdateTime;
/** Status values associated with this resource. */
Set<StatusValue> statuses;
/**
* When this domain/host's DNS was requested to be refreshed, or null if its DNS is up-to-date.
*
* <p>This will almost always be null except in the couple of minutes' interval between when a
* DNS-affecting create or update operation takes place and when the {@link RefreshDnsAction}
* runs, which resets this back to null upon completion of the DNS refresh task. This is a {@link
* DateTime} rather than a simple dirty boolean so that the DNS refresh action can order by the
* DNS refresh request time and take action on the oldest ones first.
*
* <p>Note that in the {@code DomainHistory}/{@code HostHistory} table this value means something
* slightly different: It means that the given domain/host action requested a DNS update. Unlike
* on the {@code Domain}/{code Host} table, this value is not then subsequently nulled out once
* the DNS refresh is complete; rather, it remains as a permanent record of which actions were
* DNS-affecting and which were not.
*/
@Transient @Nullable protected DateTime dnsRefreshRequestTime;
@Expose Set<StatusValue> statuses;
public String getRepoId() {
return repoId;
@@ -203,19 +186,6 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
return deletionTime;
}
/**
* Returns the DNS refresh request time iff this domain/host's DNS needs refreshing, otherwise
* absent.
*/
public Optional<DateTime> getDnsRefreshRequestTime() {
return Optional.ofNullable(dnsRefreshRequestTime);
}
@SuppressWarnings("unused")
private void setInternalDnsRefreshRequestTime(DateTime time) {
dnsRefreshRequestTime = time;
}
/** Return a clone of the resource with timed status values modified using the given time. */
public abstract EppResource cloneProjectedAtTime(DateTime now);
@@ -369,11 +339,6 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
return thisCastToDerived();
}
public B setDnsRefreshRequestTime(Optional<DateTime> dnsRefreshRequestTime) {
getInstance().dnsRefreshRequestTime = dnsRefreshRequestTime.orElse(null);
return thisCastToDerived();
}
/** Build the resource, nullifying empty strings and sets and setting defaults. */
@Override
public T build() {
@@ -44,6 +44,8 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static boolean useUncachedForTest = false;
public enum PrimaryDatabase {
CLOUD_SQL,
DATASTORE
@@ -85,7 +87,10 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
SQL_ONLY(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
/** Toggles SQL Sequence based allocateId */
SEQUENCE_BASED_ALLOCATE_ID(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
SEQUENCE_BASED_ALLOCATE_ID(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY),
/** Use SQL-based Nordn upload flow instead of the pull queue-based one. */
NORDN_SQL(PrimaryDatabase.CLOUD_SQL, false, ReplayDirection.NO_REPLAY);
private final PrimaryDatabase primaryDatabase;
private final boolean isReadOnly;
@@ -164,7 +169,9 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
MigrationState.SQL_ONLY,
MigrationState.SQL_PRIMARY_READ_ONLY,
MigrationState.SQL_PRIMARY)
.putAll(MigrationState.SQL_ONLY, MigrationState.SEQUENCE_BASED_ALLOCATE_ID);
.putAll(MigrationState.SQL_ONLY, MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
.putAll(MigrationState.SEQUENCE_BASED_ALLOCATE_ID, MigrationState.NORDN_SQL)
.putAll(MigrationState.NORDN_SQL, MigrationState.SEQUENCE_BASED_ALLOCATE_ID);
// In addition, we can always transition from a state to itself (useful when updating the map).
Arrays.stream(MigrationState.values()).forEach(state -> builder.put(state, state));
@@ -181,8 +188,8 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
public TimedTransitionProperty<MigrationState> migrationTransitions =
TimedTransitionProperty.withInitialValue(MigrationState.DATASTORE_ONLY);
// Required for Objectify initialization
private DatabaseMigrationStateSchedule() {}
// Required for Hibernate initialization
protected DatabaseMigrationStateSchedule() {}
@VisibleForTesting
public DatabaseMigrationStateSchedule(
@@ -205,6 +212,11 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
CACHE.invalidateAll();
}
@VisibleForTesting
public static void useUncachedForTest() {
useUncachedForTest = true;
}
/** Loads the currently-set migration schedule from the cache, or the default if none exists. */
public static TimedTransitionProperty<MigrationState> get() {
return CACHE.get(DatabaseMigrationStateSchedule.class);
@@ -212,7 +224,9 @@ public class DatabaseMigrationStateSchedule extends CrossTldSingleton {
/** Returns the database migration status at the given time. */
public static MigrationState getValueAtTime(DateTime dateTime) {
return get().getValueAtTime(dateTime);
return useUncachedForTest
? getUncached().getValueAtTime(dateTime)
: get().getValueAtTime(dateTime);
}
/** Loads the currently-set migration schedule from SQL, or the default if none exists. */
@@ -58,7 +58,6 @@ import org.joda.time.DateTime;
@Index(columnList = "techContact"),
@Index(columnList = "tld"),
@Index(columnList = "registrantContact"),
@Index(columnList = "dnsRefreshRequestTime"),
@Index(columnList = "lordnPhase"),
@Index(columnList = "billing_recurrence_id"),
@Index(columnList = "transfer_billing_event_id"),
@@ -200,7 +199,6 @@ public class Domain extends DomainBase implements ForeignKeyedEppResource {
.setSubordinateHosts(domainBase.getSubordinateHosts())
.setStatusValues(domainBase.getStatusValues())
.setTransferData(domainBase.getTransferData())
.setDnsRefreshRequestTime(domainBase.getDnsRefreshRequestTime())
.setLordnPhase(domainBase.getLordnPhase())
.setCurrentPackageToken(domainBase.getCurrentPackageToken().orElse(null));
}
@@ -40,6 +40,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.gson.annotations.Expose;
import google.registry.flows.ResourceFlowUtils;
import google.registry.model.EppResource;
import google.registry.model.EppResource.ResourceWithTransferData;
@@ -121,20 +122,20 @@ public class DomainBase extends EppResource
*
* @invariant domainName == domainName.toLowerCase(Locale.ENGLISH)
*/
String domainName;
@Expose String domainName;
/** The top level domain this is under, de-normalized from {@link #domainName}. */
String tld;
/** References to hosts that are the nameservers for the domain. */
@Transient Set<VKey<Host>> nsHosts;
@Expose @Transient Set<VKey<Host>> nsHosts;
/** Contacts. */
VKey<Contact> adminContact;
@Expose VKey<Contact> adminContact;
VKey<Contact> billingContact;
VKey<Contact> techContact;
VKey<Contact> registrantContact;
@Expose VKey<Contact> billingContact;
@Expose VKey<Contact> techContact;
@Expose VKey<Contact> registrantContact;
/** Authorization info (aka transfer secret) of the domain. */
@Embedded
@@ -175,10 +176,10 @@ public class DomainBase extends EppResource
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
Set<String> subordinateHosts;
@Expose Set<String> subordinateHosts;
/** When this domain's registration will expire. */
DateTime registrationExpirationTime;
@Expose DateTime registrationExpirationTime;
/**
* The poll message associated with this domain being deleted.
@@ -230,7 +231,7 @@ public class DomainBase extends EppResource
*
* <p>Can be null if the resource has never been transferred.
*/
DateTime lastTransferTime;
@Expose DateTime lastTransferTime;
/**
* When the domain's autorenewal status will expire.
@@ -273,13 +274,6 @@ public class DomainBase extends EppResource
return lordnPhase;
}
@Access(AccessType.PROPERTY)
@SuppressWarnings("unused")
@Column(name = "dnsRefreshRequestTime")
private DateTime getInternalDnsRefreshRequestTime() {
return getDnsRefreshRequestTime().orElse(null);
}
public ImmutableSet<String> getSubordinateHosts() {
return nullToEmptyImmutableCopy(subordinateHosts);
}
@@ -49,7 +49,6 @@ import javax.persistence.Table;
@Index(columnList = "creationTime"),
@Index(columnList = "deletionTime"),
@Index(columnList = "currentSponsorRegistrarId"),
@Index(columnList = "dnsRefreshRequestTime")
})
@ExternalMessagingName("host")
@WithVKey(String.class)
@@ -94,7 +93,6 @@ public class Host extends HostBase implements ForeignKeyedEppResource {
.setPersistedCurrentSponsorRegistrarId(hostBase.getPersistedCurrentSponsorRegistrarId())
.setRepoId(hostBase.getRepoId())
.setSuperordinateDomain(hostBase.getSuperordinateDomain())
.setDnsRefreshRequestTime(hostBase.getDnsRefreshRequestTime())
.setStatusValues(hostBase.getStatusValues());
}
}
@@ -32,7 +32,6 @@ import java.util.Set;
import javax.annotation.Nullable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.MappedSuperclass;
import org.joda.time.DateTime;
@@ -86,13 +85,6 @@ public class HostBase extends EppResource {
*/
DateTime lastSuperordinateChange;
@Access(AccessType.PROPERTY)
@SuppressWarnings("unused")
@Column(name = "dnsRefreshRequestTime")
private DateTime getInternalDnsRefreshRequestTime() {
return getDnsRefreshRequestTime().orElse(null);
}
public String getHostName() {
return hostName;
}
@@ -25,6 +25,7 @@ import google.registry.monitoring.whitebox.WhiteboxModule;
import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
import google.registry.ui.server.registrar.ConsoleUiAction;
@@ -61,6 +62,8 @@ interface FrontendRequestComponent {
RegistryLockVerifyAction registryLockVerifyAction();
ConsoleDomainGetAction consoleDomainGetAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
@Override public abstract Builder requestModule(RequestModule requestModule);
@@ -22,6 +22,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gson.annotations.Expose;
import google.registry.model.EppResource;
import google.registry.model.ImmutableObject;
import google.registry.model.contact.Contact;
@@ -52,7 +53,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
.collect(toImmutableMap(Class::getSimpleName, identity()));
// The primary key for the referenced entity.
Serializable key;
@Expose Serializable key;
Class<? extends T> kind;
@@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableList;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import javax.inject.Qualifier;
import javax.inject.Singleton;
/**
@@ -30,15 +31,26 @@ import javax.inject.Singleton;
public class AuthModule {
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
private static final String SA_ISSUER_URL = "https://accounts.google.com";
/** Provides the custom authentication mechanisms (including OAuth). */
@Provides
ImmutableList<AuthenticationMechanism> provideApiAuthenticationMechanisms(
OAuthAuthenticationMechanism oauthAuthenticationMechanism,
IapHeaderAuthenticationMechanism iapHeaderAuthenticationMechanism) {
return ImmutableList.of(oauthAuthenticationMechanism, iapHeaderAuthenticationMechanism);
IapHeaderAuthenticationMechanism iapHeaderAuthenticationMechanism,
ServiceAccountAuthenticationMechanism serviceAccountAuthenticationMechanism) {
return ImmutableList.of(
oauthAuthenticationMechanism,
iapHeaderAuthenticationMechanism,
serviceAccountAuthenticationMechanism);
}
@Qualifier
@interface IAP {}
@Qualifier
@interface ServiceAccount {}
/** Provides the OAuthService instance. */
@Provides
OAuthService provideOauthService() {
@@ -46,10 +58,18 @@ public class AuthModule {
}
@Provides
@IAP
@Singleton
TokenVerifier provideTokenVerifier(
@Config("projectId") String projectId, @Config("projectIdNumber") long projectIdNumber) {
String audience = String.format("/projects/%d/apps/%s", projectIdNumber, projectId);
return TokenVerifier.newBuilder().setAudience(audience).setIssuer(IAP_ISSUER_URL).build();
}
@Provides
@ServiceAccount
@Singleton
TokenVerifier provideServiceAccountTokenVerifier(@Config("projectId") String projectId) {
return TokenVerifier.newBuilder().setAudience(projectId).setIssuer(SA_ISSUER_URL).build();
}
}
@@ -14,15 +14,11 @@
package google.registry.request.auth;
import com.google.api.client.json.webtoken.JsonWebSignature;
import com.google.auth.oauth2.TokenVerifier;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryEnvironment;
import google.registry.model.console.User;
import google.registry.model.console.UserDao;
import google.registry.request.auth.AuthModule.IAP;
import java.util.Optional;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
@@ -37,41 +33,22 @@ import javax.servlet.http.HttpServletRequest;
* @see <a href="https://cloud.google.com/iap/docs/signed-headers-howto">the documentation on GCP
* IAP's signed headers for more information.</a>
*/
public class IapHeaderAuthenticationMechanism implements AuthenticationMechanism {
public class IapHeaderAuthenticationMechanism extends IdTokenAuthenticationBase {
private static final String ID_TOKEN_HEADER_NAME = "X-Goog-IAP-JWT-Assertion";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
// A workaround that allows "use" of the IAP-based authenticator when running local testing, i.e.
// the RegistryTestServer
private static Optional<User> userForTesting = Optional.empty();
private final TokenVerifier tokenVerifier;
@Inject
public IapHeaderAuthenticationMechanism(TokenVerifier tokenVerifier) {
this.tokenVerifier = tokenVerifier;
public IapHeaderAuthenticationMechanism(@IAP TokenVerifier tokenVerifier) {
super(tokenVerifier);
}
@Override
public AuthResult authenticate(HttpServletRequest request) {
if (RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST)
&& userForTesting.isPresent()) {
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userForTesting.get()));
}
String rawIdToken = request.getHeader(ID_TOKEN_HEADER_NAME);
if (rawIdToken == null) {
return AuthResult.NOT_AUTHENTICATED;
}
JsonWebSignature token;
try {
token = tokenVerifier.verify(rawIdToken);
} catch (TokenVerifier.VerificationException e) {
logger.atInfo().withCause(e).log("Error when verifying access token");
return AuthResult.NOT_AUTHENTICATED;
}
String emailAddress = (String) token.getPayload().get("email");
String rawTokenFromRequest(HttpServletRequest request) {
return request.getHeader(ID_TOKEN_HEADER_NAME);
}
@Override
AuthResult authResultFromEmail(String emailAddress) {
Optional<User> maybeUser = UserDao.loadUser(emailAddress);
if (!maybeUser.isPresent()) {
logger.atInfo().log("No user found for email address %s", emailAddress);
@@ -80,8 +57,4 @@ public class IapHeaderAuthenticationMechanism implements AuthenticationMechanism
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(maybeUser.get()));
}
@VisibleForTesting
public static void setUserAuthInfoForTestServer(@Nullable User user) {
userForTesting = Optional.ofNullable(user);
}
}
@@ -0,0 +1,70 @@
// Copyright 2022 The Nomulus Authors. 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 google.registry.request.auth;
import com.google.api.client.json.webtoken.JsonWebSignature;
import com.google.auth.oauth2.TokenVerifier;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryEnvironment;
import google.registry.model.console.User;
import java.util.Optional;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
public abstract class IdTokenAuthenticationBase implements AuthenticationMechanism {
public static final FluentLogger logger = FluentLogger.forEnclosingClass();
// A workaround that allows "use" of the IAP-based authenticator when running local testing, i.e.
// the RegistryTestServer
private static Optional<User> userForTesting = Optional.empty();
private final TokenVerifier tokenVerifier;
public IdTokenAuthenticationBase(TokenVerifier tokenVerifier) {
this.tokenVerifier = tokenVerifier;
}
abstract String rawTokenFromRequest(HttpServletRequest request);
abstract AuthResult authResultFromEmail(String email);
@Override
public AuthResult authenticate(HttpServletRequest request) {
if (RegistryEnvironment.get().equals(RegistryEnvironment.UNITTEST)
&& userForTesting.isPresent()) {
return AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userForTesting.get()));
}
String rawIdToken = rawTokenFromRequest(request);
if (rawIdToken == null) {
return AuthResult.NOT_AUTHENTICATED;
}
JsonWebSignature token;
try {
token = tokenVerifier.verify(rawIdToken);
} catch (TokenVerifier.VerificationException e) {
logger.atInfo().withCause(e).log("Error when verifying access token");
return AuthResult.NOT_AUTHENTICATED;
}
String emailAddress = (String) token.getPayload().get("email");
return authResultFromEmail(emailAddress);
}
@VisibleForTesting
public static void setUserAuthInfoForTestServer(@Nullable User user) {
userForTesting = Optional.ofNullable(user);
}
}
@@ -0,0 +1,62 @@
// Copyright 2023 The Nomulus Authors. 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 google.registry.request.auth;
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
import static google.registry.request.auth.AuthLevel.APP;
import com.google.auth.oauth2.TokenVerifier;
import google.registry.config.RegistryConfig.Config;
import google.registry.request.auth.AuthModule.ServiceAccount;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
/**
* A way to authenticate HTTP requests signed by Service Account
*
* <p>Currently used by cloud scheduler service account
*/
public class ServiceAccountAuthenticationMechanism extends IdTokenAuthenticationBase {
private final String cloudSchedulerEmailPrefix;
private static final String BEARER_PREFIX = "Bearer ";
@Inject
public ServiceAccountAuthenticationMechanism(
@ServiceAccount TokenVerifier tokenVerifier,
@Config("cloudSchedulerServiceAccountEmail") String cloudSchedulerEmailPrefix) {
super(tokenVerifier);
this.cloudSchedulerEmailPrefix = cloudSchedulerEmailPrefix;
}
@Override
String rawTokenFromRequest(HttpServletRequest request) {
String rawToken = request.getHeader(AUTHORIZATION);
if (rawToken != null && rawToken.startsWith(BEARER_PREFIX)) {
return rawToken.substring(BEARER_PREFIX.length());
}
return null;
}
@Override
AuthResult authResultFromEmail(String emailAddress) {
if (emailAddress.equals(cloudSchedulerEmailPrefix)) {
return AuthResult.create(APP);
} else {
return AuthResult.NOT_AUTHENTICATED;
}
}
}
@@ -49,7 +49,6 @@ U+011F # LATIN SMALL LETTER G WITH BREVE
U+01E7 # LATIN SMALL LETTER G WITH CARON
U+0121 # LATIN SMALL LETTER G WITH DOT ABOVE
U+0123 # LATIN SMALL LETTER G WITH CEDILLA
U+01E5 # LATIN SMALL LETTER G WITH STROKE
U+0068 # LATIN SMALL LETTER H
U+0127 # LATIN SMALL LETTER H WITH STROKE
U+0069 # LATIN SMALL LETTER I
@@ -66,7 +66,12 @@ public final class LordnTaskUtils {
}
/** Returns the corresponding CSV LORDN line for a sunrise domain. */
public static String getCsvLineForSunriseDomain(Domain domain, DateTime transactionTime) {
public static String getCsvLineForSunriseDomain(Domain domain) {
return getCsvLineForSunriseDomain(domain, domain.getCreationTime());
}
// TODO: Merge into the function above after pull queue migration.
private static String getCsvLineForSunriseDomain(Domain domain, DateTime transactionTime) {
return Joiner.on(',')
.join(
domain.getRepoId(),
@@ -77,7 +82,12 @@ public final class LordnTaskUtils {
}
/** Returns the corresponding CSV LORDN line for a claims domain. */
public static String getCsvLineForClaimsDomain(Domain domain, DateTime transactionTime) {
public static String getCsvLineForClaimsDomain(Domain domain) {
return getCsvLineForClaimsDomain(domain, domain.getCreationTime());
}
// TODO: Merge into the function above after pull queue migration.
private static String getCsvLineForClaimsDomain(Domain domain, DateTime transactionTime) {
return Joiner.on(',')
.join(
domain.getRepoId(),
@@ -100,16 +110,8 @@ public final class LordnTaskUtils {
private LordnTaskUtils() {}
public enum LordnPhase {
SUNRISE(QUEUE_SUNRISE),
CLAIMS(QUEUE_CLAIMS),
NONE(null);
final String queue;
LordnPhase(String queue) {
this.queue = queue;
}
SUNRISE,
CLAIMS,
NONE
}
}
@@ -19,9 +19,13 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.MediaType.CSV_UTF_8;
import static google.registry.persistence.transaction.QueryComposer.Comparator.EQ;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.UrlConnectionUtils.getResponseBytes;
import static google.registry.tmch.LordnTaskUtils.COLUMNS_CLAIMS;
import static google.registry.tmch.LordnTaskUtils.COLUMNS_SUNRISE;
import static google.registry.tmch.LordnTaskUtils.getCsvLineForClaimsDomain;
import static google.registry.tmch.LordnTaskUtils.getCsvLineForSunriseDomain;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.nio.charset.StandardCharsets.UTF_8;
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
@@ -33,6 +37,7 @@ import com.google.appengine.api.taskqueue.TaskHandle;
import com.google.appengine.api.taskqueue.TransientFailureException;
import com.google.apphosting.api.DeadlineExceededException;
import com.google.cloud.tasks.v2.Task;
import com.google.common.base.Ascii;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
@@ -42,6 +47,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.domain.Domain;
import google.registry.request.Action;
import google.registry.request.Action.Service;
import google.registry.request.Parameter;
@@ -49,6 +55,7 @@ import google.registry.request.RequestParameters;
import google.registry.request.UrlConnectionService;
import google.registry.request.UrlConnectionUtils;
import google.registry.request.auth.Auth;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import google.registry.util.Clock;
import google.registry.util.CloudTasksUtils;
import google.registry.util.Retrier;
@@ -59,6 +66,7 @@ import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
@@ -81,9 +89,11 @@ import org.joda.time.Duration;
public final class NordnUploadAction implements Runnable {
static final String PATH = "/_dr/task/nordnUpload";
static final String LORDN_PHASE_PARAM = "lordn-phase";
static final String LORDN_PHASE_PARAM = "lordnPhase";
// TODO: Delete after migrating off of pull queue.
static final String PULL_QUEUE_PARAM = "pullQueue";
private static final int QUEUE_BATCH_SIZE = 1000;
private static final int BATCH_SIZE = 1000;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Duration LEASE_PERIOD = Duration.standardHours(1);
@@ -100,31 +110,102 @@ public final class NordnUploadAction implements Runnable {
@Inject LordnRequestInitializer lordnRequestInitializer;
@Inject UrlConnectionService urlConnectionService;
@Inject @Config("tmchMarksdbUrl") String tmchMarksdbUrl;
@Inject @Parameter(LORDN_PHASE_PARAM) String phase;
@Inject @Parameter(RequestParameters.PARAM_TLD) String tld;
@Inject
@Config("tmchMarksdbUrl")
String tmchMarksdbUrl;
@Inject
@Parameter(LORDN_PHASE_PARAM)
String phase;
@Inject
@Parameter(RequestParameters.PARAM_TLD)
String tld;
@Inject
@Parameter(PULL_QUEUE_PARAM)
Optional<Boolean> usePullQueue;
@Inject CloudTasksUtils cloudTasksUtils;
@Inject NordnUploadAction() {}
@Inject
NordnUploadAction() {}
/**
* These LORDN parameter names correspond to the relative paths in LORDN URLs and cannot be
* changed on our end.
*/
private static final String PARAM_LORDN_PHASE_SUNRISE = "sunrise";
private static final String PARAM_LORDN_PHASE_SUNRISE =
Ascii.toLowerCase(LordnPhase.SUNRISE.toString());
private static final String PARAM_LORDN_PHASE_CLAIMS = "claims";
private static final String PARAM_LORDN_PHASE_CLAIMS =
Ascii.toLowerCase(LordnPhase.CLAIMS.toString());
/** How long to wait before attempting to verify an upload by fetching the log. */
private static final Duration VERIFY_DELAY = Duration.standardMinutes(30);
@Override
public void run() {
try {
processLordnTasks();
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
if (usePullQueue.orElse(false)) {
try {
processLordnTasks();
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
}
} else {
checkArgument(
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
"Invalid phase specified to NordnUploadAction: %s.",
phase);
tm().transact(
() -> {
// Note here that we load all domains pending Nordn in one batch, which should not
// be a problem for the rate of domain registration that we see. If we anticipate
// a peak in claims during TLD launch (sunrise is NOT first-come-first-serve, so
// there should be no expectation of a peak during it), we can consider temporarily
// increasing the frequency of Nordn upload to reduce the size of each batch.
//
// We did not further divide the domains into smaller batches because the
// read-upload-write operation per small batch needs to be inside a single
// transaction to prevent race conditions, and running several uploads in rapid
// sucession will likely overwhelm the MarksDB upload server, which recommands a
// maximum upload frequency of every 3 hours.
//
// See:
// https://datatracker.ietf.org/doc/html/draft-ietf-regext-tmch-func-spec-01#section-5.2.3.3
List<Domain> domains =
tm().createQueryComposer(Domain.class)
.where("lordnPhase", EQ, LordnPhase.valueOf(Ascii.toUpperCase(phase)))
.where("tld", EQ, tld)
.orderBy("creationTime")
.list();
if (domains.isEmpty()) {
return;
}
StringBuilder csv = new StringBuilder();
ImmutableList.Builder<Domain> newDomains = new ImmutableList.Builder<>();
domains.forEach(
domain -> {
if (phase.equals(PARAM_LORDN_PHASE_SUNRISE)) {
csv.append(getCsvLineForSunriseDomain(domain)).append('\n');
} else {
csv.append(getCsvLineForClaimsDomain(domain)).append('\n');
}
Domain newDomain = domain.asBuilder().setLordnPhase(LordnPhase.NONE).build();
newDomains.add(newDomain);
});
String columns =
phase.equals(PARAM_LORDN_PHASE_SUNRISE) ? COLUMNS_SUNRISE : COLUMNS_CLAIMS;
String header =
String.format("1,%s,%d\n%s\n", clock.nowUtc(), domains.size(), columns);
try {
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), header + csv);
} catch (IOException | GeneralSecurityException e) {
throw new RuntimeException(e);
}
tm().updateAll(newDomains.build());
});
}
}
@@ -158,7 +239,7 @@ public final class NordnUploadAction implements Runnable {
queue.leaseTasks(
LeaseOptions.Builder.withTag(tld)
.leasePeriod(LEASE_PERIOD.getMillis(), TimeUnit.MILLISECONDS)
.countLimit(QUEUE_BATCH_SIZE)),
.countLimit(BATCH_SIZE)),
TransientFailureException.class,
DeadlineExceededException.class);
if (tasks.isEmpty()) {
@@ -171,7 +252,7 @@ public final class NordnUploadAction implements Runnable {
private void processLordnTasks() throws IOException, GeneralSecurityException {
checkArgument(
phase.equals(PARAM_LORDN_PHASE_SUNRISE) || phase.equals(PARAM_LORDN_PHASE_CLAIMS),
"Invalid phase specified to Nordn servlet: %s.",
"Invalid phase specified to NordnUploadAction: %s.",
phase);
DateTime now = clock.nowUtc();
Queue queue =
@@ -184,12 +265,12 @@ public final class NordnUploadAction implements Runnable {
// Note: This upload/task deletion isn't done atomically (it's not clear how one would do so
// anyway). As a result, it is possible that the upload might succeed yet the deletion of
// enqueued tasks might fail. If so, this would result in the same lines being uploaded to NORDN
// across mulitple uploads. This is probably OK; all that we really cannot have is a missing
// across multiple uploads. This is probably OK; all that we really cannot have is a missing
// line.
if (!tasks.isEmpty()) {
String csvData = convertTasksToCsv(tasks, now, columns);
uploadCsvToLordn(String.format("/LORDN/%s/%s", tld, phase), csvData);
Lists.partition(tasks, QUEUE_BATCH_SIZE)
Lists.partition(tasks, BATCH_SIZE)
.forEach(
batch ->
retrier.callWithRetry(
@@ -22,6 +22,7 @@ import static google.registry.util.ResourceUtils.readResourceUtf8;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule.TmchCaMode;
import google.registry.model.CacheUtils;
@@ -55,6 +56,7 @@ public final class TmchCertificateAuthority {
private static final String ROOT_CRT_PILOT_FILE = "icann-tmch-pilot.crt";
private static final String CRL_FILE = "icann-tmch.crl";
private static final String CRL_PILOT_FILE = "icann-tmch-pilot.crl";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final TmchCaMode tmchCaMode;
private final Clock clock;
@@ -142,8 +144,14 @@ public final class TmchCertificateAuthority {
* @see X509Utils#verifyCrl
*/
public void updateCrl(String asciiCrl, String url) throws GeneralSecurityException {
X509CRL crl = X509Utils.loadCrl(asciiCrl);
X509Utils.verifyCrl(getAndValidateRoot(), getCrl(), crl, clock.nowUtc().toDate());
X509CRL newCrl = X509Utils.loadCrl(asciiCrl);
X509CRL oldCrl = null;
try {
oldCrl = getCrl();
} catch (Exception e) {
logger.atWarning().withCause(e).log("Old CRL is invalid, ignored during CRL update.");
}
X509Utils.verifyCrl(getAndValidateRoot(), oldCrl, newCrl, clock.nowUtc().toDate());
TmchCrl.set(asciiCrl, url);
}
@@ -27,8 +27,10 @@ import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRing;
/** Helper class for common data loaded from the jar and SQL at runtime. */
public final class TmchData {
private static final String BEGIN_ENCODED_SMD = "-----BEGIN ENCODED SMD-----";
private static final String END_ENCODED_SMD = "-----END ENCODED SMD-----";
static final String BEGIN_ENCODED_SMD = "-----BEGIN ENCODED SMD-----";
static final String END_ENCODED_SMD = "-----END ENCODED SMD-----";
private TmchData() {}
static PGPPublicKey loadPublicKey(ByteSource pgpPublicKeyFile) {
try (InputStream input = pgpPublicKeyFile.openStream();
@@ -16,6 +16,7 @@ package google.registry.tmch;
import static com.google.common.io.Resources.asByteSource;
import static com.google.common.io.Resources.getResource;
import static google.registry.request.RequestParameters.extractOptionalBooleanParameter;
import static google.registry.request.RequestParameters.extractRequiredParameter;
import dagger.Module;
@@ -25,6 +26,7 @@ import google.registry.request.HttpException.BadRequestException;
import google.registry.request.Parameter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -64,4 +66,10 @@ public final class TmchModule {
static String provideNordnLogId(HttpServletRequest req) {
return extractRequiredParameter(req, NordnVerifyAction.NORDN_LOG_ID_PARAM);
}
@Provides
@Parameter(NordnUploadAction.PULL_QUEUE_PARAM)
static Optional<Boolean> provideUsePullQueue(HttpServletRequest req) {
return extractOptionalBooleanParameter(req, NordnUploadAction.PULL_QUEUE_PARAM);
}
}
@@ -1,26 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEVjCCAz6gAwIBAgIgLrAbevoae52y3f6C2tB0Sn3p7XJm0T02FogxKCfNhXkw
DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxPDA6BgNVBAoTM0ludGVybmV0
IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEvMC0G
A1UEAxMmSUNBTk4gVHJhZGVtYXJrIENsZWFyaW5naG91c2UgUGlsb3QgQ0EwHhcN
MTMwNjI2MDAwMDAwWhcNMjMwNjI1MjM1OTU5WjB8MQswCQYDVQQGEwJVUzE8MDoG
A1UEChMzSW50ZXJuZXQgQ29ycG9yYXRpb24gZm9yIEFzc2lnbmVkIE5hbWVzIGFu
ZCBOdW1iZXJzMS8wLQYDVQQDEyZJQ0FOTiBUcmFkZW1hcmsgQ2xlYXJpbmdob3Vz
ZSBQaWxvdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMJiRqFg
iCoDF8zMJMKHPMEuSpjbEl9ZWII+1WawDyt+jw841HsTT+6MwZsqExbQvukgvnuS
lA3Rg3xTFxodMaVZWsVQJy2PXGHVFRLnCp05DYZsMGZabuN9mIekYwtjePo89Lz0
JtU3ibL3squGG3gg6TLtPjks7Txm18BYPOYLznui32GUz+1aIZuk2p5A/rSldsh3
bke68IX5WZhKuIxT0+BjS8yfLWI0HCUs71WVxzvlJ1v22/eMK0WEA6+ZhCbOKIav
VtGNJrwIYwhZmxqfiR1HzHTLvrV0SLlJ2bwNk/yzKm8IJfuFezQ5BBtQ2RS9opFX
X8ft3v+uQQQvi+MCAwEAAaOBwzCBwDASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
DgQWBBTDrT6m1hEARYBcOldKim3cMQ2ecTAOBgNVHQ8BAf8EBAMCAQYwNAYDVR0f
BC0wKzApoCegJYYjaHR0cDovL2NybC5pY2Fubi5vcmcvdG1jaF9waWxvdC5jcmww
RQYDVR0gBD4wPDA6BgMqAwQwMzAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5pY2Fu
bi5vcmcvcGlsb3RfcmVwb3NpdG9yeTANBgkqhkiG9w0BAQsFAAOCAQEAKUfEJ5X6
QAttajjRVseJFQxRXGHTgCaDk8C/1nj1ielZAuZtgdUpWDUr0NnGCi+LHSsgdTYR
+vMrxir7EVYQevrBobELkxeTEfjF9FVqjBHInyPFLOFkz15zGG2IwPJps+vhAd/7
gT0ph1k2FEkJFGL5LwRf1ms4IX0vDkxTIX8Qxy1jczCiSsoV8pwlhh2NHAkpGQWN
/pTS0Uqi7uU5Bm/IoGvPBzUp5n5SjUMnTZx/+1zAuerSabt483sXBcWsjgl7MqFt
fONiAtNeMNfh60lTMu4zgVwLZTO4TQM5Q2uylPPmZtwnA88QvM2IL85cIYJHd0z9
jpUQMBGHXF2WQA==
-----END CERTIFICATE-----
@@ -1,13 +0,0 @@
-----BEGIN X509 CRL-----
MIIB8DCB2QIBATANBgkqhkiG9w0BAQsFADB2MQswCQYDVQQGEwJVUzE8MDoGA1UE
ChMzSW50ZXJuZXQgQ29ycG9yYXRpb24gZm9yIEFzc2lnbmVkIE5hbWVzIGFuZCBO
dW1iZXJzMSkwJwYDVQQDEyBJQ0FOTiBUcmFkZW1hcmsgQ2xlYXJpbmdob3VzZSBD
QRcNMTgwMzAxMDAwMDAwWhcNMTgxMDA3MjM1OTU5WqAvMC0wHwYDVR0jBBgwFoAU
XMDxlizKTFsp8UB00xs2PkfUbgQwCgYDVR0UBAMCAQswDQYJKoZIhvcNAQELBQAD
ggEBAGhvQtqENy2Ga+nGg6kZRCzEWKy481v111Iycku/qL5aUlqSL5BkQst2Czaq
xdKRSxKHkMaTChoezSaw5huOTd0prdSXVHPg/tmjxyuuS2pqWpuAICkrG06FgXgh
AG5YCHt2DvCjeA9F3TMmbOkCMILQ/x+vsyg6Yv4Oiz8rFbFcUMntUKSrymt4dKpk
S78CTkHH/3M3YNxZCo8JPwaQohC3Rck4M30Pg8C0qC9jjSrudA6hCa4223U6aZwC
Kz3LNXdkqGWlDJPTf0YWwnT4ZyO7KKXVuEbPzg187htz3Jcr6b0x1UUoHGAkOv7i
W4IwhPbUJ14/7pUuUef6airQUw8=
-----END X509 CRL-----
@@ -1,25 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEQjCCAyqgAwIBAgIhAJNCMqhNjz3cXVJPj7yvcZvro1FKQR+dTC6tXazem5g+
MA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYTAlVTMTwwOgYDVQQKEzNJbnRlcm5l
dCBDb3Jwb3JhdGlvbiBmb3IgQXNzaWduZWQgTmFtZXMgYW5kIE51bWJlcnMxKTAn
BgNVBAMTIElDQU5OIFRyYWRlbWFyayBDbGVhcmluZ2hvdXNlIENBMB4XDTEzMDcy
NDAwMDAwMFoXDTIzMDcyMzIzNTk1OVowdjELMAkGA1UEBhMCVVMxPDA6BgNVBAoT
M0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVt
YmVyczEpMCcGA1UEAxMgSUNBTk4gVHJhZGVtYXJrIENsZWFyaW5naG91c2UgQ0Ew
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5MX6qpRnqFzEXa9w3G0b8
LTEVZzpOpcSq2BXJO16+iuZ964mpay2hm2BdZk89hSmZhUy2ePBR6PdS0GMmzzXL
NiyTHJlDIPxxXTR39Iqs8QChJ8wle4pYUu8JUk2vJ0r7PhFweeCCQZ5gvHdCwopS
bXeolj4NCqsvzU8iROsLRHSZbE83i2pkL+qBoyzjny9MO2rvMNPo5WrDNrno6hvC
hlf8Pv77HTNCazI2MeW0ArfLin4pSe6nLnDsQA11SF9bbgwDgVMQFvmB8nEvUbZW
Atnp3auaWqaylC+G0p3frFvMCUJMPrghiPwBABl3bk1GLjXXVl7D8SubKd2Xwv63
AgMBAAGjgbowgbcwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUXMDxlizK
TFsp8UB00xs2PkfUbgQwDgYDVR0PAQH/BAQDAgEGMC4GA1UdHwQnMCUwI6AhoB+G
HWh0dHA6Ly9jcmwuaWNhbm4ub3JnL3RtY2guY3JsMEIGA1UdIAQ7MDkwBgYEVR0g
ADAvBggrBgEFBQcCATAjMCEGCCsGAQUFBwIBFhVodHRwczovL2NhLmljYW5uLm9y
Zy8wDQYJKoZIhvcNAQELBQADggEBAAM29FBdwQSAx8dD4ZYtCYjXxTonNCP2qveG
wrpMJcq/I3Jp/N4etsnj+K5ej5sSlDuo8sTMF7lgMkgjrc6zgJl0+Gct2RhbRNzN
5ittE9JwJZ3Us4vwiy6gqMO5Ie9YaKMZy2MYP2iFp6AhBKIc2Iz+8aFfnFzdSEx2
b3xc+t1A09dzpnzU6zvHWUUkTYq9fTg1er1npni9ZErvp0jEyHVWi5GXvWap68XH
pVF6TBmPW2UBEEnFgd3SxbMXLhaD/wzV12tlSYjxaNed+H5qbVVbSVwN9yBeWU29
/pkZu79TqFFxTd4CJTWOBq0+yLO1Ts2ZZ1l+GgU6e3hI1XERSNc=
-----END CERTIFICATE-----
@@ -94,10 +94,10 @@ final class GenerateLordnCommand implements Command {
Domain domain) {
String status = " ";
if (domain.getLaunchNotice() == null && domain.getSmdId() != null) {
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain, domain.getCreationTime()));
sunriseCsv.add(LordnTaskUtils.getCsvLineForSunriseDomain(domain));
status = "S";
} else if (domain.getLaunchNotice() != null || domain.getSmdId() != null) {
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain, domain.getCreationTime()));
claimsCsv.add(LordnTaskUtils.getCsvLineForClaimsDomain(domain));
status = "C";
}
System.out.printf("%s[%s] ", domain.getDomainName(), status);
@@ -0,0 +1,91 @@
// Copyright 2023 The Nomulus Authors. 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 google.registry.ui.server.console;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.api.client.http.HttpStatusCodes;
import com.google.gson.Gson;
import google.registry.model.EppResourceUtils;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.User;
import google.registry.model.domain.Domain;
import google.registry.request.Action;
import google.registry.request.Parameter;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.UserAuthInfo;
import google.registry.ui.server.registrar.JsonGetAction;
import java.util.Optional;
import javax.inject.Inject;
/** Returns a JSON representation of a domain to the registrar console. */
@Action(
service = Action.Service.DEFAULT,
path = ConsoleDomainGetAction.PATH,
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ConsoleDomainGetAction implements JsonGetAction {
public static final String PATH = "/console-api/domain";
private final AuthResult authResult;
private final Response response;
private final Gson gson;
private final String paramDomain;
@Inject
public ConsoleDomainGetAction(
AuthResult authResult,
Response response,
Gson gson,
@Parameter("domain") String paramDomain) {
this.authResult = authResult;
this.response = response;
this.gson = gson;
this.paramDomain = paramDomain;
}
@Override
public void run() {
if (!authResult.isAuthenticated() || !authResult.userAuthInfo().isPresent()) {
response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
return;
}
UserAuthInfo authInfo = authResult.userAuthInfo().get();
if (!authInfo.consoleUser().isPresent()) {
response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
return;
}
User user = authInfo.consoleUser().get();
Optional<Domain> possibleDomain =
tm().transact(
() ->
EppResourceUtils.loadByForeignKeyCached(
Domain.class, paramDomain, tm().getTransactionTime()));
if (!possibleDomain.isPresent()) {
response.setStatus(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
return;
}
Domain domain = possibleDomain.get();
if (!user.getUserRoles()
.hasPermission(domain.getCurrentSponsorRegistrarId(), ConsolePermission.DOWNLOAD_DOMAINS)) {
response.setStatus(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
return;
}
response.setStatus(HttpStatusCodes.STATUS_CODE_OK);
response.setPayload(gson.toJson(domain));
}
}
@@ -156,4 +156,10 @@ public final class RegistrarConsoleModule {
static Boolean provideIsLock(HttpServletRequest req) {
return extractBooleanParameter(req, "isLock");
}
@Provides
@Parameter("domain")
static String provideDomain(HttpServletRequest req) {
return extractRequiredParameter(req, "domain");
}
}
@@ -23,12 +23,6 @@
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
"is_optional": false
},
{
"name": "shard",
"label": "The exclusive upper bound of the operation window.",
"helpText": "The exclusive upper bound of the operation window, in ISO 8601 format.",
"is_optional": true
},
{
"name": "isDryRun",
"label": "Whether this job is a dry run.",
@@ -0,0 +1,20 @@
-----BEGIN X509 CRL-----
MIIDLjCCARYCAQEwDQYJKoZIhvcNAQENBQAwfDELMAkGA1UEBhMCVVMxPDA6BgNV
BAoMM0ludGVybmV0IENvcnBvcmF0aW9uIGZvciBBc3NpZ25lZCBOYW1lcyBhbmQg
TnVtYmVyczEvMC0GA1UEAwwmSUNBTk4gVHJhZGVtYXJrIENsZWFyaW5naG91c2Ug
UGlsb3QgQ0EXDTIyMTExNjEzMzIyN1oXDTIzMDQwNjEzMzIyN1owNTAzAhQc4zug
SmVXTpNkiBlOLRFSS6qBnhcNMjIxMTE2MTMzMjI3WjAMMAoGA1UdFQQDCgEAoC8w
LTAfBgNVHSMEGDAWgBRHe0+uelGRtdG/nTbphn82FgSpRTAKBgNVHRQEAwIBATAN
BgkqhkiG9w0BAQ0FAAOCAgEAD5pxGf7W2nxnCyoMhhRWclaBrY2VF+lYitpQdUIA
Li3nhCXDiXwHWNtiyGjKaWJFsCFAph0EejKTR1iHh/7t7fZ5T2KhiqyREGGs2VT5
AXTWTDZUdGtobmc9xmXowzF7YUWoZZenj1AwUt0/tDKth1ieZvoRWEKJ+0YCpIDQ
LyfJKBFM6NEyrYiKu1szcdT7+Meii4M8ulYHkUXEJXQBN5+LuESkRrqach6n6zSS
urvCG2I0ijqVj36TudwRrYU+sCpk8XR6//XyJbcjW5vuUd1/uYrJ+lSZCPaKfjIo
gLKK1UJ9wLZbg28Hqtb5KxYsLtlzMsNFCbVebatl6QdS+J4OaCGLE4SM2NnsheN/
qxErMS1eAzNVgpW+yY4JV47k54HDBZfgHmgA8lgyShn7w08dA2mWIYbmbKHcnh2N
QSQ5wjYbTEy3a251t32pR76W5k/uduoMXestJEXD7yViMz3pFzu97l1huAP8C0Hs
sMEysMomthMQChqNUZw19wakdxuCyiU+YrL7bHTTL2pAKYB0AKOGE1XgecnneC89
+K5vr5TUTWOpksUeuM5Oq2YYLicYuES1Nr/5GkszNCCY0J+fBL50AI0IItrfFjt1
Xu/mlbiJKQZXMppWfLJUhu/8Ur1VYeYLeCNR3ju7jfvm3DkVzmqSc0b01uz5POTz
Hak=
-----END X509 CRL-----
@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF7DCCA9SgAwIBAgIUemptMV4lw+1QL1e648o+wvANH4wwDQYJKoZIhvcNAQEN
BQAwfDELMAkGA1UEBhMCVVMxPDA6BgNVBAoMM0ludGVybmV0IENvcnBvcmF0aW9u
IGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEvMC0GA1UEAwwmSUNBTk4g
VHJhZGVtYXJrIENsZWFyaW5naG91c2UgUGlsb3QgQ0EwHhcNMjIxMTE1MTg1MDA5
WhcNNDIxMTE1MTg1MDA5WjB8MQswCQYDVQQGEwJVUzE8MDoGA1UECgwzSW50ZXJu
ZXQgQ29ycG9yYXRpb24gZm9yIEFzc2lnbmVkIE5hbWVzIGFuZCBOdW1iZXJzMS8w
LQYDVQQDDCZJQ0FOTiBUcmFkZW1hcmsgQ2xlYXJpbmdob3VzZSBQaWxvdCBDQTCC
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALQQS8gSAw6fsyqP+yWvfOtU
D2hCe/RvbKMG6cJ6yuCMscxIEPT0xrVTkGfzG8b6T4j8iD9mVHDxO19z+y0ALog/
IPeVLw/x/2QC5YTDlrQtbsT33BN+NFdp13mE324owiyVyYrPqN1B6MtdERQLkIFU
PIlhTopHfnMtRNzwt2gPpNwy2q5lqK20dKzrG9W1kLd26nFfnN5T9fnv21TtBhSJ
73qfoU8GuOZhytloJRmT/yvvZNH1JTHyvuG15Q6kDDf46E1d6PO1+tmBQnNIZBfp
FALrqN1QX1znaHkd1smgLEC1JV/2iAOtxNUL0d1vJcQfmjHXBtMF8Yx1ulpJjN1c
A6iLMJfO5znd8jQ9O6hkMUjYNRz+XTGHiCTZVkhlNeJiIQbBlILbsnuT4Q+Ywxu+
83W/ymqq/G2tIJdqXapUGEulYw/09y0TMyMnkA0VO9eDNf/B1AaQxBCEhpP6OufR
G/nEzbH/SknVhgeV8CkhZo4UeFOx5XFZVj1Y3vBsqVwQYTc0NG84Bv3HD6sDXQd0
DtW0gjqXg2caxQBoX8F40MCkik5TvnOT8RawvWKJjakEKSgeMceu9LnjRgFk+96Z
ig1vGVJi213rUgSv7oXcO3HgraHOLkzkMglqOBh7NrUnEdCrrDGKYZwxZ/46cofY
yyOb+9y/UOWa8MWvoam7AgMBAAGjZjBkMB0GA1UdDgQWBBRHe0+uelGRtdG/nTbp
hn82FgSpRTAfBgNVHSMEGDAWgBRHe0+uelGRtdG/nTbphn82FgSpRTASBgNVHRMB
Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQ0FAAOCAgEA
ElXV35T8rG25yyGzNTgI9lDntDy2D0c/WSPPn9LZQREddKEpMBSy8pztHLJurH7B
uKeb+j0KXw+0IMG5ZKxacUbLlW8NGIXqBRkRiDfBDw374dsLIeB7Gb3PKMWsnvg5
zZic/iW7Wrrur6xAjFsgFMz8KRuNseGFDZi3UF1O4xX6Wy2KV5HMvvbnzyQa4bN9
mbnCEf8tVXws2ZWC4e7yEkbLFqDh5czujVGq+g8VEl82wFTn0s+u6roI3vCrqZN9
Qh2/yOzhpnu+daDcIUqb8keNNIswE7n9A9Yl40xNfzZid8bP4fJXM2oVcXxqUnsD
Khwk9wgk30XVuKokoWYB3ExAVTYeR6j3jZPpDp3wYHXV23hgexPykKSE/7TMByII
K1egDjKLdUlReQ5Rca48IRRAa6f4igJoaSvmp3eEF4lmxgXMhHIDocUN0hVDDaPb
WGkr+sChXtftIUVhE2bi746dNhiBLWWPz8FX/uZzD1srJA8kPmf8YWdH2d6yJ8BN
2olV7QpDRpmCJwblyzLLeNWCQiwHQNN4MvtxJFFFZQfF6m6A6bZ5CKNM5GvJanRl
/aS1ehO/DhOkcGelxAjMtTPqKhI1j+SBZqPdumrQDFhfHN/sM9F4g+I8datpu/2P
Dop0Ki70evaFhD8jVE4z0zt59OUzEHjezWOTNoYU9GU=
-----END CERTIFICATE-----
@@ -0,0 +1,18 @@
-----BEGIN X509 CRL-----
MIIC8DCB2QIBATANBgkqhkiG9w0BAQ0FADB2MQswCQYDVQQGEwJVUzE8MDoGA1UE
CgwzSW50ZXJuZXQgQ29ycG9yYXRpb24gZm9yIEFzc2lnbmVkIE5hbWVzIGFuZCBO
dW1iZXJzMSkwJwYDVQQDDCBJQ0FOTiBUcmFkZW1hcmsgQ2xlYXJpbmdob3VzZSBD
QRcNMjIxMTE2MTMyNzU3WhcNMjMwNDA2MTMyNzU3WqAvMC0wHwYDVR0jBBgwFoAU
P/RCC1aVjbgjAjp0MnrSEivX8cYwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQENBQAD
ggIBAJkrxahXQDaniHHE+8/3GVSlXz2175xVfZ/zqq3twatKd4FWxXD5sr42595Z
5T9EP5XFii5o/j49qM6a+Qc3V++LEcTj+VHFxvhG2czYhiuZXzFu1WmdmtSCe2+C
9N7DgGl9VNRg14DKWoW5BPdmgy6/XZCEcxlQ6ft/caZ8G9pR+Q5i9rwCXDFXB1ni
kIuMKnp5rq95GzF8WnbEGfM0s5YY/UfSozF35oPGtRSyCWdGoTmmpnp3DXMvElMW
wMxtCRhdhxsS6YzeCPiORTzq08IiCJcVpud5ZdDdKzja1tF8iSc5MnMJ0pygT4ds
uZOHmj8/bAA9cf9PK/8N5fd7jZZlPDKKbhT+EoKZTXzNwBiGy68tXerWENFkR0tF
Sy9T45RcGve9L5nEV8bqawsxrmnuatSh/6fSTDiz4HO1/mW6/GAT1QPFYrU++p8o
BR7WcKCHvQpUt5tXhh1hAZba6j4aeWpXUquyTtrjgqThvvBIT5m76k19BcRaOroE
qf0WJOQcvn2hPBNEbSbbHOWaXpHbTI8R6gk+/utRc9/xkHF5vEQTfUPHTkjoK4dW
S4p4P6tRcNoxzSfh7bN9nts2VFKcvSaF10m2G1bCyJB2QjKMZG7aGVX+9Pvnoa1v
HgNDfKNZR1a/ZYcJm7QY5TRuQF+Evd/OcsVOdRhx804d08ms
-----END X509 CRL-----
@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF4DCCA8igAwIBAgIUHTVZH/TadFNIiEBCJ/OdngKfZwwwDQYJKoZIhvcNAQEN
BQAwdjELMAkGA1UEBhMCVVMxPDA6BgNVBAoMM0ludGVybmV0IENvcnBvcmF0aW9u
IGZvciBBc3NpZ25lZCBOYW1lcyBhbmQgTnVtYmVyczEpMCcGA1UEAwwgSUNBTk4g
VHJhZGVtYXJrIENsZWFyaW5naG91c2UgQ0EwHhcNMjIxMTE1MTg0ODQxWhcNNDIx
MTE1MTg0ODQxWjB2MQswCQYDVQQGEwJVUzE8MDoGA1UECgwzSW50ZXJuZXQgQ29y
cG9yYXRpb24gZm9yIEFzc2lnbmVkIE5hbWVzIGFuZCBOdW1iZXJzMSkwJwYDVQQD
DCBJQ0FOTiBUcmFkZW1hcmsgQ2xlYXJpbmdob3VzZSBDQTCCAiIwDQYJKoZIhvcN
AQEBBQADggIPADCCAgoCggIBAMf5/4d2gaDgG0Tbx5ewIKZNlH/KxURjRqWj7vzc
SYnzszAcaTuwM1sHWTJtUUC0QP4QcG90e8Q7A7zhgYVm6POBV3U9hv/NVSZB6Set
DK5lxU/cubQrPhf2Bc7AkGvfnJV8+/0GI5x9AF8dlSUj3yvl9VWvI8Iuph4xHm0g
Fg6BHo4beUVsbdBwnBkSPEmsmNo0D0gf1rCIb/wYfWMZBqU8bduS36TUvHshMTB/
Luad3QYyPhqgomizVzEjXebuGlyCtwlGOHdI5t2WlM7XF3RPXZVxA+nsFwRWm9UT
r6ygGve3+9y1bjqudWu8mt9VevYCiesLPowUy9E8Vg8xKcsntUWs1KoZTQYxlohb
u3cHNxBdYGflQ8m8cbkDeAvWNOgMlhPzWBDFqQeVuBQhiuF9iKR3RZHFAHXJy81t
DKQgzR6YlMd3iCGfBVK/uUVr89UgJ1xv5hniSaFDYqtD5rZftvGb2YXsyeQjs0Pl
QkZyaynVS5P3Tax57fQUcJR3YqgeoeXQNTit+/ieZju1zGLutGikYujciPBIWoBl
S8YnOgPNyfjE+LrQG2RqsZOumqlN66ZjqYH4pCf6lI14PJUl4mUh2YpnIyjQd8Uq
QxZmrqDOJAawd2LVuHr4GR6Vbm/oAyyCdQ5HztvCbXOK6v+pMdrrbtb+IlvQ5hcu
FoqrAgMBAAGjZjBkMB0GA1UdDgQWBBQ/9EILVpWNuCMCOnQyetISK9fxxjAfBgNV
HSMEGDAWgBQ/9EILVpWNuCMCOnQyetISK9fxxjASBgNVHRMBAf8ECDAGAQH/AgEA
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQ0FAAOCAgEAm8QZeNzTD52hZH3I
Vy9pti6NRcVSudtzZloVFJ4g9GbIx1uw8k61bgUX70jwk4pPbcOji8RoZoYG842p
3tgq50rlRYsKZZx24ZUVaQDz0WKTzjhs2qlk0pRM9XZukZ8SB2knhvJ3byxogxJ0
kIP4ysS5op90dcWsrS0O9HF8eBtHYvw2+MuA5KleWB4Qo94+GjmFJsiJiIQ6S+sG
M9PZbHSEWW64fNNsgeozlnY9vJ4qRF55tylrB+pXOxVcKDRD3l5GstobmC0waTv8
ZvMtR6SQ1QeHRcdznzWsASvDSxhv0vBauKbuBs1T/wgcDF9XXikTx8PbbCQUoCbC
4mX+ZNgIXyCbhSVnNBQKN+HBrddm/AqHRLLnfOOcGBqCQ5JLicLvnsRMVrpnoLPS
nMbq2QT7J7F5i+q2v2TqeKEwmj4zzh/hX1PbppS8IA/MujivFjLdn1SL0halidYN
ywqEF6gUJMoImJ9YWvGRnyv7pm+kgrF83MPbD43AX6Hq8zidYOIzwT4ZnCMlBWJ2
iZWciK3/nPe6YH8P5cPddLxRAWBstd5tbDmdPkIMZ0vHccmfIMhlMrCO/IB8N2tv
7QJR8V0nE3BIE9RfIa4BrfY5nQpGHWAdpXJH9WTXgcwWUB3JQcxD64c3GhVvp7e4
Jwz/ypzBX6WYeSrb3OZWylJ4sWE=
-----END CERTIFICATE-----
@@ -49,6 +49,8 @@ import google.registry.model.tld.Registry.TldState;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.TaskQueueExtension;
import google.registry.tmch.TmchData;
import google.registry.tmch.TmchTestData;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
@@ -64,6 +66,9 @@ class EppLifecycleDomainTest extends EppTestCase {
"ACDATE", "2002-06-04T00:00:00Z",
"EXDATE", "2003-06-01T00:04:00Z");
private static final String ENCODED_SMD =
TmchData.readEncodedSignedMark(TmchTestData.loadFile("smd/active.smd")).getEncodedData();
@RegisterExtension
final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().withClock(clock).buildIntegrationTestExtension();
@@ -1184,8 +1189,8 @@ class EppLifecycleDomainTest extends EppTestCase {
*/
@Test
void testDomainCreation_startDateSunriseFull() throws Exception {
// The signed mark is valid between 2013 and 2017
DateTime sunriseDate = DateTime.parse("2014-09-08T09:09:09Z");
// The signed mark is valid between 2022-11-22 and 2027-10-18.
DateTime sunriseDate = DateTime.parse("2025-09-08T09:09:09Z");
DateTime gaDate = sunriseDate.plusDays(30);
createTld(
"example",
@@ -1201,7 +1206,7 @@ class EppLifecycleDomainTest extends EppTestCase {
createContactsAndHosts();
// During pre-delegation, any create should fail both with and without mark
assertThatCommand("domain_create_sunrise_encoded_mark.xml")
assertThatCommand("domain_create_sunrise_encoded_mark.xml", ImmutableMap.of("SMD", ENCODED_SMD))
.atTime(sunriseDate.minusDays(2))
.hasResponse(
"response_error.xml",
@@ -1219,7 +1224,9 @@ class EppLifecycleDomainTest extends EppTestCase {
"MSG", "The current registry phase does not allow for general registrations"));
// During sunrise, verify that the launch phase must be set to sunrise.
assertThatCommand("domain_create_start_date_sunrise_encoded_mark_wrong_phase.xml")
assertThatCommand(
"domain_create_start_date_sunrise_encoded_mark_wrong_phase.xml",
ImmutableMap.of("SMD", ENCODED_SMD))
.atTime(sunriseDate)
.hasResponse(
"response_error.xml",
@@ -1230,14 +1237,14 @@ class EppLifecycleDomainTest extends EppTestCase {
// During sunrise, create with mark will succeed but without will fail.
// We also test we can delete without a mark.
assertThatCommand("domain_create_sunrise_encoded_mark.xml")
assertThatCommand("domain_create_sunrise_encoded_mark.xml", ImmutableMap.of("SMD", ENCODED_SMD))
.atTime(sunriseDate.plusDays(1))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:09:09Z",
"EXDATE", "2015-09-09T09:09:09Z"));
"CRDATE", "2025-09-09T09:09:09Z",
"EXDATE", "2026-09-09T09:09:09Z"));
assertThatCommand("domain_delete.xml", ImmutableMap.of("DOMAIN", "test-validate.example"))
.atTime(sunriseDate.plusDays(1).plusMinutes(1))
@@ -1264,15 +1271,14 @@ class EppLifecycleDomainTest extends EppTestCase {
"Declared launch extension phase does not match the current registry phase"));
assertThatCommand(
"domain_create_no_hosts_or_dsdata.xml",
ImmutableMap.of("DOMAIN", "general.example"))
"domain_create_no_hosts_or_dsdata.xml", ImmutableMap.of("DOMAIN", "general.example"))
.atTime(gaDate.plusDays(2))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "general.example",
"CRDATE", "2014-10-10T09:09:09Z",
"EXDATE", "2016-10-10T09:09:09Z"));
"CRDATE", "2025-10-10T09:09:09Z",
"EXDATE", "2027-10-10T09:09:09Z"));
assertThatLogoutSucceeds();
}
@@ -1280,8 +1286,8 @@ class EppLifecycleDomainTest extends EppTestCase {
/** Test that missing type= argument on launch create works in start-date sunrise. */
@Test
void testDomainCreation_startDateSunrise_noType() throws Exception {
// The signed mark is valid between 2013 and 2017
DateTime sunriseDate = DateTime.parse("2014-09-08T09:09:09Z");
// The signed mark is valid between 2022-11-22 and 2027-10-18.
DateTime sunriseDate = DateTime.parse("2025-09-08T09:09:09Z");
DateTime gaDate = sunriseDate.plusDays(30);
createTld(
"example",
@@ -1306,14 +1312,16 @@ class EppLifecycleDomainTest extends EppTestCase {
"CODE", "2303",
"MSG", "The domain with given ID (test-validate.example) doesn't exist."));
assertThatCommand("domain_create_start_date_sunrise_encoded_mark_no_type.xml")
assertThatCommand(
"domain_create_start_date_sunrise_encoded_mark_no_type.xml",
ImmutableMap.of("SMD", ENCODED_SMD))
.atTime(sunriseDate.plusDays(1).plusMinutes(1))
.hasResponse(
"domain_create_response.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:10:09Z",
"EXDATE", "2015-09-09T09:10:09Z"));
"CRDATE", "2025-09-09T09:10:09Z",
"EXDATE", "2026-09-09T09:10:09Z"));
assertThatCommand("domain_info.xml", ImmutableMap.of("DOMAIN", "test-validate.example"))
.atTime(sunriseDate.plusDays(1).plusMinutes(2))
@@ -1321,8 +1329,8 @@ class EppLifecycleDomainTest extends EppTestCase {
"domain_info_response_ok_wildcard.xml",
ImmutableMap.of(
"DOMAIN", "test-validate.example",
"CRDATE", "2014-09-09T09:10:09Z",
"EXDATE", "2015-09-09T09:10:09Z"));
"CRDATE", "2025-09-09T09:10:09Z",
"EXDATE", "2026-09-09T09:10:09Z"));
assertThatLogoutSucceeds();
}
@@ -14,6 +14,7 @@
package google.registry.flows.domain;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
@@ -72,7 +73,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Ordering;
import com.google.common.truth.Truth8;
import google.registry.config.RegistryConfig;
import google.registry.flows.EppException;
import google.registry.flows.EppException.UnimplementedExtensionException;
@@ -91,6 +91,7 @@ import google.registry.flows.domain.DomainCreateFlow.SignedMarksOnlyDuringSunris
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkExpiredException;
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkNotYetValidException;
import google.registry.flows.domain.DomainFlowTmchUtils.NoMarksFoundMatchingDomainException;
import google.registry.flows.domain.DomainFlowTmchUtils.SignedMarkRevokedErrorException;
import google.registry.flows.domain.DomainFlowUtils.AcceptedTooLongAgoException;
import google.registry.flows.domain.DomainFlowUtils.BadDomainNameCharacterException;
import google.registry.flows.domain.DomainFlowUtils.BadDomainNamePartsCountException;
@@ -154,6 +155,8 @@ import google.registry.model.billing.BillingEvent;
import google.registry.model.billing.BillingEvent.Flag;
import google.registry.model.billing.BillingEvent.Reason;
import google.registry.model.billing.BillingEvent.RenewalPriceBehavior;
import google.registry.model.common.DatabaseMigrationStateSchedule;
import google.registry.model.common.DatabaseMigrationStateSchedule.MigrationState;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.GracePeriod;
@@ -181,6 +184,10 @@ import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.TaskQueueExtension;
import google.registry.testing.TaskQueueHelper.TaskMatcher;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import google.registry.tmch.SmdrlCsvParser;
import google.registry.tmch.TmchData;
import google.registry.tmch.TmchTestData;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;
@@ -188,9 +195,14 @@ import javax.annotation.Nullable;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junitpioneer.jupiter.cartesian.CartesianTest;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
/** Unit tests for {@link DomainCreateFlow}. */
class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain> {
@@ -198,6 +210,18 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
@RegisterExtension TaskQueueExtension taskQueue = new TaskQueueExtension();
private static final String CLAIMS_KEY = "2013041500/2/6/9/rJ1NrDO92vDsAzf7EQzgjX4R0000000001";
// This is a time when SMD itself is not valid, but its signing certificates are. It will
// trigger a different exception than when any signing cert is not valid yet.
private static final DateTime SMD_NOT_YET_VALID_TIME = DateTime.parse("2022-11-20T12:34:56Z");
private static final DateTime SMD_VALID_TIME = DateTime.parse("2023-01-02T12:34:56Z");
// This is a time when the imtermediate certificate in the SMD signature chain has expired. The
// SMD itself has not expired yet. It will trigger a different exception than when the SMD itself
// has expired.
private static final DateTime SMD_CERT_EXPIRED_TIME = DateTime.parse("2027-11-02T12:34:56Z");
private static final String SMD_ID = "000000851669081693741-65535";
private static final String SMD_FILE_PATH = "smd/active.smd";
private static final String ENCODED_SMD =
TmchData.readEncodedSignedMark(TmchTestData.loadFile(SMD_FILE_PATH)).getEncodedData();
private AllocationToken allocationToken;
@@ -206,8 +230,13 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z").minus(Duration.millis(1)));
}
@BeforeAll
static void beforeAll() {
DatabaseMigrationStateSchedule.useUncachedForTest();
}
@BeforeEach
void initCreateTest() {
void initCreateTest() throws Exception {
createTld("tld");
allocationToken =
persistResource(
@@ -372,21 +401,33 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.that(reloadResourceByForeignKey())
.hasSmdId(null)
.and()
.hasLaunchNotice(null);
.hasLaunchNotice(null)
.and()
.hasLordnPhase(LordnPhase.NONE);
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
assertNoTasksEnqueued(QUEUE_CLAIMS, QUEUE_SUNRISE);
}
private void assertSunriseLordn(String domainName) throws Exception {
assertAboutDomains()
.that(reloadResourceByForeignKey())
.hasSmdId("0000001761376042759136-65535")
.hasSmdId(SMD_ID)
.and()
.hasLaunchNotice(null);
String expectedPayload =
String.format(
"%s,%s,0000001761376042759136-65535,1,2014-09-09T09:09:09.017Z",
reloadResourceByForeignKey().getRepoId(), domainName);
assertTasksEnqueued(QUEUE_SUNRISE, new TaskMatcher().payload(expectedPayload));
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
.equals(MigrationState.NORDN_SQL)) {
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.SUNRISE);
} else {
String expectedPayload =
String.format(
"%s,%s,%s,1,%s",
reloadResourceByForeignKey().getRepoId(),
domainName,
SMD_ID,
SMD_VALID_TIME.plusMillis(17));
assertTasksEnqueued(QUEUE_SUNRISE, new TaskMatcher().payload(expectedPayload));
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
}
}
private void assertClaimsLordn() throws Exception {
@@ -400,13 +441,19 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
"tmch",
DateTime.parse("2010-08-16T09:00:00.0Z"),
DateTime.parse("2009-08-16T09:00:00.0Z")));
TaskMatcher task =
new TaskMatcher()
.payload(
reloadResourceByForeignKey().getRepoId()
+ ",example-one.tld,370d0b7c9223372036854775807,1,"
+ "2009-08-16T09:00:00.017Z,2009-08-16T09:00:00.000Z");
assertTasksEnqueued(QUEUE_CLAIMS, task);
if (DatabaseMigrationStateSchedule.getValueAtTime(clock.nowUtc())
.equals(MigrationState.NORDN_SQL)) {
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.CLAIMS);
} else {
TaskMatcher task =
new TaskMatcher()
.payload(
reloadResourceByForeignKey().getRepoId()
+ ",example-one.tld,370d0b7c9223372036854775807,1,"
+ "2009-08-16T09:00:00.017Z,2009-08-16T09:00:00.000Z");
assertTasksEnqueued(QUEUE_CLAIMS, task);
assertAboutDomains().that(reloadResourceByForeignKey()).hasLordnPhase(LordnPhase.NONE);
}
}
private void doSuccessfulTest(
@@ -632,7 +679,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "open"));
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "open", "SMD", ENCODED_SMD));
persistContactsAndHosts();
EppException thrown = assertThrows(SignedMarksOnlyDuringSunriseException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@@ -641,10 +688,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
@Test
void testFailure_generalAvailability_superuserMismatchedEncodedSignedMark() {
createTld("tld", GENERAL_AVAILABILITY);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "wrong.tld", "PHASE", "open"));
ImmutableMap.of("DOMAIN", "wrong.tld", "PHASE", "open", "SMD", ENCODED_SMD));
persistContactsAndHosts();
EppException thrown =
assertThrows(NoMarksFoundMatchingDomainException.class, this::runFlowAsSuperuser);
@@ -656,7 +703,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
}
@Test
@@ -664,7 +713,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
}
@Test
@@ -672,7 +723,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
}
@Test
@@ -680,7 +733,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "26.00"));
}
@Test
@@ -688,7 +743,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "26.00"));
}
@Test
@@ -696,7 +753,9 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
setEppInput("domain_create_fee_defaults.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
persistContactsAndHosts();
doSuccessfulTest(
"tld", "domain_create_response_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12"));
"tld",
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "26.00"));
}
@Test
@@ -918,8 +977,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_claimsNotice() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_claimsNotice(boolean usePullQueue) throws Exception {
if (!usePullQueue) {
useNordnSql();
}
clock.setTo(DateTime.parse("2009-08-16T09:00:00.0Z"));
setEppInput("domain_create_claim_notice.xml");
persistContactsAndHosts();
@@ -929,8 +992,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertClaimsLordn();
}
@Test
void testSuccess_claimsNoticeInQuietPeriod() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_claimsNoticeInQuietPeriod(boolean usePullQueue) throws Exception {
if (!usePullQueue) {
useNordnSql();
}
allocationToken =
persistResource(
new AllocationToken.Builder()
@@ -1056,6 +1123,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v06() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.6", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v06() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailure_wrongFeeAmount_v11() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
@@ -1066,6 +1184,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v11() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.11", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v11() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.11", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailure_wrongFeeAmount_v12() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
@@ -1076,6 +1245,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccess_wrongFeeAmountTooHigh_defaultToken_v12() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 8))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts();
// $12 is equal to 50% off the first year registration and 0% 0ff the 2nd year
runFlowAssertResponse(
loadFile(
"domain_create_response_fee.xml",
ImmutableMap.of("FEE_VERSION", "0.12", "FEE", "12.00")));
}
@Test
void testFailure_wrongFeeAmountTooLow_defaultToken_v12() throws Exception {
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedRegistrarIds(ImmutableSet.of("TheRegistrar"))
.setAllowedTlds(ImmutableSet.of("tld"))
.setDiscountFraction(0.5)
.build());
persistResource(
Registry.get("tld")
.asBuilder()
.setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey()))
.setCreateBillingCost(Money.of(USD, 100))
.build());
// Expects fee of $26
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.12", "CURRENCY", "USD"));
persistContactsAndHosts();
EppException thrown = assertThrows(FeesMismatchException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailure_wrongCurrency_v06() {
setEppInput("domain_create_fee.xml", ImmutableMap.of("FEE_VERSION", "0.6", "CURRENCY", "EUR"));
@@ -1199,8 +1419,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertAllocationTokenWasRedeemed("abcDEF23456");
}
@Test
void testSuccess_anchorTenant_withClaims() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_anchorTenant_withClaims(boolean usePullQueue) throws Exception {
if (!usePullQueue) {
useNordnSql();
}
persistResource(
new AllocationToken.Builder()
.setDomainName("example-one.tld")
@@ -1249,19 +1473,31 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
@Test
void testSuccess_anchorTenantInSunrise_withMetadataExtension_andSignedMark() throws Exception {
createTld("tld", START_DATE_SUNRISE);
setEppInput("domain_create_anchor_tenant_sunrise_metadata_extension_signed_mark.xml");
setEppInput(
"domain_create_anchor_tenant_sunrise_metadata_extension_signed_mark.xml",
ImmutableMap.of("SMD", ENCODED_SMD));
eppRequestSource = EppRequestSource.TOOL; // Only tools can pass in metadata.
persistContactsAndHosts();
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
runFlowAssertResponse(
loadFile(
"domain_create_response_encoded_signed_mark_name.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld")));
ImmutableMap.of(
"DOMAIN",
"test-validate.tld",
"CREATE_TIME",
SMD_VALID_TIME.toString(),
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE, ANCHOR_TENANT));
}
@Test
void testSuccess_anchorTenantInSunrise_withSignedMark() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_anchorTenantInSunrise_withSignedMark(boolean usePullQueue) throws Exception {
if (!usePullQueue) {
useNordnSql();
}
allocationToken =
persistResource(
new AllocationToken.Builder()
@@ -1276,13 +1512,19 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
persistReservedList("anchor_tenants", "test-validate,RESERVED_FOR_ANCHOR_TENANT"))
.setTldStateTransitions(ImmutableSortedMap.of(START_OF_TIME, START_DATE_SUNRISE))
.build());
setEppInput("domain_create_anchor_tenant_signed_mark.xml");
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
setEppInput("domain_create_anchor_tenant_signed_mark.xml", ImmutableMap.of("SMD", ENCODED_SMD));
clock.setTo(SMD_VALID_TIME);
persistContactsAndHosts();
runFlowAssertResponse(
loadFile(
"domain_create_response_encoded_signed_mark_name.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld")));
ImmutableMap.of(
"DOMAIN",
"test-validate.tld",
"CREATE_TIME",
SMD_VALID_TIME.toString(),
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT, SUNRISE), allocationToken);
assertDnsTasksEnqueued("test-validate.tld");
assertSunriseLordn("test-validate.tld");
@@ -1364,7 +1606,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.hasValue(getHistoryEntries(reloadResourceByForeignKey()).get(0).getHistoryEntryId());
}
private void assertAllocationTokenWasNotRedeemed(String token) {
private static void assertAllocationTokenWasNotRedeemed(String token) {
AllocationToken reloadedToken =
tm().transact(() -> tm().loadByKey(VKey.create(AllocationToken.class, token)));
assertThat(reloadedToken.isRedeemed()).isFalse();
@@ -1855,23 +2097,33 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
assertSuccessfulCreate("tld", ImmutableSet.of(RESERVED));
}
@Test
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage()
throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_reservedNameCollisionDomain_inSunrise_setsServerHoldAndPollMessage(
boolean usePullQueue) throws Exception {
if (!usePullQueue) {
useNordnSql();
}
persistResource(
Registry.get("tld")
.asBuilder()
.setTldStateTransitions(ImmutableSortedMap.of(START_OF_TIME, START_DATE_SUNRISE))
.build());
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-and-validate.tld", "PHASE", "sunrise"));
ImmutableMap.of("DOMAIN", "test-and-validate.tld", "PHASE", "sunrise", "SMD", ENCODED_SMD));
persistContactsAndHosts();
runFlowAssertResponse(
loadFile(
"domain_create_response_encoded_signed_mark_name.xml",
ImmutableMap.of("DOMAIN", "test-and-validate.tld")));
ImmutableMap.of(
"DOMAIN",
"test-and-validate.tld",
"CREATE_TIME",
SMD_VALID_TIME.toString(),
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSunriseLordn("test-and-validate.tld");
@@ -2394,33 +2646,57 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
"tld", "domain_create_response.xml", SUPERUSER, ImmutableMap.of("DOMAIN", "example.tld"));
}
@Test
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark(boolean usePullQueue)
throws Exception {
if (!usePullQueue) {
useNordnSql();
}
createTld("tld", START_DATE_SUNRISE);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise"));
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise", "SMD", ENCODED_SMD));
persistContactsAndHosts();
runFlowAssertResponse(
loadFile(
"domain_create_response_encoded_signed_mark_name.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld")));
ImmutableMap.of(
"DOMAIN",
"test-validate.tld",
"CREATE_TIME",
SMD_VALID_TIME.toString(),
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE));
assertSunriseLordn("test-validate.tld");
}
/** Test that missing type= argument on launch create works in start-date sunrise. */
@Test
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType() throws Exception {
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_startDateSunriseRegistration_withEncodedSignedMark_noType(boolean usePullQueue)
throws Exception {
if (!usePullQueue) {
useNordnSql();
}
createTld("tld", START_DATE_SUNRISE);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
setEppInput("domain_create_sunrise_encoded_signed_mark_no_type.xml");
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_sunrise_encoded_signed_mark_no_type.xml",
ImmutableMap.of("SMD", ENCODED_SMD));
persistContactsAndHosts();
runFlowAssertResponse(
loadFile(
"domain_create_response_encoded_signed_mark_name.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld")));
ImmutableMap.of(
"DOMAIN",
"test-validate.tld",
"CREATE_TIME",
SMD_VALID_TIME.toString(),
"EXPIRATION_TIME",
SMD_VALID_TIME.plusYears(2).toString())));
assertSuccessfulCreate("tld", ImmutableSet.of(SUNRISE));
assertSunriseLordn("test-validate.tld");
}
@@ -2428,23 +2704,66 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
@Test
void testFail_startDateSunriseRegistration_wrongEncodedSignedMark() {
createTld("tld", START_DATE_SUNRISE);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "wrong.tld", "PHASE", "sunrise"));
ImmutableMap.of("DOMAIN", "wrong.tld", "PHASE", "sunrise", "SMD", ENCODED_SMD));
persistContactsAndHosts();
EppException thrown = assertThrows(NoMarksFoundMatchingDomainException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFail_startDateSunriseRegistration_revokedSignedMark() throws Exception {
SmdrlCsvParser.parse(TmchTestData.loadFile("smd/smdrl.csv").lines().collect(toImmutableList()))
.save();
createTld("tld", START_DATE_SUNRISE);
clock.setTo(SMD_VALID_TIME);
String revokedSmd =
TmchData.readEncodedSignedMark(TmchTestData.loadFile("smd/revoked.smd")).getEncodedData();
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise", "SMD", revokedSmd));
persistContactsAndHosts();
EppException thrown = assertThrows(SignedMarkRevokedErrorException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@CartesianTest
void testFail_startDateSunriseRegistration_IdnRevokedSignedMark(
@Values(strings = {"Agent", "Holder"}) String contact,
@Values(strings = {"Court", "Trademark", "TreatyStatute"}) String type,
@Values(strings = {"Arab", "Chinese", "English", "French"}) String language)
throws Exception {
String filepath =
String.format("idn/%s-%s/%s-%s-%s-Revoked.smd", contact, language, type, contact, language);
ImmutableList<String> labels = TmchTestData.extractLabels(filepath);
if (labels.isEmpty()) {
return;
}
SmdrlCsvParser.parse(
TmchTestData.loadFile("idn/idn_smdrl.csv").lines().collect(toImmutableList()))
.save();
createTld("tld", START_DATE_SUNRISE);
clock.setTo(SMD_VALID_TIME);
String revokedSmd =
TmchData.readEncodedSignedMark(TmchTestData.loadFile(filepath)).getEncodedData();
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", labels.get(0) + ".tld", "PHASE", "sunrise", "SMD", revokedSmd));
persistContactsAndHosts();
EppException thrown = assertThrows(SignedMarkRevokedErrorException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFail_startDateSunriseRegistration_markNotYetValid() {
createTld("tld", START_DATE_SUNRISE);
// If we move now back in time a bit, the mark will not have gone into effect yet.
clock.setTo(DateTime.parse("2013-08-09T10:05:59Z").minusSeconds(1));
clock.setTo(SMD_NOT_YET_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise"));
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise", "SMD", ENCODED_SMD));
persistContactsAndHosts();
EppException thrown = assertThrows(FoundMarkNotYetValidException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@@ -2454,10 +2773,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
void testFail_startDateSunriseRegistration_markExpired() {
createTld("tld", START_DATE_SUNRISE);
// Move time forward to the mark expiration time.
clock.setTo(DateTime.parse("2017-07-23T22:00:00.000Z"));
clock.setTo(SMD_CERT_EXPIRED_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise"));
ImmutableMap.of("DOMAIN", "test-validate.tld", "PHASE", "sunrise", "SMD", ENCODED_SMD));
persistContactsAndHosts();
EppException thrown = assertThrows(FoundMarkExpiredException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
@@ -3165,10 +3484,10 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
@Test
void testSuccess_anchorTenant_inSunrise_trademarked_withSignedMark_viaToken() throws Exception {
createTld("tld", START_DATE_SUNRISE);
clock.setTo(DateTime.parse("2014-09-09T09:09:09Z"));
clock.setTo(SMD_VALID_TIME);
setEppInput(
"domain_create_registration_encoded_signed_mark_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "test-validate.tld"));
ImmutableMap.of("DOMAIN", "test-validate.tld", "SMD", ENCODED_SMD));
persistResource(
allocationToken
.asBuilder()
@@ -3390,7 +3709,7 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.build()));
Domain domain = reloadResourceByForeignKey();
assertThat(domain.getCurrentPackageToken()).isPresent();
Truth8.assertThat(domain.getCurrentPackageToken()).hasValue(token.createVKey());
assertThat(domain.getCurrentPackageToken()).hasValue(token.createVKey());
}
@Test
@@ -3414,4 +3733,97 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
.isEqualTo(
"The package token abc123 cannot be used to register names for longer than 1 year.");
}
private static void useNordnSql() {
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
.build()));
tm().transact(
() ->
DatabaseMigrationStateSchedule.set(
new ImmutableSortedMap.Builder<DateTime, MigrationState>(Ordering.natural())
.put(START_OF_TIME, MigrationState.DATASTORE_ONLY)
.put(START_OF_TIME.plusMillis(1), MigrationState.DATASTORE_PRIMARY)
.put(START_OF_TIME.plusMillis(2), MigrationState.DATASTORE_PRIMARY_NO_ASYNC)
.put(
START_OF_TIME.plusMillis(3), MigrationState.DATASTORE_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(4), MigrationState.SQL_PRIMARY_READ_ONLY)
.put(START_OF_TIME.plusMillis(5), MigrationState.SQL_PRIMARY)
.put(START_OF_TIME.plusMillis(6), MigrationState.SQL_ONLY)
.put(START_OF_TIME.plusMillis(7), MigrationState.SEQUENCE_BASED_ALLOCATE_ID)
.put(START_OF_TIME.plusMillis(8), MigrationState.NORDN_SQL)
.build()));
}
}
@@ -221,7 +221,6 @@ public class DomainTest {
"TheRegistrar",
oneTimeBillKey))
.setAutorenewEndTime(Optional.of(fakeClock.nowUtc().plusYears(2)))
.setDnsRefreshRequestTime(Optional.of(fakeClock.nowUtc()))
.build()));
}
@@ -41,8 +41,6 @@ import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
import google.registry.util.SerializeUtils;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -97,7 +95,6 @@ public class DomainHistoryTest extends EntityTestCase {
.asBuilder()
.setNameservers(host.createVKey())
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 3, new byte[] {0, 1, 2})))
.setDnsRefreshRequestTime(Optional.of(DateTime.parse("2020-03-09T16:40:00Z")))
.build();
insertInDb(domain);
return domain;
@@ -0,0 +1,75 @@
// Copyright 2023 The Nomulus Authors. 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 google.registry.request.auth;
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.json.webtoken.JsonWebSignature;
import com.google.api.client.json.webtoken.JsonWebSignature.Header;
import com.google.auth.oauth2.TokenVerifier;
import javax.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class ServiceAccountAuthenticationMechanismTest {
@Mock private TokenVerifier tokenVerifier;
@Mock private HttpServletRequest request;
private JsonWebSignature token;
private ServiceAccountAuthenticationMechanism serviceAccountAuthenticationMechanism;
@BeforeEach
void beforeEach() throws Exception {
serviceAccountAuthenticationMechanism =
new ServiceAccountAuthenticationMechanism(tokenVerifier, "sa-prefix@email.com");
when(request.getHeader(AUTHORIZATION)).thenReturn("Bearer jwtValue");
Payload payload = new Payload();
payload.setEmail("sa-prefix@email.com");
token = new JsonWebSignature(new Header(), payload, new byte[0], new byte[0]);
when(tokenVerifier.verify("jwtValue")).thenReturn(token);
}
@Test
void testSuccess_authenticates() throws Exception {
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
assertThat(authResult.isAuthenticated()).isTrue();
assertThat(authResult.authLevel()).isEqualTo(AuthLevel.APP);
}
@Test
void testFails_authenticateWrongEmail() throws Exception {
token.getPayload().set("email", "not-service-account-email@email.com");
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
assertThat(authResult.isAuthenticated()).isFalse();
}
@Test
void testFails_authenticateWrongHeader() throws Exception {
when(request.getHeader(AUTHORIZATION)).thenReturn("BEARER asd");
AuthResult authResult = serviceAccountAuthenticationMechanism.authenticate(request);
assertThat(authResult.isAuthenticated()).isFalse();
}
}
@@ -312,6 +312,7 @@ public final class DatabaseHelper {
return persistResource(domain.asBuilder().setDeletionTime(deletionTime).build());
}
// TODO: delete after pull queue migration.
/** Persists a domain and enqueues a LORDN task of the appropriate type for it. */
public static Domain persistDomainAndEnqueueLordn(final Domain domain) {
final Domain persistedDomain = persistResource(domain);
@@ -27,6 +27,7 @@ import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.domain.secdns.DomainDsData;
import google.registry.model.eppcommon.AuthInfo;
import google.registry.testing.TruthChainer.And;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import java.util.Set;
import org.joda.time.DateTime;
@@ -41,7 +42,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
}
public And<DomainSubject> hasDomainName(String domainName) {
return hasValue(domainName, actual.getDomainName(), "has domainName");
return hasValue(domainName, actual.getDomainName(), "domainName");
}
public And<DomainSubject> hasExactlyDsData(DomainDsData... dsData) {
@@ -49,15 +50,19 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
}
public And<DomainSubject> hasExactlyDsData(Set<DomainDsData> dsData) {
return hasValue(dsData, actual.getDsData(), "has dsData");
return hasValue(dsData, actual.getDsData(), "dsData");
}
public And<DomainSubject> hasNumDsData(int num) {
return hasValue(num, actual.getDsData().size(), "has num dsData");
return hasValue(num, actual.getDsData().size(), "dsData.size()");
}
public And<DomainSubject> hasLaunchNotice(LaunchNotice launchNotice) {
return hasValue(launchNotice, actual.getLaunchNotice(), "has launchNotice");
return hasValue(launchNotice, actual.getLaunchNotice(), "launchNotice");
}
public And<DomainSubject> hasLordnPhase(LordnPhase lordnPhase) {
return hasValue(lordnPhase, actual.getLordnPhase(), "lordnPhase");
}
public And<DomainSubject> hasAuthInfoPwd(String pw) {
@@ -67,7 +72,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
public And<DomainSubject> hasCurrentSponsorRegistrarId(String registrarId) {
return hasValue(
registrarId, actual.getCurrentSponsorRegistrarId(), "has currentSponsorRegistrarId");
registrarId, actual.getCurrentSponsorRegistrarId(), "currentSponsorRegistrarId");
}
public And<DomainSubject> hasRegistrationExpirationTime(DateTime expiration) {
@@ -14,13 +14,17 @@
package google.registry.tmch;
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
import static com.google.common.net.HttpHeaders.LOCATION;
import static com.google.common.net.MediaType.FORM_DATA;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ForeignKeyUtils.load;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadByKey;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.newDomain;
import static google.registry.testing.DatabaseHelper.persistDomainAndEnqueueLordn;
import static google.registry.testing.DatabaseHelper.persistResource;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -34,6 +38,7 @@ import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import com.google.appengine.api.taskqueue.LeaseOptions;
@@ -48,15 +53,17 @@ import com.google.common.collect.ImmutableList;
import google.registry.model.domain.Domain;
import google.registry.model.domain.launch.LaunchNotice;
import google.registry.model.tld.Registry;
import google.registry.persistence.VKey;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.request.RequestParameters;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.CloudTasksHelper.TaskMatcher;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeSleeper;
import google.registry.testing.FakeUrlConnectionService;
import google.registry.testing.TaskQueueExtension;
import google.registry.tmch.LordnTaskUtils.LordnPhase;
import google.registry.util.CloudTasksUtils;
import google.registry.util.Retrier;
import google.registry.util.UrlConnectionException;
@@ -67,25 +74,32 @@ import java.net.URL;
import java.security.SecureRandom;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
/** Unit tests for {@link NordnUploadAction}. */
class NordnUploadActionTest {
private static final String CLAIMS_CSV =
"1,2010-05-01T10:11:12.000Z,1\n"
"1,2010-05-04T10:11:12.000Z,2\n"
+ "roid,domain-name,notice-id,registrar-id,registration-datetime,ack-datetime,"
+ "application-datetime\n"
+ "2-TLD,claims-landrush1.tld,landrush1tcn,99999,2010-05-01T10:11:12.000Z,"
+ "1969-12-31T23:00:00.000Z\n";
+ "6-TLD,claims-landrush2.tld,landrush2tcn,88888,2010-05-03T10:11:12.000Z,"
+ "2010-05-03T08:11:12.000Z\n"
+ "8-TLD,claims-landrush1.tld,landrush1tcn,99999,2010-05-04T10:11:12.000Z,"
+ "2010-05-04T09:11:12.000Z\n";
private static final String SUNRISE_CSV =
"1,2010-05-01T10:11:12.000Z,1\n"
"1,2010-05-04T10:11:12.000Z,2\n"
+ "roid,domain-name,SMD-id,registrar-id,registration-datetime,application-datetime\n"
+ "2-TLD,sunrise1.tld,my-smdid,99999,2010-05-01T10:11:12.000Z\n";
+ "2-TLD,sunrise2.tld,new-smdid,88888,2010-05-01T10:11:12.000Z\n"
+ "4-TLD,sunrise1.tld,my-smdid,99999,2010-05-02T10:11:12.000Z\n";
private static final String LOCATION_URL = "http://trololol";
@@ -116,8 +130,12 @@ class NordnUploadActionTest {
when(httpUrlConnection.getHeaderField(LOCATION)).thenReturn("http://trololol");
when(httpUrlConnection.getOutputStream()).thenReturn(connectionOutputStream);
persistResource(loadRegistrar("TheRegistrar").asBuilder().setIanaIdentifier(99999L).build());
persistResource(loadRegistrar("NewRegistrar").asBuilder().setIanaIdentifier(88888L).build());
createTld("tld");
persistResource(Registry.get("tld").asBuilder().setLordnUsername("lolcat").build());
persistSunriseModeDomain();
clock.advanceBy(Duration.standardDays(1));
persistClaimsModeDomain();
action.clock = clock;
action.cloudTasksUtils = cloudTasksUtils;
action.urlConnectionService = urlConnectionService;
@@ -127,6 +145,7 @@ class NordnUploadActionTest {
action.tmchMarksdbUrl = "http://127.0.0.1";
action.random = new SecureRandom();
action.retrier = new Retrier(new FakeSleeper(clock), 3);
action.usePullQueue = Optional.empty();
}
@Test
@@ -137,7 +156,7 @@ class NordnUploadActionTest {
makeTaskHandle("task1", "example", "csvLine1", "lordn-sunrise"),
makeTaskHandle("task3", "example", "ending", "lordn-sunrise"));
assertThat(NordnUploadAction.convertTasksToCsv(tasks, clock.nowUtc(), "col1,col2"))
.isEqualTo("1,2010-05-01T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
.isEqualTo("1,2010-05-04T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
}
@Test
@@ -149,13 +168,13 @@ class NordnUploadActionTest {
makeTaskHandle("task3", "example", "ending", "lordn-sunrise"),
makeTaskHandle("task1", "example", "csvLine1", "lordn-sunrise"));
assertThat(NordnUploadAction.convertTasksToCsv(tasks, clock.nowUtc(), "col1,col2"))
.isEqualTo("1,2010-05-01T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
.isEqualTo("1,2010-05-04T10:11:12.000Z,3\ncol1,col2\ncsvLine1\ncsvLine2\nending\n");
}
@Test
void test_convertTasksToCsv_doesntFailOnEmptyTasks() {
assertThat(NordnUploadAction.convertTasksToCsv(ImmutableList.of(), clock.nowUtc(), "col1,col2"))
.isEqualTo("1,2010-05-01T10:11:12.000Z,0\ncol1,col2\n");
.isEqualTo("1,2010-05-04T10:11:12.000Z,0\ncol1,col2\n");
}
@Test
@@ -187,122 +206,105 @@ class NordnUploadActionTest {
}
@Test
void testRun_claimsMode_appendsTldAndClaimsToRequestUrl() throws Exception {
persistClaimsModeDomain();
action.run();
assertThat(httpUrlConnection.getURL()).isEqualTo(new URL("http://127.0.0.1/LORDN/tld/claims"));
}
@Test
void testRun_sunriseMode_appendsTldAndClaimsToRequestUrl() throws Exception {
persistSunriseModeDomain();
action.run();
assertThat(httpUrlConnection.getURL()).isEqualTo(new URL("http://127.0.0.1/LORDN/tld/sunrise"));
}
@Test
void testRun_usesMultipartContentType() throws Exception {
persistClaimsModeDomain();
action.run();
verify(httpUrlConnection)
.setRequestProperty(eq(CONTENT_TYPE), startsWith("multipart/form-data; boundary="));
verify(httpUrlConnection).setRequestMethod("POST");
}
@Test
void testRun_hasPassword_setsAuthorizationHeader() {
persistClaimsModeDomain();
action.run();
verify(httpUrlConnection)
.setRequestProperty(
AUTHORIZATION, "Basic bG9sY2F0OmF0dGFjaw=="); // echo -n lolcat:attack | base64
}
@Test
void testRun_noPassword_doesntSendAuthorizationHeader() {
void testSuccess_noPassword_doesntSendAuthorizationHeader() {
action.lordnRequestInitializer = new LordnRequestInitializer(Optional.empty());
persistClaimsModeDomain();
action.run();
verify(httpUrlConnection, times(0)).setRequestProperty(eq(AUTHORIZATION), anyString());
}
@Test
void testRun_claimsMode_payloadMatchesClaimsCsv() {
persistClaimsModeDomain();
void testSuccess_nothingScheduled() {
persistResource(
loadByKey(load(Domain.class, "claims-landrush1.tld", clock.nowUtc()))
.asBuilder()
.setLordnPhase(LordnPhase.NONE)
.build());
persistResource(
loadByKey(load(Domain.class, "claims-landrush2.tld", clock.nowUtc()))
.asBuilder()
.setLordnPhase(LordnPhase.NONE)
.build());
action.run();
assertThat(connectionOutputStream.toString(UTF_8)).contains(CLAIMS_CSV);
verifyNoInteractions(httpUrlConnection);
cloudTasksHelper.assertNoTasksEnqueued(NordnVerifyAction.QUEUE);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_claimsMode(boolean usePullQueue) throws Exception {
testRun("claims", "claims-landrush1.tld", "claims-landrush2.tld", CLAIMS_CSV, usePullQueue);
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
void testSuccess_sunriseMode(boolean usePullQueue) throws Exception {
testRun("sunrise", "sunrise1.tld", "sunrise2.tld", SUNRISE_CSV, usePullQueue);
}
@Test
void testRun_claimsMode_verifyTaskGetsEnqueuedWithClaimsCsv() {
persistClaimsModeDomain();
action.run();
cloudTasksHelper.assertTasksEnqueued(
NordnVerifyAction.QUEUE,
new TaskMatcher()
.url(NordnVerifyAction.PATH)
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
.header(CONTENT_TYPE, FORM_DATA.toString()));
}
@Test
void testRun_sunriseMode_payloadMatchesSunriseCsv() {
persistSunriseModeDomain();
action.run();
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
}
@Test
void test_noResponseContent_stillWorksNormally() throws Exception {
void testSuccess_noResponseContent_stillWorksNormally() throws Exception {
// Returning null only affects logging.
when(httpUrlConnection.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[] {}));
persistSunriseModeDomain();
action.run();
assertThat(connectionOutputStream.toString(UTF_8)).contains(SUNRISE_CSV);
}
@Test
void testRun_sunriseMode_verifyTaskGetsEnqueuedWithSunriseCsv() {
persistSunriseModeDomain();
action.run();
cloudTasksHelper.assertTasksEnqueued(
NordnVerifyAction.QUEUE,
new TaskMatcher()
.url(NordnVerifyAction.PATH)
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
.header(CONTENT_TYPE, FORM_DATA.toString()));
testRun("claims", "claims-landrush1.tld", "claims-landrush2.tld", CLAIMS_CSV, false);
}
@Test
void testFailure_nullRegistryUser() {
persistClaimsModeDomain();
persistResource(Registry.get("tld").asBuilder().setLordnUsername(null).build());
VerifyException thrown = assertThrows(VerifyException.class, action::run);
assertThat(thrown).hasMessageThat().contains("lordnUsername is not set for tld.");
}
@Test
void testFetchFailure() throws Exception {
persistClaimsModeDomain();
void testFailure_errorResponseCode() throws Exception {
when(httpUrlConnection.getResponseCode()).thenReturn(SC_INTERNAL_SERVER_ERROR);
assertThrows(UrlConnectionException.class, action::run);
}
private static void persistClaimsModeDomain() {
Domain domain = DatabaseHelper.newDomain("claims-landrush1.tld");
@Test
void testFailure_noLocationHeaderInResponse() throws Exception {
when(httpUrlConnection.getHeaderField(LOCATION)).thenReturn(null);
assertThrows(UrlConnectionException.class, action::run);
}
private void persistClaimsModeDomain() {
persistDomainAndEnqueueLordn(
domain
newDomain("claims-landrush2.tld")
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.setCreationRegistrarId("NewRegistrar")
.setLaunchNotice(
LaunchNotice.create(
"landrush1tcn", null, null, domain.getCreationTime().minusHours(1)))
LaunchNotice.create("landrush2tcn", null, null, clock.nowUtc().minusHours(2)))
.setLordnPhase(LordnPhase.CLAIMS)
.build());
clock.advanceBy(Duration.standardDays(1));
persistDomainAndEnqueueLordn(
newDomain("claims-landrush1.tld")
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.setLaunchNotice(
LaunchNotice.create("landrush1tcn", null, null, clock.nowUtc().minusHours(1)))
.setLordnPhase(LordnPhase.CLAIMS)
.build());
}
private void persistSunriseModeDomain() {
action.phase = "sunrise";
Domain domain = DatabaseHelper.newDomain("sunrise1.tld");
persistDomainAndEnqueueLordn(domain.asBuilder().setSmdId("my-smdid").build());
persistDomainAndEnqueueLordn(
newDomain("sunrise2.tld")
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.setCreationRegistrarId("NewRegistrar")
.setSmdId("new-smdid")
.setLordnPhase(LordnPhase.SUNRISE)
.build());
clock.advanceBy(Duration.standardDays(1));
persistDomainAndEnqueueLordn(
newDomain("sunrise1.tld")
.asBuilder()
.setCreationTimeForTest(clock.nowUtc())
.setSmdId("my-smdid")
.setLordnPhase(LordnPhase.SUNRISE)
.build());
}
private static TaskHandle makeTaskHandle(
@@ -311,4 +313,46 @@ class NordnUploadActionTest {
TaskOptions.Builder.withPayload(payload).method(Method.PULL).tag(tag).taskName(taskName),
queue);
}
private void verifyColumnCleared(String domainName) {
VKey<Domain> domainKey = load(Domain.class, domainName, clock.nowUtc());
Domain domain = loadByKey(domainKey);
assertThat(domain.getLordnPhase()).isEqualTo(LordnPhase.NONE);
}
private void testRun(
String phase, String domain1, String domain2, String csv, boolean usePullQueue)
throws Exception {
action.usePullQueue = Optional.of(usePullQueue);
action.phase = phase;
action.run();
verify(httpUrlConnection)
.setRequestProperty(
AUTHORIZATION, "Basic bG9sY2F0OmF0dGFjaw=="); // echo -n lolcat:attack | base64
verify(httpUrlConnection)
.setRequestProperty(eq(CONTENT_TYPE), startsWith("multipart/form-data; boundary="));
verify(httpUrlConnection).setRequestMethod("POST");
assertThat(httpUrlConnection.getURL())
.isEqualTo(new URL("http://127.0.0.1/LORDN/tld/" + phase));
assertThat(connectionOutputStream.toString(UTF_8)).contains(csv);
if (!usePullQueue) {
verifyColumnCleared(domain1);
verifyColumnCleared(domain2);
} else {
assertThat(
getQueue("lordn-" + phase)
.leaseTasks(
LeaseOptions.Builder.withTag("tld")
.leasePeriod(1, TimeUnit.HOURS)
.countLimit(100)))
.isEmpty();
}
cloudTasksHelper.assertTasksEnqueued(
NordnVerifyAction.QUEUE,
new TaskMatcher()
.url(NordnVerifyAction.PATH)
.param(NordnVerifyAction.NORDN_URL_PARAM, LOCATION_URL)
.param(RequestParameters.PARAM_TLD, "tld")
.header(CONTENT_TYPE, FORM_DATA.toString()));
}
}
@@ -33,7 +33,7 @@ class SmdrlCsvParserTest {
private final FakeClock clock = new FakeClock();
private static final CharSource SMDRL_LATEST_CSV =
TmchTestData.loadBytes("smdrl-latest.csv").asCharSource(US_ASCII);
TmchTestData.loadBytes("smdrl/smdrl-latest.csv").asCharSource(US_ASCII);
@Test
void testParse() throws Exception {
@@ -62,7 +62,8 @@ abstract class TmchActionTestCase {
@BeforeEach
public void beforeEachTmchActionTestCase() throws Exception {
marksdb.tmchMarksdbUrl = MARKSDB_URL;
marksdb.marksdbPublicKey = TmchData.loadPublicKey(TmchTestData.loadBytes("pubkey"));
marksdb.marksdbPublicKey =
TmchData.loadPublicKey(TmchTestData.loadBytes("crypto/marksdb-public-key-test.asc"));
marksdb.urlConnectionService = urlConnectionService;
when(httpUrlConnection.getResponseCode()).thenReturn(SC_OK);
}
@@ -37,24 +37,31 @@ import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link TmchCertificateAuthority}. */
class TmchCertificateAuthorityTest {
private static final String GOOD_TEST_CERTIFICATE = loadFile("icann-tmch-test-good.crt");
private static final String REVOKED_TEST_CERTIFICATE = loadFile("icann-tmch-test-revoked.crt");
// This certificate is extracted from the SMD file smd/active.smd. It is the
// intermediate (TMV) certificate that was signed by the root (CA) cert and signed the SMD
// file.
private static final String GOOD_TMV_CERTIFICATE = loadFile("crypto/icann-tmv-test-good.crt");
// This certificate is extracted from the SMD file smd/tmv-cert-revoked.smd. It is the (revoked)
// intermediate (TMV) certificate that was signed by the root (CA) cert and signed the SMD
// file.
private static final String REVOKED_TMV_CERTIFICATE =
loadFile("crypto/icann-tmv-test-revoked.crt");
@RegisterExtension
public final JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
private final FakeClock clock = new FakeClock(DateTime.parse("2014-01-01T00:00:00Z"));
private final FakeClock clock = new FakeClock(DateTime.parse("2022-11-20T00:00:00Z"));
@Test
void testFailure_prodRootExpired() {
TmchCertificateAuthority tmchCertificateAuthority =
new TmchCertificateAuthority(PRODUCTION, clock);
clock.setTo(DateTime.parse("2024-01-01T00:00:00Z"));
clock.setTo(DateTime.parse("2500-01-01T00:00:00Z"));
CertificateExpiredException e =
assertThrows(
CertificateExpiredException.class, tmchCertificateAuthority::getAndValidateRoot);
assertThat(e).hasMessageThat().contains("NotAfter: Sun Jul 23 23:59:59 UTC 2023");
assertThat(e).hasMessageThat().contains("NotAfter");
}
@Test
@@ -65,7 +72,7 @@ class TmchCertificateAuthorityTest {
CertificateNotYetValidException e =
assertThrows(
CertificateNotYetValidException.class, tmchCertificateAuthority::getAndValidateRoot);
assertThat(e).hasMessageThat().contains("NotBefore: Wed Jul 24 00:00:00 UTC 2013");
assertThat(e).hasMessageThat().contains("NotBefore");
}
@Test
@@ -77,14 +84,14 @@ class TmchCertificateAuthorityTest {
SignatureException e =
assertThrows(
SignatureException.class,
() -> tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE)));
() -> tmchCertificateAuthority.verify(loadCertificate(GOOD_TMV_CERTIFICATE)));
assertThat(e).hasMessageThat().contains("Signature does not match");
}
@Test
void testSuccess_verify() throws Exception {
TmchCertificateAuthority tmchCertificateAuthority = new TmchCertificateAuthority(PILOT, clock);
tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE));
tmchCertificateAuthority.verify(loadCertificate(GOOD_TMV_CERTIFICATE));
}
@Test
@@ -94,7 +101,7 @@ class TmchCertificateAuthorityTest {
SignatureException e =
assertThrows(
SignatureException.class,
() -> tmchCertificateAuthority.verify(loadCertificate(GOOD_TEST_CERTIFICATE)));
() -> tmchCertificateAuthority.verify(loadCertificate(GOOD_TMV_CERTIFICATE)));
assertThat(e).hasMessageThat().contains("Signature does not match");
}
@@ -104,7 +111,7 @@ class TmchCertificateAuthorityTest {
CertificateRevokedException thrown =
assertThrows(
CertificateRevokedException.class,
() -> tmchCertificateAuthority.verify(loadCertificate(REVOKED_TEST_CERTIFICATE)));
assertThat(thrown).hasMessageThat().contains("revoked, reason: KEY_COMPROMISE");
() -> tmchCertificateAuthority.verify(loadCertificate(REVOKED_TMV_CERTIFICATE)));
assertThat(thrown).hasMessageThat().contains("revoked, reason: UNSPECIFIED");
}
}
@@ -15,7 +15,7 @@
package google.registry.tmch;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.TestDataHelper.loadBytes;
import static google.registry.tmch.TmchTestData.loadBytes;
import static google.registry.util.ResourceUtils.readResourceBytes;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.verify;
@@ -29,6 +29,7 @@ import java.security.SignatureException;
import java.security.cert.CRLException;
import java.security.cert.CertificateNotYetValidException;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link TmchCrlAction}. */
@@ -38,29 +39,30 @@ class TmchCrlActionTest extends TmchActionTestCase {
TmchCrlAction action = new TmchCrlAction();
action.marksdb = marksdb;
action.tmchCertificateAuthority = new TmchCertificateAuthority(tmchCaMode, clock);
action.tmchCrlUrl = new URL("http://sloth.lol/tmch.crl");
action.tmchCrlUrl = new URL("https://sloth.lol/tmch.crl");
return action;
}
@BeforeEach
void before() {
clock.setTo(DateTime.parse("2023-03-24TZ"));
}
@Test
void testSuccess() throws Exception {
clock.setTo(DateTime.parse("2013-07-24TZ"));
when(httpUrlConnection.getInputStream())
.thenReturn(
new ByteArrayInputStream(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read()));
newTmchCrlAction(TmchCaMode.PRODUCTION).run();
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-pilot.crl").read()));
newTmchCrlAction(TmchCaMode.PILOT).run();
verify(httpUrlConnection).getInputStream();
assertThat(connectedUrls).containsExactly(new URL("http://sloth.lol/tmch.crl"));
assertThat(connectedUrls).containsExactly(new URL("https://sloth.lol/tmch.crl"));
}
@Test
void testFailure_crlTooOld() throws Exception {
clock.setTo(DateTime.parse("2020-01-01TZ"));
when(httpUrlConnection.getInputStream())
.thenReturn(
new ByteArrayInputStream(
loadBytes(TmchCrlActionTest.class, "icann-tmch-pilot-old.crl").read()));
.thenReturn(new ByteArrayInputStream(loadBytes("crypto/icann-tmch-pilot-old.crl").read()));
TmchCrlAction action = newTmchCrlAction(TmchCaMode.PILOT);
Exception e = assertThrows(Exception.class, action::run);
assertThat(e).hasCauseThat().isInstanceOf(CRLException.class);
@@ -72,12 +74,11 @@ class TmchCrlActionTest extends TmchActionTestCase {
@Test
void testFailure_crlNotSignedByRoot() throws Exception {
clock.setTo(DateTime.parse("2013-07-24TZ"));
when(httpUrlConnection.getInputStream())
.thenReturn(
new ByteArrayInputStream(
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch.crl").read()));
Exception e = assertThrows(Exception.class, newTmchCrlAction(TmchCaMode.PILOT)::run);
readResourceBytes(TmchCertificateAuthority.class, "icann-tmch-pilot.crl").read()));
Exception e = assertThrows(Exception.class, newTmchCrlAction(TmchCaMode.PRODUCTION)::run);
assertThat(e).hasCauseThat().isInstanceOf(SignatureException.class);
assertThat(e).hasCauseThat().hasMessageThat().isEqualTo("Signature does not match.");
}
@@ -43,8 +43,8 @@ class TmchDnlActionTest extends TmchActionTestCase {
void testDnl() throws Exception {
assertThat(ClaimsListDao.get().getClaimKey("xn----7sbejwbn3axu3d")).isEmpty();
when(httpUrlConnection.getInputStream())
.thenReturn(new ByteArrayInputStream(TmchTestData.loadBytes("dnl-latest.csv").read()))
.thenReturn(new ByteArrayInputStream(TmchTestData.loadBytes("dnl-latest.sig").read()));
.thenReturn(new ByteArrayInputStream(TmchTestData.loadBytes("dnl/dnl-latest.csv").read()))
.thenReturn(new ByteArrayInputStream(TmchTestData.loadBytes("dnl/dnl-latest.sig").read()));
newTmchDnlAction().run();
verify(httpUrlConnection, times(2)).getInputStream();
assertThat(connectedUrls.stream().map(URL::toString).collect(toImmutableList()))
@@ -46,8 +46,8 @@ class TmchSmdrlActionTest extends TmchActionTestCase {
assertThat(smdrl.isSmdRevoked("0000001681375789102250-65535", now)).isFalse();
assertThat(smdrl.isSmdRevoked("0000001681375789102250-65536", now)).isFalse();
when(httpUrlConnection.getInputStream())
.thenReturn(new ByteArrayInputStream(loadBytes("smdrl-latest.csv").read()))
.thenReturn(new ByteArrayInputStream(loadBytes("smdrl-latest.sig").read()));
.thenReturn(new ByteArrayInputStream(loadBytes("smdrl/smdrl-latest.csv").read()))
.thenReturn(new ByteArrayInputStream(loadBytes("smdrl/smdrl-latest.sig").read()));
newTmchSmdrlAction().run();
verify(httpUrlConnection, times(2)).getInputStream();
assertThat(connectedUrls.stream().map(URL::toString).collect(toImmutableList()))
@@ -16,22 +16,33 @@ package google.registry.tmch;
import static com.google.common.base.CharMatcher.whitespace;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.tmch.TmchData.BEGIN_ENCODED_SMD;
import static google.registry.tmch.TmchData.END_ENCODED_SMD;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteSource;
import com.google.re2j.Matcher;
import com.google.re2j.Pattern;
import google.registry.testing.TestDataHelper;
/** Utility class providing easy access to contents of the {@code testdata/} directory. */
/**
* Utility class providing easy access to contents of the {@code
* core/src/test/resources/google/registry/tmch/} directory.
*/
public final class TmchTestData {
private static final String BEGIN_ENCODED_SMD = "-----BEGIN ENCODED SMD-----";
private static final String END_ENCODED_SMD = "-----END ENCODED SMD-----";
private TmchTestData() {}
/** Returns {@link ByteSource} for file in {@code tmch/testdata/} directory. */
/**
* Returns {@link ByteSource} for file in {@code core/src/test/resources/google/registry/tmch/}
* directory.
*/
public static ByteSource loadBytes(String filename) {
return TestDataHelper.loadBytes(TmchTestData.class, filename);
}
/** Loads data from file in {@code tmch/testdata/} as a String. */
/** Loads data from file in {@code core/src/test/resources/google/registry/tmch/} as a String. */
public static String loadFile(String filename) {
return TestDataHelper.loadFile(TmchTestData.class, filename);
}
@@ -47,4 +58,15 @@ public final class TmchTestData {
data.indexOf(BEGIN_ENCODED_SMD) + BEGIN_ENCODED_SMD.length(),
data.indexOf(END_ENCODED_SMD))));
}
public static ImmutableList<String> extractLabels(String filepath) {
String pattern = "U-labels: ";
String content = loadFile(filepath);
Matcher matcher = Pattern.compile(pattern + ".*").matcher(content);
matcher.find();
String matchedString = matcher.group().replace(pattern, "");
return matchedString.isEmpty()
? ImmutableList.of()
: ImmutableList.copyOf(Splitter.on(',').trimResults().split(matchedString));
}
}
@@ -42,9 +42,9 @@ class TmchTestDataExpirationTest {
* files and so that we can test various types of files, but this test will vail when the validity
* of the ICANN-provided file expires.
*
* <p>When this fails, check
* <a>https://newgtlds.icann.org/en/about/trademark-clearinghouse/registries-registrars</a> for a
* new updated SMD file.
* <p>When this fails, check <a
* href="https://newgtlds.icann.org/en/about/trademark-clearinghouse/registries-registrars">Signed
* Mark Data Files</a> for a new updated SMD file.
*/
@Test
void testActiveSignedMarkFiles_areValidAndNotExpired() throws Exception {
@@ -53,7 +53,7 @@ class TmchTestDataExpirationTest {
new TmchXmlSignature(
new TmchCertificateAuthority(TmchCaMode.PILOT, new SystemClock())));
String filePath = "active/smd-active-21aug20-en.smd";
String filePath = "smd/active.smd";
String tmchData = loadFile(TmchTestDataExpirationTest.class, filePath);
EncodedSignedMark smd = TmchData.readEncodedSignedMark(tmchData);
try {
@@ -28,14 +28,18 @@ import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateRevokedException;
import javax.xml.crypto.dsig.XMLSignatureException;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.junitpioneer.jupiter.cartesian.CartesianTest;
import org.junitpioneer.jupiter.cartesian.CartesianTest.Values;
/**
* Unit tests for {@link TmchXmlSignature}.
*
* <p>This class does not test the {@code revoked/smd/} folder because it's not a crypto issue.
* <p>This class does not verify if the SMD itself is revoked, which is different from if the
* certificate signging the SMD is revoked, as it is not a crypto issue.
*/
class TmchXmlSignatureTest {
@@ -44,38 +48,54 @@ class TmchXmlSignatureTest {
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
// This should be a date which falls within the validity range of the test files contained in the
// testdata/active directory. Note that test files claiming to be valid for a particular date
// smd/ directory. Note that test files claiming to be valid for a particular date
// range in the file header may not actually be valid the whole time, because they contain an
// embedded certificate which might have a shorter validity range.
// embedded (intermediate) certificate which might have a shorter validity range.
//
// New versions of the test files are published every few years by ICANN, and available at in the
// Signed Mark Data Files section of:
// "Signed Mark Data Files" section of:
//
// https://newgtlds.icann.org/en/about/trademark-clearinghouse/registries-registrars
//
// The link labeled "Set of IDN test-SMDs" leads to a .tar.gz file containing the test files which
// in our directory structure reside in testdata/active and testdata/revoked/smd (it is not clear
// where the files in testdata/invalid and testdata/revoked/tmv come from; we probably made them
// ourselves, since there aren't as many of them). For purposes of testing, we could probably keep
// using old test files forever, and keep a corresponding old date, but it seems like a good idea
// to keep up to date if possible.
//
// When updating this date, also update the dates below, which test to make sure that dates before
// and after the validity window result in rejection.
private final FakeClock clock = new FakeClock(DateTime.parse("2018-05-15T23:15:37.4Z"));
// When updating this date, also update the "time travel" dates in two tests below, which test to
// make sure that dates before and after the validity window result in rejection.
private final FakeClock clock = new FakeClock(DateTime.parse("2023-01-15T23:15:37.4Z"));
private byte[] smdData;
private TmchXmlSignature tmchXmlSignature =
new TmchXmlSignature(new TmchCertificateAuthority(TmchCaMode.PILOT, clock));
@BeforeEach
void beforeEach() {}
@Test
void testActive() throws Exception {
smdData = loadSmd("smd/active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testRevoked() throws Exception {
smdData = loadSmd("smd/revoked.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testInvalid() {
smdData = loadSmd("smd/invalid.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testTmvCertRevoked() {
smdData = loadSmd("smd/tmv-cert-revoked.smd");
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("Certificate has been revoked");
}
@Test
void testWrongCertificateAuthority() {
tmchXmlSignature =
new TmchXmlSignature(new TmchCertificateAuthority(TmchCaMode.PRODUCTION, clock));
smdData = loadSmd("active/Court-Agent-Arab-Active.smd");
smdData = loadSmd("smd/active.smd");
CertificateSignatureException e =
assertThrows(CertificateSignatureException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("Signature does not match");
@@ -83,265 +103,40 @@ class TmchXmlSignatureTest {
@Test
void testTimeTravelBeforeCertificateWasCreated() {
smdData = loadSmd("active/Court-Agent-Arab-Active.smd");
clock.setTo(DateTime.parse("2013-05-01T00:00:00Z"));
smdData = loadSmd("smd/active.smd");
clock.setTo(DateTime.parse("2021-05-01T00:00:00Z"));
assertThrows(CertificateNotYetValidException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testTimeTravelAfterCertificateHasExpired() {
smdData = loadSmd("active/Court-Agent-Arab-Active.smd");
clock.setTo(DateTime.parse("2023-06-01T00:00:00Z"));
smdData = loadSmd("smd/active.smd");
clock.setTo(DateTime.parse("2028-06-01T00:00:00Z"));
assertThrows(CertificateExpiredException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testActiveCourtAgentArabActive() throws Exception {
smdData = loadSmd("active/Court-Agent-Arab-Active.smd");
@CartesianTest
void testInd(
@Values(strings = {"Agent", "Holder"}) String contact,
@Values(strings = {"Court", "Trademark", "TreatyStatute"}) String type,
@Values(strings = {"Arab", "Chinese", "English", "French"}) String language,
@Values(strings = {"Active", "Revoked"}) String status)
throws Exception {
smdData =
loadSmd(
String.format(
"idn/%s-%s/%s-%s-%s-%s.smd", contact, language, type, contact, language, status));
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtAgentChineseActive() throws Exception {
smdData = loadSmd("active/Court-Agent-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtAgentEnglishActive() throws Exception {
smdData = loadSmd("active/Court-Agent-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtAgentFrenchActive() throws Exception {
smdData = loadSmd("active/Court-Agent-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtAgentRussianActive() throws Exception {
smdData = loadSmd("active/Court-Agent-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtHolderArabActive() throws Exception {
smdData = loadSmd("active/Court-Holder-Arab-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtHolderChineseActive() throws Exception {
smdData = loadSmd("active/Court-Holder-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtHolderEnglishActive() throws Exception {
smdData = loadSmd("active/Court-Holder-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtHolderFrenchActive() throws Exception {
smdData = loadSmd("active/Court-Holder-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveCourtHolderRussianActive() throws Exception {
smdData = loadSmd("active/Court-Holder-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkAgentArabActive() throws Exception {
smdData = loadSmd("active/Trademark-Agent-Arab-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkAgentChineseActive() throws Exception {
smdData = loadSmd("active/Trademark-Agent-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkAgentEnglishActive() throws Exception {
smdData = loadSmd("active/Trademark-Agent-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkAgentFrenchActive() throws Exception {
smdData = loadSmd("active/Trademark-Agent-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkAgentRussianActive() throws Exception {
smdData = loadSmd("active/Trademark-Agent-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkHolderArabActive() throws Exception {
smdData = loadSmd("active/Trademark-Holder-Arab-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkHolderChineseActive() throws Exception {
smdData = loadSmd("active/Trademark-Holder-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkHolderEnglishActive() throws Exception {
smdData = loadSmd("active/Trademark-Holder-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkHolderFrenchActive() throws Exception {
smdData = loadSmd("active/Trademark-Holder-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTrademarkHolderRussianActive() throws Exception {
smdData = loadSmd("active/Trademark-Holder-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteAgentArabActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Agent-Arab-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteAgentChineseActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Agent-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteAgentEnglishActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Agent-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteAgentFrenchActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Agent-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteAgentRussianActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Agent-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteHolderArabActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Holder-Arab-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteHolderChineseActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Holder-Chinese-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteHolderEnglishActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Holder-English-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteHolderFrenchActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Holder-French-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testActiveTreatystatuteHolderRussianActive() throws Exception {
smdData = loadSmd("active/TreatyStatute-Holder-Russian-Active.smd");
tmchXmlSignature.verify(smdData);
}
@Test
void testInvalidInvalidsignatureCourtAgentFrenchActive() {
smdData = loadSmd("invalid/InvalidSignature-Court-Agent-French-Active.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testInvalidInvalidsignatureTrademarkAgentEnglishActive() {
smdData = loadSmd("invalid/InvalidSignature-Trademark-Agent-English-Active.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testInvalidInvalidsignatureTrademarkAgentRussianActive() {
smdData = loadSmd("invalid/InvalidSignature-Trademark-Agent-Russian-Active.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testInvalidInvalidsignatureTreatystatuteAgentChineseActive() {
smdData = loadSmd("invalid/InvalidSignature-TreatyStatute-Agent-Chinese-Active.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testInvalidInvalidsignatureTreatystatuteAgentEnglishActive() {
smdData = loadSmd("invalid/InvalidSignature-TreatyStatute-Agent-English-Active.smd");
assertThrows(XMLSignatureException.class, () -> tmchXmlSignature.verify(smdData));
}
@Test
void testRevokedTmvTmvrevokedCourtAgentFrenchActive() {
smdData = loadSmd("revoked/tmv/TMVRevoked-Court-Agent-French-Active.smd");
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("KEY_COMPROMISE");
}
@Test
void testRevokedTmvTmvrevokedTrademarkAgentEnglishActive() {
smdData = loadSmd("revoked/tmv/TMVRevoked-Trademark-Agent-English-Active.smd");
@ParameterizedTest
@ValueSource(strings = {"Arab", "Chinese", "English", "French"})
void testIndTmvRevoked(String language) {
smdData =
loadSmd(
String.format("idn/RevokedCert/TMVRevoked-Trademark-Agent-%s-Active.smd", language));
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("Certificate has been revoked");
}
@Test
void testRevokedTmvTmvrevokedTrademarkAgentRussianActive() {
smdData = loadSmd("revoked/tmv/TMVRevoked-Trademark-Agent-Russian-Active.smd");
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("Certificate has been revoked");
}
@Test
void testRevokedTmvTmvrevokedTreatystatuteAgentChineseActive() {
smdData = loadSmd("revoked/tmv/TMVRevoked-TreatyStatute-Agent-Chinese-Active.smd");
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("KEY_COMPROMISE");
}
@Test
void testRevokedTmvTmvrevokedTreatystatuteAgentEnglishActive() {
smdData = loadSmd("revoked/tmv/TMVRevoked-TreatyStatute-Agent-English-Active.smd");
CertificateRevokedException e =
assertThrows(CertificateRevokedException.class, () -> tmchXmlSignature.verify(smdData));
assertThat(e).hasMessageThat().contains("KEY_COMPROMISE");
}
}
@@ -0,0 +1,139 @@
// Copyright 2023 The Nomulus Authors. 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 google.registry.ui.server.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static org.mockito.Mockito.mock;
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.UserAuthInfo;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.FakeResponse;
import google.registry.util.UtilsModule;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.ConsoleDomainGetAction}. */
public class ConsoleDomainGetActionTest {
private static final Gson GSON = UtilsModule.provideGson();
private static final FakeResponse RESPONSE = new FakeResponse();
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@BeforeEach
void beforeEach() {
createTld("tld");
DatabaseHelper.persistActiveDomain("exists.tld");
}
@Test
void testSuccess_fullJsonRepresentation() {
ConsoleDomainGetAction action =
createAction(
AuthResult.create(
AuthLevel.USER,
UserAuthInfo.create(
createUser(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of("TheRegistrar", RegistrarRole.ACCOUNT_MANAGER))
.build()))),
"exists.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
assertThat(RESPONSE.getPayload())
.isEqualTo(
"{\"domainName\":\"exists.tld\",\"adminContact\":{\"key\":\"3-ROID\"},\"techContact\":"
+ "{\"key\":\"3-ROID\"},\"registrantContact\":{\"key\":\"3-ROID\"},\"registrationExpirationTime\":"
+ "\"294247-01-10T04:00:54.775Z\",\"lastTransferTime\":\"null\",\"repoId\":\"2-TLD\","
+ "\"currentSponsorRegistrarId\":\"TheRegistrar\",\"creationRegistrarId\":\"TheRegistrar\","
+ "\"creationTime\":{\"creationTime\":\"1970-01-01T00:00:00.000Z\"},\"lastEppUpdateTime\":\"null\","
+ "\"statuses\":[\"INACTIVE\"]}");
}
@Test
void testFailure_emptyAuth() {
ConsoleDomainGetAction action = createAction(AuthResult.NOT_AUTHENTICATED, "exists.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
}
@Test
void testFailure_appAuth() {
ConsoleDomainGetAction action = createAction(AuthResult.create(AuthLevel.APP), "exists.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
}
@Test
void testFailure_wrongTypeOfUser() {
ConsoleDomainGetAction action =
createAction(
AuthResult.create(
AuthLevel.USER,
UserAuthInfo.create(mock(com.google.appengine.api.users.User.class), false)),
"exists.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
}
@Test
void testFailure_noAccessToRegistrar() {
ConsoleDomainGetAction action =
createAction(
AuthResult.create(
AuthLevel.USER, UserAuthInfo.create(createUser(new UserRoles.Builder().build()))),
"exists.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
}
@Test
void testFailure_nonexistentDomain() {
ConsoleDomainGetAction action =
createAction(
AuthResult.create(
AuthLevel.USER,
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))),
"nonexistent.tld");
action.run();
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
}
private User createUser(UserRoles userRoles) {
return new User.Builder()
.setEmailAddress("email@email.com")
.setGaiaId("gaiaId")
.setUserRoles(userRoles)
.build();
}
private ConsoleDomainGetAction createAction(AuthResult authResult, String domain) {
return new ConsoleDomainGetAction(authResult, RESPONSE, GSON, domain);
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,8 +6,8 @@
<resData>
<domain:creData xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
<domain:name>%DOMAIN%</domain:name>
<domain:crDate>2014-09-09T09:09:09Z</domain:crDate>
<domain:exDate>2016-09-09T09:09:09Z</domain:exDate>
<domain:crDate>%CREATE_TIME%</domain:crDate>
<domain:exDate>%EXPIRATION_TIME%</domain:exDate>
</domain:creData>
</resData>
<trID>
@@ -14,7 +14,7 @@
<extension>
<fee:creData xmlns:fee="urn:ietf:params:xml:ns:fee-%FEE_VERSION%">
<fee:currency>USD</fee:currency>
<fee:fee description="create">26.00</fee:fee>
<fee:fee description="create">%FEE%</fee:fee>
</fee:creData>
</extension>
<trID>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,6 @@
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
/_dr/epp EppTlsAction POST n INTERNAL,API APP PUBLIC
/console-api/domain ConsoleDomainGetAction GET n API,LEGACY USER PUBLIC
/registrar ConsoleUiAction GET n INTERNAL,API,LEGACY NONE PUBLIC
/registrar-create ConsoleRegistrarCreatorAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
/registrar-ote-setup ConsoleOteSetupAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
@@ -1,99 +0,0 @@
Marks: الاختبار &amp; لتقييم
smdID: 000000761526320373066-65535
U-labels: xn------nzeaagpf7azb2ppajr3fa, xn-----btdaafne4a7azpoaiq8ea, xn----ymcaaeld1a4a6onahp3ea, xn--mgbaadjcy1a8mmago8da
notBefore: 2018-05-14T17:52:53.066Z
notAfter: 2022-08-18T14:27:18.209Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il82MzZi
ZDEyYy02YzExLTRhOGYtYTVkZC01YmU0NzFhZGNiNWQiPjxzbWQ6aWQ+MDAwMDAwNzYxNTI2MzIw
MzczMDY2LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo1My4wNjZaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDoyNzoxOC4yMDlaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDQxNTAzMDY2MDIyMTUwMzA2NjAyMi0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPtin2YTYp9iu2KrYqNin2LEgJmFtcDsg2YTYqtmC2YrZitmFPC9tYXJrOm1hcmtO
YW1lPjxtYXJrOmhvbGRlciBlbnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm9yZz7ZiNmD2KfZhNip
PC9tYXJrOm9yZz48bWFyazphZGRyPjxtYXJrOnN0cmVldD7YrNi52YHYsSDYp9io2YYg2LPZitmG
2KfYoSA3NTwvbWFyazpzdHJlZXQ+PG1hcms6Y2l0eT7ZhdmD2YbYp9izPC9tYXJrOmNpdHk+PG1h
cms6cGM+MjkwMDwvbWFyazpwYz48bWFyazpjYz5NQTwvbWFyazpjYz48L21hcms6YWRkcj48L21h
cms6aG9sZGVyPjxtYXJrOmNvbnRhY3QgdHlwZT0iYWdlbnQiPjxtYXJrOm5hbWU+2YXZh9mG2K/Y
syDYp9mE2YXYudmE2YjZhdin2KrZitipPC9tYXJrOm5hbWU+PG1hcms6b3JnPtmI2YPYp9mE2Kk8
L21hcms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3RyZWV0Pti02KfYsdi5INis2LnZgdixINin2KjZ
hiDYs9mK2YbYp9ihIDc1PC9tYXJrOnN0cmVldD48bWFyazpjaXR5PtmF2YPZhtin2LM8L21hcms6
Y2l0eT48bWFyazpwYz4yOTAwPC9tYXJrOnBjPjxtYXJrOmNjPk1BPC9tYXJrOmNjPjwvbWFyazph
ZGRyPjxtYXJrOnZvaWNlPisyMTIuNTIyNTM5MDQwPC9tYXJrOnZvaWNlPjxtYXJrOmZheD4rMjEy
LjUyMjUzOTA0MTwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BhZ2VuY3ktbWFyb2Njby5jb208
L21hcms6ZW1haWw+PC9tYXJrOmNvbnRhY3Q+PG1hcms6bGFiZWw+eG4tLS0tLS1uemVhYWdwZjdh
emIycHBhanIzZmE8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS0tLWJ0ZGFhZm5lNGE3YXpw
b2FpcThlYTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tLS15bWNhYWVsZDFhNGE2b25haHAz
ZWE8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLW1nYmFhZGpjeTFhOG1tYWdvOGRhPC9tYXJr
OmxhYmVsPjxtYXJrOmdvb2RzQW5kU2VydmljZXM+2LrZitiq2KfYscKnPC9tYXJrOmdvb2RzQW5k
U2VydmljZXM+PG1hcms6cmVmTnVtPjEyMzQ8L21hcms6cmVmTnVtPjxtYXJrOnByb0RhdGU+MjAx
NC0wOS0wOFQwMDowMDowMC4wMDBaPC9tYXJrOnByb0RhdGU+PG1hcms6Y2M+VVM8L21hcms6Y2M+
PG1hcms6Y291cnROYW1lPtin2YTYr9in2LEg2KfZhNio2YrYttin2KE8L21hcms6Y291cnROYW1l
PjwvbWFyazpjb3VydD48L21hcms6bWFyaz48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8v
d3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJZD0iX2Y5YjhmY2I1LWIyNWMtNDEzOS1hZGE1
LTRjOGVhNjEwY2NkOSI+PGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2Qg
QWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6
U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxk
c2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZlcmVuY2UgVVJJPSIjXzYzNmJkMTJjLTZjMTEt
NGE4Zi1hNWRkLTViZTQ3MWFkY2I1ZCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0
dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAv
eG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRo
bT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZh
bHVlPnNzQldOUE1COFBFbVlPbGMzVlpNaFVlL1BZa2tmWm1tcCt1TXdWZGN4M3M9PC9kczpEaWdl
c3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48ZHM6UmVmZXJlbmNlIFVSST0iI184OWIzYzk0YS0wMmE0
LTRhNTMtOWI5Yi03MjFiN2NkMjMzNTUiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxn
b3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRy
YW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIw
MDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5YcXNTbW1BZUZBTnJxaGtwTFlG
OE55UFZWUHFtcktYTmhmamFlUVVhRG9NPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+
PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZSBJZD0iXzQ3ZjgxY2I0LWNkMjktNDJj
Mi1iZTdjLTFhNzI0ZTVhY2I4NSI+dm5pVCtid2xTTDJBTVh1TFNrV0kzVFExdDEwR1p1TFJRL1Vr
bjZZNG9SUWRjc0RiTUlmcUFvRUdiT2FjbStvM2lEU1V4RTlwVGdzNwpjUDJaR1FsNk9zbmF3YzR0
dEZVdmZVVEx1TGhPR2U5d0cvdXFJR1h5Q3RrZUNWcTJUZitjOGRzZlU2OGFHSkdqVHptZEJVUVR2
ZWp6CkNFK2VzRjNFNTFUQ3RkUGxhek15Mm5uQ3Z1bWJzTHU1WnFRWlF2Q20xb25LMGRxMnF6a3k0
UWFYSDA0WFpiU2FHcFVaUmp1dDkrTHQKUW9KZm5VeFNOa1MrRC9aWVl5b3lpb2RoWVdPQ1Z1Mk1a
MUQvOGlHQUFWRGdmS1RwbXN6RXZsb1F1N2wxeUtIaU1SU2h1ZFY2RGRUKwpRRzBrdTRDbEhUWFdO
RFBMQ0J0TUJELzhUakdldFJncGtFaXNQdz09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5m
byBJZD0iXzg5YjNjOTRhLTAyYTQtNGE1My05YjliLTcyMWI3Y2QyMzM1NSI+PGRzOlg1MDlEYXRh
PjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRk96Q0NCQ09nQXdJQkFnSWdMckFiZXZvYWU1MnkzZjZD
MnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOaFpjd0RRWUpLb1pJaHZjTgpBUUVMQlFBd2ZERUxNQWtH
QTFVRUJoTUNWVk14UERBNkJnTlZCQW9UTTBsdWRHVnlibVYwSUVOdmNuQnZjbUYwYVc5dUlHWnZj
aUJCCmMzTnBaMjVsWkNCT1lXMWxjeUJoYm1RZ1RuVnRZbVZ5Y3pFdk1DMEdBMVVFQXhNbVNVTkJU
azRnVkhKaFpHVnRZWEpySUVOc1pXRnkKYVc1bmFHOTFjMlVnVUdsc2IzUWdRMEV3SGhjTk1UZ3dN
akk0TURBd01EQXdXaGNOTWpNd016QXhNak0xT1RVNVdqQ0JqekVMTUFrRwpBMVVFQmhNQ1FrVXhJ
REFlQmdOVkJBZ1RGMEp5ZFhOelpXeHpMVU5oY0dsMFlXd2dVbVZuYVc5dU1SRXdEd1lEVlFRSEV3
aENjblZ6CmMyVnNjekVSTUE4R0ExVUVDaE1JUkdWc2IybDBkR1V4T0RBMkJnTlZCQU1UTDBsRFFV
NU9JRlJOUTBnZ1FYVjBhRzl5YVhwbFpDQlUKY21Ga1pXMWhjbXNnVUdsc2IzUWdWbUZzYVdSaGRH
OXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQQp4bHAzS3BZSFgz
V3lBc0ZoU2szTHdXZm5HbHhuVURGcUZaQTNVb3VNWWovWGlnYk1rTmVFWElqbGtST0tUNE9QR2ZS
eC9MQXlSbFFRCmpDTXY0cWhia2NYMXA3YXI2M2ZscTRTWk5WY2wxNWw3aDB1VDU4RnpTZm5sejB1
NXJrSGZKSW1ENDMrbWFQLzhndjM2RlIyN2pXOFIKOXdZNGhrK1dzNElCMGlGU2Q4U1h2MUtyOHcv
Sm1NUVNEa2l1RytSZklpdWJ3US9meTdFa2o1UVdoUFp3K21NeE5LbkhVTHkzeFl6MgpMd1ZmZnRq
d1V1ZWFjdnFOUkNrTVhsQ2xPQURxZlQ4b1Nab2VEWGVoSHZsUHNMQ2VtR0JvVEt1cnNrSVM2OUYw
eVBFSDVnemUwSCtmCjhGUk9zSW9LU3NWUTM0QjRTL2pvRTY3bnBzSlBUZEtzTlBKVHlRSURBUUFC
bzRJQmt6Q0NBWTh3REFZRFZSMFRBUUgvQkFJd0FEQWQKQmdOVkhRNEVGZ1FVb0ZwWTc2cDV5b05E
Ukd0UXB6VnVSODFVV1Ewd2djWUdBMVVkSXdTQnZqQ0J1NEFVdzYwK3B0WVJBRVdBWERwWApTb3B0
M0RFTm5uR2hnWUNrZmpCOE1Rc3dDUVlEVlFRR0V3SlZVekU4TURvR0ExVUVDaE16U1c1MFpYSnVa
WFFnUTI5eWNHOXlZWFJwCmIyNGdabTl5SUVGemMybG5ibVZrSUU1aGJXVnpJR0Z1WkNCT2RXMWla
WEp6TVM4d0xRWURWUVFERXlaSlEwRk9UaUJVY21Ga1pXMWgKY21zZ1EyeGxZWEpwYm1kb2IzVnpa
U0JRYVd4dmRDQkRRWUlnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTgpo
WGt3RGdZRFZSMFBBUUgvQkFRREFnZUFNRFFHQTFVZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5
OWpjbXd1YVdOaGJtNHViM0puCkwzUnRZMmhmY0dsc2IzUXVZM0pzTUZFR0ExVWRJQVJLTUVnd0VB
WU9Ld1lCQkFHQ3lSc0JCWU03REFvd05BWUlLd1lCQlFVSEFnRXcKS0RBbUJnZ3JCZ0VGQlFjQ0FS
WWFhSFIwY0hNNkx5OWpZUzVwWTJGdWJpNXZjbWN2Y0dsc2IzUXdEUVlKS29aSWh2Y05BUUVMQlFB
RApnZ0VCQUF1aloySWNSMkRWcnRhUnJBNTllTllDbDR4Y3NKTXU4RFFDSHYyOGZUZmkvQmlaWTRJ
cjdGOWtGeTk2RDdPWjhvTFk1empmCjRkSHhGd0hQcUg4RGg2Sldzelh1SFcxWmEzWG1sMFBhSHhD
V1JTMFhvbDhXc0hIcE55Z2pNQllmSjBvZFZNODg1VFoxRWw5U2l1RUgKbnluRkJnU21pRmM5OXVR
ZC9ZRFJadUd2L0EwSHl2N3lSOXRrTEVkRDNBMXVOSkJXNFArSEpHcGRLa1lMMVE1clU3K29IVlB0
TUtLSQozaUZrVUVzYk80NUFWZDd2UC9qLzdKdEFaUGI2a29PVjVsWmkySDFSTGNjR3d6ZGV6bmhK
Z2QwTjlvYmIwdm5FNDEvVVNXYWZkV1JaClZHa3dQdXFUaGw3c0N0enJKSDhYWTB4Y3VtK2NmTHgy
RUFJd1VuT2NhYjQ9PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUlu
Zm8+PC9kczpTaWduYXR1cmU+PC9zbWQ6c2lnbmVkTWFyaz4=
-----END ENCODED SMD-----
@@ -1,97 +0,0 @@
Marks: 标记&amp;记录
smdID: 000000791526320378900-65535
U-labels: xn----kw3bu0xlr2bba, xn--and-vj3ft79a885cda, xn--w2t96qr64aa
notBefore: 2018-05-14T17:52:58.900Z
notAfter: 2022-08-18T14:36:50.931Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8yOTg3
MmViNi0xY2JiLTQzYjMtYmIzMy1kZjA2MzhmZmQ0MjciPjxzbWQ6aWQ+MDAwMDAwNzkxNTI2MzIw
Mzc4OTAwLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo1OC45MDBaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDozNjo1MC45MzFaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDYxNTAzMDY2NjMxMTUwMzA2NjYzMS0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPuagh+iusCZhbXA76K6w5b2VPC9tYXJrOm1hcmtOYW1lPjxtYXJrOmhvbGRlciBl
bnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm9yZz7lt6XnqIvlpIQ8L21hcms6b3JnPjxtYXJrOmFk
ZHI+PG1hcms6c3RyZWV0Pummmea4r+S4nOi3rzblj7fvvIw15Y+35qW877yMOOWPt+WupDwvbWFy
azpzdHJlZXQ+PG1hcms6Y2l0eT7pnZLlspvluII8L21hcms6Y2l0eT48bWFyazpwYz4zNTAwPC9t
YXJrOnBjPjxtYXJrOmNjPkNOPC9tYXJrOmNjPjwvbWFyazphZGRyPjwvbWFyazpob2xkZXI+PG1h
cms6Y29udGFjdCB0eXBlPSJhZ2VudCI+PG1hcms6bmFtZT7mnY7lsI/mlrk8L21hcms6bmFtZT48
bWFyazpvcmc+5bel56iL5aSEPC9tYXJrOm9yZz48bWFyazphZGRyPjxtYXJrOnN0cmVldD7pppnm
uK/kuJzot6825Y+377yMNeWPt+alvO+8jDjlj7flrqQ8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+
6Z2S5bKb5biCPC9tYXJrOmNpdHk+PG1hcms6cGM+MzUwMDwvbWFyazpwYz48bWFyazpjYz5DTjwv
bWFyazpjYz48L21hcms6YWRkcj48bWFyazp2b2ljZT4rODYuMTA4NDY1NzE3MzwvbWFyazp2b2lj
ZT48bWFyazpmYXg+Kzg2LjEwODQ2NTcxNzU8L21hcms6ZmF4PjxtYXJrOmVtYWlsPmluZm9AY2hp
bmVzZS1hZ2VuY3kuY29tPC9tYXJrOmVtYWlsPjwvbWFyazpjb250YWN0PjxtYXJrOmxhYmVsPnhu
LS0tLWt3M2J1MHhscjJiYmE8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLWFuZC12ajNmdDc5
YTg4NWNkYTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tdzJ0OTZxcjY0YWE8L21hcms6bGFi
ZWw+PG1hcms6Z29vZHNBbmRTZXJ2aWNlcz4g5ZCJ5LuWPC9tYXJrOmdvb2RzQW5kU2VydmljZXM+
PG1hcms6cmVmTnVtPjEyMzQ8L21hcms6cmVmTnVtPjxtYXJrOnByb0RhdGU+MjAxMy0wMS0wMVQw
MDowMDowMC4wMDBaPC9tYXJrOnByb0RhdGU+PG1hcms6Y2M+VVM8L21hcms6Y2M+PG1hcms6Y291
cnROYW1lPkhvdmU8L21hcms6Y291cnROYW1lPjwvbWFyazpjb3VydD48L21hcms6bWFyaz48ZHM6
U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJ
ZD0iXzI3ZDI4YTJhLTIyOGMtNDMxNS04YTQ0LTY5NDU1ODdhYjkwYSI+PGRzOlNpZ25lZEluZm8+
PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8y
MDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0
cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZl
cmVuY2UgVVJJPSIjXzI5ODcyZWI2LTFjYmItNDNiMy1iYjMzLWRmMDYzOGZmZDQyNyI+PGRzOlRy
YW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAv
MDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09
Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jt
cz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94
bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPmYwdWNzMUZjM2VwSGxHaldVa3ZVaG4vM0p2
V0pMUjl3d2tWSjZkMXRSdXc9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48ZHM6UmVm
ZXJlbmNlIFVSST0iI19mMGVlZmI2NS00Zjg5LTQ4OTktYWQ3Ny04ZGI2MGY3M2UzMDAiPjxkczpU
cmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAx
LzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdl
c3RWYWx1ZT5WalVhVnhGM0dGNkwzYWUvNGJOUHl0VWRoVE1RZFNNS09mMURaY1lsN3VRPTwvZHM6
RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVW
YWx1ZSBJZD0iXzhmNzZhNTEwLThjYmUtNDI0OS05M2FjLTM4MTM2YTc5NTg2YyI+RUltei9JSWZ4
OG5zbVc3TExONXRCbi9NN2VYUDN3QXZVSmNyY2xJaTVCMVBXcldmd2lhbGVvd1lPVGFnWE15cnN5
RWMycklETEpQRAprNStZMWxjSnVRaWd6aTd4YlFkaTQveGswRUVJRjJ0TUNDYkgxU0Nua1VoRGkv
c096RVJKeXdncWlhbTN2bmE5UE5YaWEzaCs2bU5ICkpOVVZvWWQ3bW4xbHBHOTNkQzA5cVdIbWRT
MHRrRVZZQkgyTDlldHJFNjhBMEROWDRaa0NJL05YdzRvQVVlWGtUNUZIWlpJSHRRek4KTlNzUGRX
Ujl5a0hMRWZ4NFo5YThES0YzU2JtUnJKVktNbzNLRlhCNzQyVjFRcldsc2xsSmtHMGpBR3Freklw
UGxyTm52M2hWUlFrZgpEUUs5QXZ2QlhCSm94UEpFYTFDYzRBKysxQUFqZXBkVVp6ZlV6QT09PC9k
czpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbyBJZD0iX2YwZWVmYjY1LTRmODktNDg5OS1hZDc3
LThkYjYwZjczZTMwMCI+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRk96Q0NC
Q09nQXdJQkFnSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOaFpjd0RR
WUpLb1pJaHZjTgpBUUVMQlFBd2ZERUxNQWtHQTFVRUJoTUNWVk14UERBNkJnTlZCQW9UTTBsdWRH
VnlibVYwSUVOdmNuQnZjbUYwYVc5dUlHWnZjaUJCCmMzTnBaMjVsWkNCT1lXMWxjeUJoYm1RZ1Ru
VnRZbVZ5Y3pFdk1DMEdBMVVFQXhNbVNVTkJUazRnVkhKaFpHVnRZWEpySUVOc1pXRnkKYVc1bmFH
OTFjMlVnVUdsc2IzUWdRMEV3SGhjTk1UZ3dNakk0TURBd01EQXdXaGNOTWpNd016QXhNak0xT1RV
NVdqQ0JqekVMTUFrRwpBMVVFQmhNQ1FrVXhJREFlQmdOVkJBZ1RGMEp5ZFhOelpXeHpMVU5oY0ds
MFlXd2dVbVZuYVc5dU1SRXdEd1lEVlFRSEV3aENjblZ6CmMyVnNjekVSTUE4R0ExVUVDaE1JUkdW
c2IybDBkR1V4T0RBMkJnTlZCQU1UTDBsRFFVNU9JRlJOUTBnZ1FYVjBhRzl5YVhwbFpDQlUKY21G
a1pXMWhjbXNnVUdsc2IzUWdWbUZzYVdSaGRHOXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9D
QVE4QU1JSUJDZ0tDQVFFQQp4bHAzS3BZSFgzV3lBc0ZoU2szTHdXZm5HbHhuVURGcUZaQTNVb3VN
WWovWGlnYk1rTmVFWElqbGtST0tUNE9QR2ZSeC9MQXlSbFFRCmpDTXY0cWhia2NYMXA3YXI2M2Zs
cTRTWk5WY2wxNWw3aDB1VDU4RnpTZm5sejB1NXJrSGZKSW1ENDMrbWFQLzhndjM2RlIyN2pXOFIK
OXdZNGhrK1dzNElCMGlGU2Q4U1h2MUtyOHcvSm1NUVNEa2l1RytSZklpdWJ3US9meTdFa2o1UVdo
UFp3K21NeE5LbkhVTHkzeFl6MgpMd1ZmZnRqd1V1ZWFjdnFOUkNrTVhsQ2xPQURxZlQ4b1Nab2VE
WGVoSHZsUHNMQ2VtR0JvVEt1cnNrSVM2OUYweVBFSDVnemUwSCtmCjhGUk9zSW9LU3NWUTM0QjRT
L2pvRTY3bnBzSlBUZEtzTlBKVHlRSURBUUFCbzRJQmt6Q0NBWTh3REFZRFZSMFRBUUgvQkFJd0FE
QWQKQmdOVkhRNEVGZ1FVb0ZwWTc2cDV5b05EUkd0UXB6VnVSODFVV1Ewd2djWUdBMVVkSXdTQnZq
Q0J1NEFVdzYwK3B0WVJBRVdBWERwWApTb3B0M0RFTm5uR2hnWUNrZmpCOE1Rc3dDUVlEVlFRR0V3
SlZVekU4TURvR0ExVUVDaE16U1c1MFpYSnVaWFFnUTI5eWNHOXlZWFJwCmIyNGdabTl5SUVGemMy
bG5ibVZrSUU1aGJXVnpJR0Z1WkNCT2RXMWlaWEp6TVM4d0xRWURWUVFERXlaSlEwRk9UaUJVY21G
a1pXMWgKY21zZ1EyeGxZWEpwYm1kb2IzVnpaU0JRYVd4dmRDQkRRWUlnTHJBYmV2b2FlNTJ5M2Y2
QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTgpoWGt3RGdZRFZSMFBBUUgvQkFRREFnZUFNRFFHQTFV
ZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5OWpjbXd1YVdOaGJtNHViM0puCkwzUnRZMmhmY0ds
c2IzUXVZM0pzTUZFR0ExVWRJQVJLTUVnd0VBWU9Ld1lCQkFHQ3lSc0JCWU03REFvd05BWUlLd1lC
QlFVSEFnRXcKS0RBbUJnZ3JCZ0VGQlFjQ0FSWWFhSFIwY0hNNkx5OWpZUzVwWTJGdWJpNXZjbWN2
Y0dsc2IzUXdEUVlKS29aSWh2Y05BUUVMQlFBRApnZ0VCQUF1aloySWNSMkRWcnRhUnJBNTllTllD
bDR4Y3NKTXU4RFFDSHYyOGZUZmkvQmlaWTRJcjdGOWtGeTk2RDdPWjhvTFk1empmCjRkSHhGd0hQ
cUg4RGg2Sldzelh1SFcxWmEzWG1sMFBhSHhDV1JTMFhvbDhXc0hIcE55Z2pNQllmSjBvZFZNODg1
VFoxRWw5U2l1RUgKbnluRkJnU21pRmM5OXVRZC9ZRFJadUd2L0EwSHl2N3lSOXRrTEVkRDNBMXVO
SkJXNFArSEpHcGRLa1lMMVE1clU3K29IVlB0TUtLSQozaUZrVUVzYk80NUFWZDd2UC9qLzdKdEFa
UGI2a29PVjVsWmkySDFSTGNjR3d6ZGV6bmhKZ2QwTjlvYmIwdm5FNDEvVVNXYWZkV1JaClZHa3dQ
dXFUaGw3c0N0enJKSDhYWTB4Y3VtK2NmTHgyRUFJd1VuT2NhYjQ9PC9kczpYNTA5Q2VydGlmaWNh
dGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PC9zbWQ6c2lnbmVk
TWFyaz4=
-----END ENCODED SMD-----
@@ -1,100 +0,0 @@
Marks: Test &amp; Validate
smdID: 000000851526320390595-65535
U-labels: test---validate, test--validate, test-and-validate, test-andvalidate, test-validate, testand-validate, testandvalidate, testvalidate
notBefore: 2018-05-14T17:53:10.595Z
notAfter: 2022-08-18T14:57:36.681Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8wYjlj
YTI5My0yYjExLTQ4M2MtYjZjMi0xYTk5MGIyMTdlYjgiPjxzbWQ6aWQ+MDAwMDAwODUxNTI2MzIw
MzkwNTk1LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzoxMC41OTVaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDo1NzozNi42ODFaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxMzcxNTAzMDY3ODY4MTUwMzA2Nzg2OC0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPlRlc3QgJmFtcDsgVmFsaWRhdGU8L21hcms6bWFya05hbWU+PG1hcms6aG9sZGVy
IGVudGl0bGVtZW50PSJvd25lciI+PG1hcms6bmFtZT5Ub255IEhvbGxhbmQ8L21hcms6bmFtZT48
bWFyazpvcmc+QWcgY29ycG9yYXRpb248L21hcms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3RyZWV0
PjEzMDUgQnJpZ2h0IEF2ZW51ZTwvbWFyazpzdHJlZXQ+PG1hcms6Y2l0eT5BcmNhZGlhPC9tYXJr
OmNpdHk+PG1hcms6cGM+OTAwMjg8L21hcms6cGM+PG1hcms6Y2M+VVM8L21hcms6Y2M+PC9tYXJr
OmFkZHI+PC9tYXJrOmhvbGRlcj48bWFyazpjb250YWN0IHR5cGU9ImFnZW50Ij48bWFyazpuYW1l
PlRvbnkgSG9sbGFuZDwvbWFyazpuYW1lPjxtYXJrOm9yZz5BZyBjb3Jwb3JhdGlvbjwvbWFyazpv
cmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+QnJpZ2h0IEF2ZW51ZSAxMzA1IDwvbWFyazpzdHJl
ZXQ+PG1hcms6Y2l0eT5BcmNhZGlhPC9tYXJrOmNpdHk+PG1hcms6c3A+Q0E8L21hcms6c3A+PG1h
cms6cGM+OTAwMjg8L21hcms6cGM+PG1hcms6Y2M+VVM8L21hcms6Y2M+PC9tYXJrOmFkZHI+PG1h
cms6dm9pY2U+KzEuMjAyNTU2MjMwMjwvbWFyazp2b2ljZT48bWFyazpmYXg+KzEuMjAyNTU2MjMw
MTwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BhZ2NvcnBvcmF0aW9uLmNvbTwvbWFyazplbWFp
bD48L21hcms6Y29udGFjdD48bWFyazpsYWJlbD50ZXN0LS0tdmFsaWRhdGU8L21hcms6bGFiZWw+
PG1hcms6bGFiZWw+dGVzdC0tdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdC1h
bmQtdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdC1hbmR2YWxpZGF0ZTwvbWFy
azpsYWJlbD48bWFyazpsYWJlbD50ZXN0LXZhbGlkYXRlPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVs
PnRlc3RhbmQtdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdGFuZHZhbGlkYXRl
PC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnRlc3R2YWxpZGF0ZTwvbWFyazpsYWJlbD48bWFyazpn
b29kc0FuZFNlcnZpY2VzPmd1aXRhcjwvbWFyazpnb29kc0FuZFNlcnZpY2VzPjxtYXJrOnJlZk51
bT4xMjM0PC9tYXJrOnJlZk51bT48bWFyazpwcm9EYXRlPjIwMTMtMDEtMDFUMDA6MDA6MDAuMDAw
WjwvbWFyazpwcm9EYXRlPjxtYXJrOmNjPlVTPC9tYXJrOmNjPjxtYXJrOmNvdXJ0TmFtZT5Ib3Zl
PC9tYXJrOmNvdXJ0TmFtZT48L21hcms6Y291cnQ+PC9tYXJrOm1hcms+PGRzOlNpZ25hdHVyZSB4
bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgSWQ9Il83NzViYTgx
YS1mMWYzLTQ3OTgtODE4NS1hODkzNmYyZTI4MTkiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmlj
YWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwt
ZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMu
b3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0i
I18wYjljYTI5My0yYjExLTQ4M2MtYjZjMi0xYTk5MGIyMTdlYjgiPjxkczpUcmFuc2Zvcm1zPjxk
czpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcj
ZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3
LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2Vz
dE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1
NiIvPjxkczpEaWdlc3RWYWx1ZT5xYVZhY2gxNFNkbHd1R0JBNk0xV0ZFdUJuQnM1RW01QjExWDg5
YndGR1E4PTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PGRzOlJlZmVyZW5jZSBVUkk9
IiNfY2I3YjUxMWUtNjdiNC00ZTlhLTlmODAtZDdkYjg2MjY4ZGRmIj48ZHM6VHJhbnNmb3Jtcz48
ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhj
LWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRw
Oi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+cEND
NVlpakJXUWFmM0J3VWVzbEh2TVNFNjcyZ1NUWVNqencxN3VLZDdmOD08L2RzOkRpZ2VzdFZhbHVl
PjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWUgSWQ9Il84
MTkyMTFkOS02ZDUzLTQwMzgtOTBiYi01MDAxYTk5MDE0MDgiPmxZNjBKZEpoMGs1MElTWm4yYzAz
VFRGc1c4bURxaVNDTUFKeDkwNlVEb2FUM2tndUh6cXM0c1V5VXRobEdWOXhMMlNkNmQwNkVrcTUK
aVFnVnFKNGN2ZldlVjlJN2hxSk16NldjOHpNdXBFZ2ZlUGVLWkNYL2JlaGtGM3RSRHJ4NGdqbFBR
RDVhV0MveURjWEJjWGo1QU4xNwpMY0pnVjVDMmUxSzVNWjV6amFzWExTaHJnMEtuZ1Y5S094RXl3
Zm9LZWtTWWRzZWpJYTRCYjVnVzgzMG1uMEtKWjdOaUVqclB1TTU5CklqbTExYTNyY2Q1L2hGNGln
TTQ3RWI0YVg4WG1NRDU1N0xnVy9FWStHbGpKNWFFRlJrN1hMZ2ZTM2VPcGptUGlyNGpCZGIwSDBJ
NkYKRkNHM0pua0F6UWxUeFo3RUZ6L0Zqa2VnREVoSXhIMHBLTW1LM1E9PTwvZHM6U2lnbmF0dXJl
VmFsdWU+PGRzOktleUluZm8gSWQ9Il9jYjdiNTExZS02N2I0LTRlOWEtOWY4MC1kN2RiODYyNjhk
ZGYiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUZPekNDQkNPZ0F3SUJBZ0ln
THJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTmhaY3dEUVlKS29aSWh2Y04K
QVFFTEJRQXdmREVMTUFrR0ExVUVCaE1DVlZNeFBEQTZCZ05WQkFvVE0wbHVkR1Z5Ym1WMElFTnZj
bkJ2Y21GMGFXOXVJR1p2Y2lCQgpjM05wWjI1bFpDQk9ZVzFsY3lCaGJtUWdUblZ0WW1WeWN6RXZN
QzBHQTFVRUF4TW1TVU5CVGs0Z1ZISmhaR1Z0WVhKcklFTnNaV0Z5CmFXNW5hRzkxYzJVZ1VHbHNi
M1FnUTBFd0hoY05NVGd3TWpJNE1EQXdNREF3V2hjTk1qTXdNekF4TWpNMU9UVTVXakNCanpFTE1B
a0cKQTFVRUJoTUNRa1V4SURBZUJnTlZCQWdURjBKeWRYTnpaV3h6TFVOaGNHbDBZV3dnVW1WbmFX
OXVNUkV3RHdZRFZRUUhFd2hDY25WegpjMlZzY3pFUk1BOEdBMVVFQ2hNSVJHVnNiMmwwZEdVeE9E
QTJCZ05WQkFNVEwwbERRVTVPSUZSTlEwZ2dRWFYwYUc5eWFYcGxaQ0JVCmNtRmtaVzFoY21zZ1VH
bHNiM1FnVm1Gc2FXUmhkRzl5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dL
Q0FRRUEKeGxwM0twWUhYM1d5QXNGaFNrM0x3V2ZuR2x4blVERnFGWkEzVW91TVlqL1hpZ2JNa05l
RVhJamxrUk9LVDRPUEdmUngvTEF5UmxRUQpqQ012NHFoYmtjWDFwN2FyNjNmbHE0U1pOVmNsMTVs
N2gwdVQ1OEZ6U2ZubHowdTVya0hmSkltRDQzK21hUC84Z3YzNkZSMjdqVzhSCjl3WTRoaytXczRJ
QjBpRlNkOFNYdjFLcjh3L0ptTVFTRGtpdUcrUmZJaXVid1EvZnk3RWtqNVFXaFBadyttTXhOS25I
VUx5M3hZejIKTHdWZmZ0andVdWVhY3ZxTlJDa01YbENsT0FEcWZUOG9TWm9lRFhlaEh2bFBzTENl
bUdCb1RLdXJza0lTNjlGMHlQRUg1Z3plMEgrZgo4RlJPc0lvS1NzVlEzNEI0Uy9qb0U2N25wc0pQ
VGRLc05QSlR5UUlEQVFBQm80SUJrekNDQVk4d0RBWURWUjBUQVFIL0JBSXdBREFkCkJnTlZIUTRF
RmdRVW9GcFk3NnA1eW9ORFJHdFFwelZ1UjgxVVdRMHdnY1lHQTFVZEl3U0J2akNCdTRBVXc2MCtw
dFlSQUVXQVhEcFgKU29wdDNERU5ubkdoZ1lDa2ZqQjhNUXN3Q1FZRFZRUUdFd0pWVXpFOE1Eb0dB
MVVFQ2hNelNXNTBaWEp1WlhRZ1EyOXljRzl5WVhScApiMjRnWm05eUlFRnpjMmxuYm1Wa0lFNWhi
V1Z6SUdGdVpDQk9kVzFpWlhKek1TOHdMUVlEVlFRREV5WkpRMEZPVGlCVWNtRmtaVzFoCmNtc2dR
MnhsWVhKcGJtZG9iM1Z6WlNCUWFXeHZkQ0JEUVlJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdY
Sm0wVDAyRm9neEtDZk4KaFhrd0RnWURWUjBQQVFIL0JBUURBZ2VBTURRR0ExVWRId1F0TUNzd0th
QW5vQ1dHSTJoMGRIQTZMeTlqY213dWFXTmhibTR1YjNKbgpMM1J0WTJoZmNHbHNiM1F1WTNKc01G
RUdBMVVkSUFSS01FZ3dFQVlPS3dZQkJBR0N5UnNCQllNN0RBb3dOQVlJS3dZQkJRVUhBZ0V3CktE
QW1CZ2dyQmdFRkJRY0NBUllhYUhSMGNITTZMeTlqWVM1cFkyRnViaTV2Y21jdmNHbHNiM1F3RFFZ
SktvWklodmNOQVFFTEJRQUQKZ2dFQkFBdWpaMkljUjJEVnJ0YVJyQTU5ZU5ZQ2w0eGNzSk11OERR
Q0h2MjhmVGZpL0JpWlk0SXI3RjlrRnk5NkQ3T1o4b0xZNXpqZgo0ZEh4RndIUHFIOERoNkpXc3pY
dUhXMVphM1htbDBQYUh4Q1dSUzBYb2w4V3NISHBOeWdqTUJZZkowb2RWTTg4NVRaMUVsOVNpdUVI
Cm55bkZCZ1NtaUZjOTl1UWQvWURSWnVHdi9BMEh5djd5Ujl0a0xFZEQzQTF1TkpCVzRQK0hKR3Bk
S2tZTDFRNXJVNytvSFZQdE1LS0kKM2lGa1VFc2JPNDVBVmQ3dlAvai83SnRBWlBiNmtvT1Y1bFpp
MkgxUkxjY0d3emRlem5oSmdkME45b2JiMHZuRTQxL1VTV2FmZFdSWgpWR2t3UHVxVGhsN3NDdHpy
Skg4WFkweGN1bStjZkx4MkVBSXdVbk9jYWI0PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUw
OURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjwvc21kOnNpZ25lZE1hcms+
-----END ENCODED SMD-----
@@ -1,101 +0,0 @@
Marks: Essai &amp; évaluation
smdID: 000000821526320384749-65535
U-labels: xn--essai---valuation-itb, xn--essai--valuation-hqb, xn--essai-et-valuation-jwb, xn--essai-etvaluation-itb, xn--essai-valuation-gnb, xn--essaiet-valuation-itb, xn--essaietvaluation-hqb, xn--essaivaluation-fkb
notBefore: 2018-05-14T17:53:04.749Z
notAfter: 2022-08-18T14:46:53.013Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il84MGIx
NGY4MS1mODA0LTQwYjMtOGRjZC1iOTNhNjVhNTc5MTgiPjxzbWQ6aWQ+MDAwMDAwODIxNTI2MzIw
Mzg0NzQ5LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzowNC43NDlaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDo0Njo1My4wMTNaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxMzkxNTAzMDY3MTg5MTUwMzA2NzE4OS0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPkVzc2FpICZhbXA7IMOpdmFsdWF0aW9uPC9tYXJrOm1hcmtOYW1lPjxtYXJrOmhv
bGRlciBlbnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm9yZz5BZ2VuY2UgZW4gRnJhbmNlPC9tYXJr
Om9yZz48bWFyazphZGRyPjxtYXJrOnN0cmVldD4xMCBBdmVudWUgUm91c3NlYXV4PC9tYXJrOnN0
cmVldD48bWFyazpjaXR5PlZlcnNhaWxsZXM8L21hcms6Y2l0eT48bWFyazpwYz4zMzA4MTwvbWFy
azpwYz48bWFyazpjYz5GUjwvbWFyazpjYz48L21hcms6YWRkcj48L21hcms6aG9sZGVyPjxtYXJr
OmNvbnRhY3QgdHlwZT0iYWdlbnQiPjxtYXJrOm5hbWU+RnJhbmMgTGVicnVuPC9tYXJrOm5hbWU+
PG1hcms6b3JnPkFnZW5jZSBlbiBGcmFuY2U8L21hcms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3Ry
ZWV0PkF2ZW51ZSBSb3Vzc2VhdXggMTAgPC9tYXJrOnN0cmVldD48bWFyazpjaXR5PlZlcnNhaWxs
ZXM8L21hcms6Y2l0eT48bWFyazpwYz4zMzA4MTwvbWFyazpwYz48bWFyazpjYz5GUjwvbWFyazpj
Yz48L21hcms6YWRkcj48bWFyazp2b2ljZT4rMzMuMTI1NzgxMjUwPC9tYXJrOnZvaWNlPjxtYXJr
OmZheD4rMzMuMTI1NzgxMjUxPC9tYXJrOmZheD48bWFyazplbWFpbD5pbmZvQGFnZW5jZS1lbi1m
cmFuY2UuZnI8L21hcms6ZW1haWw+PC9tYXJrOmNvbnRhY3Q+PG1hcms6bGFiZWw+eG4tLWVzc2Fp
LS0tdmFsdWF0aW9uLWl0YjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tZXNzYWktLXZhbHVh
dGlvbi1ocWI8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLWVzc2FpLWV0LXZhbHVhdGlvbi1q
d2I8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLWVzc2FpLWV0dmFsdWF0aW9uLWl0YjwvbWFy
azpsYWJlbD48bWFyazpsYWJlbD54bi0tZXNzYWktdmFsdWF0aW9uLWduYjwvbWFyazpsYWJlbD48
bWFyazpsYWJlbD54bi0tZXNzYWlldC12YWx1YXRpb24taXRiPC9tYXJrOmxhYmVsPjxtYXJrOmxh
YmVsPnhuLS1lc3NhaWV0dmFsdWF0aW9uLWhxYjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0t
ZXNzYWl2YWx1YXRpb24tZmtiPC9tYXJrOmxhYmVsPjxtYXJrOmdvb2RzQW5kU2VydmljZXM+Z3Vp
dGFyPC9tYXJrOmdvb2RzQW5kU2VydmljZXM+PG1hcms6cmVmTnVtPjEyMzQ8L21hcms6cmVmTnVt
PjxtYXJrOnByb0RhdGU+MjAxMy0wMS0wMVQwMDowMDowMC4wMDBaPC9tYXJrOnByb0RhdGU+PG1h
cms6Y2M+RlI8L21hcms6Y2M+PG1hcms6Y291cnROYW1lPmd1aXRhcmU8L21hcms6Y291cnROYW1l
PjwvbWFyazpjb3VydD48L21hcms6bWFyaz48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8v
d3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJZD0iX2E0YTNhZTUyLTgwODQtNGVlYi04M2M5
LTc1ZTQ1ZDQzMDBhMiI+PGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2Qg
QWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6
U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxk
c2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZlcmVuY2UgVVJJPSIjXzgwYjE0ZjgxLWY4MDQt
NDBiMy04ZGNkLWI5M2E2NWE1NzkxOCI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0
dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAv
eG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRo
bT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZh
bHVlPnpKaDgwMDVSTmtXL3F4YmNHZHUrVXlEaUFaQ1VNRWkwT0xnUW9jZ0FCc1E9PC9kczpEaWdl
c3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48ZHM6UmVmZXJlbmNlIFVSST0iI18wNzdjNzM1OS03YWI2
LTQyNDUtOGJiNi0xOWUyNTdmNmU3MTciPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxn
b3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRy
YW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIw
MDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5CTzloVkJUa3dVbDBxZHhUNTl5
aXpjV3VDN1ZIMjIreGovRDZPZitVbnRZPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+
PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZSBJZD0iXzA2OTE3YzM0LTZiMmMtNDdi
ZS04YzA3LWNmMTJhZDkzZDYxNSI+bnRFbHMwT2h4bEFDL0MxVWZwemhRR2xkNHlXZkxRZTdFdDd1
b3JiY0dRTldOOERGZjBNbVpqUnFmaTZWVzYwM2Fwd3dZZWlaTTdDVwpvRi93REhsMkc2a0d1eTBG
QnoyakhPVnVQdG1RNGZJcVdQU24xZUUxQkZSbHpURDlPRm5VTWxPRW9ONDFxMHdGVzQwdTRnMVd0
bU5YCmpWVFJEY1BmejMwWUxCT29lSUFMUHhJSHEwTkRQRmpSNExTNWtzY2J2eGU4d0h3RWNHeGJq
b0tnU0xUTklNeDVTbkwwNFpYSHd0eGgKMGJ5eWRBanFnMU9ja2JhdEVaQ0U0MHFpZ0kwRmdRb0hm
M0tjVkY3UXEwbTFIdXlNS3lwRUVLSFBmejNWcmw1N24wUFVWU1FJd0VpTgpxaEVVMkxhRy8zQndp
YWw1M29GdVZpcTd3VUZyNzVmR2ZQcm14QT09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5m
byBJZD0iXzA3N2M3MzU5LTdhYjYtNDI0NS04YmI2LTE5ZTI1N2Y2ZTcxNyI+PGRzOlg1MDlEYXRh
PjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRk96Q0NCQ09nQXdJQkFnSWdMckFiZXZvYWU1MnkzZjZD
MnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOaFpjd0RRWUpLb1pJaHZjTgpBUUVMQlFBd2ZERUxNQWtH
QTFVRUJoTUNWVk14UERBNkJnTlZCQW9UTTBsdWRHVnlibVYwSUVOdmNuQnZjbUYwYVc5dUlHWnZj
aUJCCmMzTnBaMjVsWkNCT1lXMWxjeUJoYm1RZ1RuVnRZbVZ5Y3pFdk1DMEdBMVVFQXhNbVNVTkJU
azRnVkhKaFpHVnRZWEpySUVOc1pXRnkKYVc1bmFHOTFjMlVnVUdsc2IzUWdRMEV3SGhjTk1UZ3dN
akk0TURBd01EQXdXaGNOTWpNd016QXhNak0xT1RVNVdqQ0JqekVMTUFrRwpBMVVFQmhNQ1FrVXhJ
REFlQmdOVkJBZ1RGMEp5ZFhOelpXeHpMVU5oY0dsMFlXd2dVbVZuYVc5dU1SRXdEd1lEVlFRSEV3
aENjblZ6CmMyVnNjekVSTUE4R0ExVUVDaE1JUkdWc2IybDBkR1V4T0RBMkJnTlZCQU1UTDBsRFFV
NU9JRlJOUTBnZ1FYVjBhRzl5YVhwbFpDQlUKY21Ga1pXMWhjbXNnVUdsc2IzUWdWbUZzYVdSaGRH
OXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQQp4bHAzS3BZSFgz
V3lBc0ZoU2szTHdXZm5HbHhuVURGcUZaQTNVb3VNWWovWGlnYk1rTmVFWElqbGtST0tUNE9QR2ZS
eC9MQXlSbFFRCmpDTXY0cWhia2NYMXA3YXI2M2ZscTRTWk5WY2wxNWw3aDB1VDU4RnpTZm5sejB1
NXJrSGZKSW1ENDMrbWFQLzhndjM2RlIyN2pXOFIKOXdZNGhrK1dzNElCMGlGU2Q4U1h2MUtyOHcv
Sm1NUVNEa2l1RytSZklpdWJ3US9meTdFa2o1UVdoUFp3K21NeE5LbkhVTHkzeFl6MgpMd1ZmZnRq
d1V1ZWFjdnFOUkNrTVhsQ2xPQURxZlQ4b1Nab2VEWGVoSHZsUHNMQ2VtR0JvVEt1cnNrSVM2OUYw
eVBFSDVnemUwSCtmCjhGUk9zSW9LU3NWUTM0QjRTL2pvRTY3bnBzSlBUZEtzTlBKVHlRSURBUUFC
bzRJQmt6Q0NBWTh3REFZRFZSMFRBUUgvQkFJd0FEQWQKQmdOVkhRNEVGZ1FVb0ZwWTc2cDV5b05E
Ukd0UXB6VnVSODFVV1Ewd2djWUdBMVVkSXdTQnZqQ0J1NEFVdzYwK3B0WVJBRVdBWERwWApTb3B0
M0RFTm5uR2hnWUNrZmpCOE1Rc3dDUVlEVlFRR0V3SlZVekU4TURvR0ExVUVDaE16U1c1MFpYSnVa
WFFnUTI5eWNHOXlZWFJwCmIyNGdabTl5SUVGemMybG5ibVZrSUU1aGJXVnpJR0Z1WkNCT2RXMWla
WEp6TVM4d0xRWURWUVFERXlaSlEwRk9UaUJVY21Ga1pXMWgKY21zZ1EyeGxZWEpwYm1kb2IzVnpa
U0JRYVd4dmRDQkRRWUlnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTgpo
WGt3RGdZRFZSMFBBUUgvQkFRREFnZUFNRFFHQTFVZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5
OWpjbXd1YVdOaGJtNHViM0puCkwzUnRZMmhmY0dsc2IzUXVZM0pzTUZFR0ExVWRJQVJLTUVnd0VB
WU9Ld1lCQkFHQ3lSc0JCWU03REFvd05BWUlLd1lCQlFVSEFnRXcKS0RBbUJnZ3JCZ0VGQlFjQ0FS
WWFhSFIwY0hNNkx5OWpZUzVwWTJGdWJpNXZjbWN2Y0dsc2IzUXdEUVlKS29aSWh2Y05BUUVMQlFB
RApnZ0VCQUF1aloySWNSMkRWcnRhUnJBNTllTllDbDR4Y3NKTXU4RFFDSHYyOGZUZmkvQmlaWTRJ
cjdGOWtGeTk2RDdPWjhvTFk1empmCjRkSHhGd0hQcUg4RGg2Sldzelh1SFcxWmEzWG1sMFBhSHhD
V1JTMFhvbDhXc0hIcE55Z2pNQllmSjBvZFZNODg1VFoxRWw5U2l1RUgKbnluRkJnU21pRmM5OXVR
ZC9ZRFJadUd2L0EwSHl2N3lSOXRrTEVkRDNBMXVOSkJXNFArSEpHcGRLa1lMMVE1clU3K29IVlB0
TUtLSQozaUZrVUVzYk80NUFWZDd2UC9qLzdKdEFaUGI2a29PVjVsWmkySDFSTGNjR3d6ZGV6bmhK
Z2QwTjlvYmIwdm5FNDEvVVNXYWZkV1JaClZHa3dQdXFUaGw3c0N0enJKSDhYWTB4Y3VtK2NmTHgy
RUFJd1VuT2NhYjQ9PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUlu
Zm8+PC9kczpTaWduYXR1cmU+PC9zbWQ6c2lnbmVkTWFyaz4=
-----END ENCODED SMD-----
@@ -1,102 +0,0 @@
Marks: Марк &amp; записи
smdID: 000000731526320367222-65535
U-labels: xn------5cdd5bials4bfv, xn-----6kcc8ahakq0bft, xn---and--3vef9ckanw2cfz, xn---and-43de2cjamu8bfx, xn----7sbb1agajo6afr, xn--and--43de2cjamu8bfx, xn--and-5cdd5bials4bfv, xn--80aaufaim2afp
notBefore: 2018-05-14T17:52:47.222Z
notAfter: 2022-08-18T14:16:55.554Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il81ZWZi
ZWYxMy0zYjRkLTQ4NDctOGRkMi1hMGRkMzMwM2RkMDEiPjxzbWQ6aWQ+MDAwMDAwNzMxNTI2MzIw
MzY3MjIyLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo0Ny4yMjJaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDoxNjo1NS41NTRaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDExNTAzMDY1MzU1MTUwMzA2NTM1NS0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPtCc0LDRgNC6ICZhbXA7INC30LDQv9C40YHQuDwvbWFyazptYXJrTmFtZT48bWFy
azpob2xkZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpvcmc+0JDQs9C10L3RgtGB0YLQstC+
PC9tYXJrOm9yZz48bWFyazphZGRyPjxtYXJrOnN0cmVldD7Qn9GA0L7RgdC/0LXQutGCINCS0LXR
gNC90LDQtNGB0LrQvtCz0L4gMTU8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+0JzQvtGB0LrQstCw
PC9tYXJrOmNpdHk+PG1hcms6cGM+MTE3NDg1PC9tYXJrOnBjPjxtYXJrOmNjPlJVPC9tYXJrOmNj
PjwvbWFyazphZGRyPjwvbWFyazpob2xkZXI+PG1hcms6Y29udGFjdCB0eXBlPSJhZ2VudCI+PG1h
cms6bmFtZT7QndCw0YLQsNC70YzRjyDQkNC90YLQvtC90L7QstCwPC9tYXJrOm5hbWU+PG1hcms6
b3JnPtCQ0LPQtdC90YLRgdGC0LLQvjwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+
0J/RgNC+0YHQv9C10LrRgiDQktC10YDQvdCw0LTRgdC60L7Qs9C+IDE1PC9tYXJrOnN0cmVldD48
bWFyazpjaXR5PtCc0L7RgdC60LLQsDwvbWFyazpjaXR5PjxtYXJrOnBjPjExNzQ4NTwvbWFyazpw
Yz48bWFyazpjYz5SVTwvbWFyazpjYz48L21hcms6YWRkcj48bWFyazp2b2ljZT4rNy45MTg4MjIx
Njc0PC9tYXJrOnZvaWNlPjxtYXJrOmZheD4rNy45MTg4MjIxNjczPC9tYXJrOmZheD48bWFyazpl
bWFpbD5pbmZvQGFnZW5jeS5ydTwvbWFyazplbWFpbD48L21hcms6Y29udGFjdD48bWFyazpsYWJl
bD54bi0tLS0tLTVjZGQ1YmlhbHM0YmZ2PC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS02
a2NjOGFoYWtxMGJmdDwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tLWFuZC0tM3ZlZjlja2Fu
dzJjZno8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS1hbmQtNDNkZTJjamFtdThiZng8L21h
cms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS0tN3NiYjFhZ2FqbzZhZnI8L21hcms6bGFiZWw+PG1h
cms6bGFiZWw+eG4tLWFuZC0tNDNkZTJjamFtdThiZng8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+
eG4tLWFuZC01Y2RkNWJpYWxzNGJmdjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tODBhYXVm
YWltMmFmcDwvbWFyazpsYWJlbD48bWFyazpnb29kc0FuZFNlcnZpY2VzPtCz0LjRgtCw0YDQsCA8
L21hcms6Z29vZHNBbmRTZXJ2aWNlcz48bWFyazpyZWZOdW0+MTIzNDwvbWFyazpyZWZOdW0+PG1h
cms6cHJvRGF0ZT4yMDEzLTAxLTAxVDAwOjAwOjAwLjAwMFo8L21hcms6cHJvRGF0ZT48bWFyazpj
Yz5VUzwvbWFyazpjYz48bWFyazpjb3VydE5hbWU+SG92ZTwvbWFyazpjb3VydE5hbWU+PC9tYXJr
OmNvdXJ0PjwvbWFyazptYXJrPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMu
b3JnLzIwMDAvMDkveG1sZHNpZyMiIElkPSJfZmQyNjk0MDktMGVhMy00ODJiLWIyMDktMDNlZmFm
MTVhMTQ3Ij48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0
aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1
cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9y
ZSNyc2Etc2hhMjU2Ii8+PGRzOlJlZmVyZW5jZSBVUkk9IiNfNWVmYmVmMTMtM2I0ZC00ODQ3LThk
ZDItYTBkZDMzMDNkZDAxIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0i
aHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48
ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhj
LWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRw
Oi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+bEpl
RHVaWDVIalB1VGZZRm9iOXMxdXNTVU96d2cvUGVaaDc4cjQ1V1Bjaz08L2RzOkRpZ2VzdFZhbHVl
PjwvZHM6UmVmZXJlbmNlPjxkczpSZWZlcmVuY2UgVVJJPSIjXzM2ZmY4ODQ5LTAzMTQtNDgwZC1i
YTg4LWFiNWI4NGU2OGU2MiI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09
Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jt
cz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94
bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPlJGWmZtb3ZVeW9qaDJTSU0rQXI0Snl6bkgw
MGpPMkI0aGlNWnNyVFhtODA9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNp
Z25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlIElkPSJfNTRiMmQ4MDctZGZmNC00MDY5LTg2NWQt
NWU1YjdiOGQ5OGVmIj5GK1o0V3RZcjlCYk5WWHJlViswSzBpWDVQbnFPWjg3OHRhU0xDNjdzQ1ht
OWFINVRDNFhHTnBxVjlUK2RrbU9tVUNJQ0lmTE5PVlZxCkhWMlNZNTR4T2U2NFNUaEtKK3pWOXJo
RUVBK1NvZVFLSHVib3VMY0dMK3BYUmpWMVBETnBWeHdrUE45QnhGT21HbEh6anVxTHhtcXQKSCtT
M1J4OFdmT0tXc3lURTdwMTJhd0g2dFVoYXBqV1A3U29PVTVxOExLUU9hdWJaaW4vYklPUHN1RTcy
bmZIOTRKZnQ5REdLb0doUgpSaE81bVRUcUdSQlJIQjFqbU5sK1hmUGdSNHM0OGc0Uk01WTEydnIx
NmRFMk14RDV4TEczZUVlVk9zS1p1OWpnVytPMXd3djZxbDZlClBYdFVyU0o4dTVKWjYrem5RNmdI
bm5oMVp6V0xYVGZYYlhYa293PT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZvIElkPSJf
MzZmZjg4NDktMDMxNC00ODBkLWJhODgtYWI1Yjg0ZTY4ZTYyIj48ZHM6WDUwOURhdGE+PGRzOlg1
MDlDZXJ0aWZpY2F0ZT5NSUlGT3pDQ0JDT2dBd0lCQWdJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24z
cDdYSm0wVDAyRm9neEtDZk5oWmN3RFFZSktvWklodmNOCkFRRUxCUUF3ZkRFTE1Ba0dBMVVFQmhN
Q1ZWTXhQREE2QmdOVkJBb1RNMGx1ZEdWeWJtVjBJRU52Y25CdmNtRjBhVzl1SUdadmNpQkIKYzNO
cFoyNWxaQ0JPWVcxbGN5QmhibVFnVG5WdFltVnljekV2TUMwR0ExVUVBeE1tU1VOQlRrNGdWSEpo
WkdWdFlYSnJJRU5zWldGeQphVzVuYUc5MWMyVWdVR2xzYjNRZ1EwRXdIaGNOTVRnd01qSTRNREF3
TURBd1doY05Nak13TXpBeE1qTTFPVFU1V2pDQmp6RUxNQWtHCkExVUVCaE1DUWtVeElEQWVCZ05W
QkFnVEYwSnlkWE56Wld4ekxVTmhjR2wwWVd3Z1VtVm5hVzl1TVJFd0R3WURWUVFIRXdoQ2NuVnoK
YzJWc2N6RVJNQThHQTFVRUNoTUlSR1ZzYjJsMGRHVXhPREEyQmdOVkJBTVRMMGxEUVU1T0lGUk5R
MGdnUVhWMGFHOXlhWHBsWkNCVQpjbUZrWlcxaGNtc2dVR2xzYjNRZ1ZtRnNhV1JoZEc5eU1JSUJJ
akFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnhscDNLcFlIWDNXeUFzRmhT
azNMd1dmbkdseG5VREZxRlpBM1VvdU1Zai9YaWdiTWtOZUVYSWpsa1JPS1Q0T1BHZlJ4L0xBeVJs
UVEKakNNdjRxaGJrY1gxcDdhcjYzZmxxNFNaTlZjbDE1bDdoMHVUNThGelNmbmx6MHU1cmtIZkpJ
bUQ0MyttYVAvOGd2MzZGUjI3alc4Ugo5d1k0aGsrV3M0SUIwaUZTZDhTWHYxS3I4dy9KbU1RU0Rr
aXVHK1JmSWl1YndRL2Z5N0VrajVRV2hQWncrbU14TktuSFVMeTN4WXoyCkx3VmZmdGp3VXVlYWN2
cU5SQ2tNWGxDbE9BRHFmVDhvU1pvZURYZWhIdmxQc0xDZW1HQm9US3Vyc2tJUzY5RjB5UEVINWd6
ZTBIK2YKOEZST3NJb0tTc1ZRMzRCNFMvam9FNjducHNKUFRkS3NOUEpUeVFJREFRQUJvNElCa3pD
Q0FZOHdEQVlEVlIwVEFRSC9CQUl3QURBZApCZ05WSFE0RUZnUVVvRnBZNzZwNXlvTkRSR3RRcHpW
dVI4MVVXUTB3Z2NZR0ExVWRJd1NCdmpDQnU0QVV3NjArcHRZUkFFV0FYRHBYClNvcHQzREVObm5H
aGdZQ2tmakI4TVFzd0NRWURWUVFHRXdKVlV6RThNRG9HQTFVRUNoTXpTVzUwWlhKdVpYUWdRMjl5
Y0c5eVlYUnAKYjI0Z1ptOXlJRUZ6YzJsbmJtVmtJRTVoYldWeklHRnVaQ0JPZFcxaVpYSnpNUzh3
TFFZRFZRUURFeVpKUTBGT1RpQlVjbUZrWlcxaApjbXNnUTJ4bFlYSnBibWRvYjNWelpTQlFhV3h2
ZENCRFFZSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOCmhYa3dEZ1lE
VlIwUEFRSC9CQVFEQWdlQU1EUUdBMVVkSHdRdE1Dc3dLYUFub0NXR0kyaDBkSEE2THk5amNtd3Vh
V05oYm00dWIzSm4KTDNSdFkyaGZjR2xzYjNRdVkzSnNNRkVHQTFVZElBUktNRWd3RUFZT0t3WUJC
QUdDeVJzQkJZTTdEQW93TkFZSUt3WUJCUVVIQWdFdwpLREFtQmdnckJnRUZCUWNDQVJZYWFIUjBj
SE02THk5allTNXBZMkZ1Ymk1dmNtY3ZjR2xzYjNRd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJB
QXVqWjJJY1IyRFZydGFSckE1OWVOWUNsNHhjc0pNdThEUUNIdjI4ZlRmaS9CaVpZNElyN0Y5a0Z5
OTZEN09aOG9MWTV6amYKNGRIeEZ3SFBxSDhEaDZKV3N6WHVIVzFaYTNYbWwwUGFIeENXUlMwWG9s
OFdzSEhwTnlnak1CWWZKMG9kVk04ODVUWjFFbDlTaXVFSApueW5GQmdTbWlGYzk5dVFkL1lEUlp1
R3YvQTBIeXY3eVI5dGtMRWREM0ExdU5KQlc0UCtISkdwZEtrWUwxUTVyVTcrb0hWUHRNS0tJCjNp
RmtVRXNiTzQ1QVZkN3ZQL2ovN0p0QVpQYjZrb09WNWxaaTJIMVJMY2NHd3pkZXpuaEpnZDBOOW9i
YjB2bkU0MS9VU1dhZmRXUloKVkdrd1B1cVRobDdzQ3R6ckpIOFhZMHhjdW0rY2ZMeDJFQUl3VW5P
Y2FiND08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2Rz
OlNpZ25hdHVyZT48L3NtZDpzaWduZWRNYXJrPg==
-----END ENCODED SMD-----
@@ -1,95 +0,0 @@
Marks: الاختبار &amp; لتقييم
smdID: 000000911526320398360-65535
U-labels: xn------nzeaagpf7azb2ppajr3fa, xn-----btdaafne4a7azpoaiq8ea, xn----ymcaaeld1a4a6onahp3ea, xn--mgbaadjcy1a8mmago8da
notBefore: 2018-05-14T17:53:18.360Z
notAfter: 2022-08-21T08:59:34.305Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il9mN2Zm
YTA1ZC1lZTkwLTQ3OWMtOTkzNC1hZmI2MWY5MTMxNWUiPjxzbWQ6aWQ+MDAwMDAwOTExNTI2MzIw
Mzk4MzYwLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzoxOC4zNjBaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODo1OTozNC4zMDVaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDIxNTAzMzA1NTg0MTUwMzMwNTU4NC0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPtin2YTYp9iu2KrYqNin2LEgJmFtcDsg2YTYqtmC2YrZitmFPC9tYXJrOm1hcmtO
YW1lPjxtYXJrOmhvbGRlciBlbnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm5hbWU+2YXZh9mG2K/Y
syDYp9mE2YXYudmE2YjZhdin2KrZitipPC9tYXJrOm5hbWU+PG1hcms6b3JnPtin2K7Yqtio2KfY
sTwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+2KzYudmB2LEg2KfYqNmGINiz2YrZ
htin2KEgNzU8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+2YXZg9mG2KfYszwvbWFyazpjaXR5Pjxt
YXJrOnBjPjI5MDA8L21hcms6cGM+PG1hcms6Y2M+TUE8L21hcms6Y2M+PC9tYXJrOmFkZHI+PG1h
cms6dm9pY2U+KzIxMi41MjI1MzkwNDA8L21hcms6dm9pY2U+PG1hcms6ZmF4PisyMTIuNTIyNTM5
MDQxPC9tYXJrOmZheD48bWFyazplbWFpbD5pbmZvQGV4YW1wbGUuZXhhbXBsZTwvbWFyazplbWFp
bD48L21hcms6aG9sZGVyPjxtYXJrOmxhYmVsPnhuLS0tLS0tbnplYWFncGY3YXpiMnBwYWpyM2Zh
PC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS1idGRhYWZuZTRhN2F6cG9haXE4ZWE8L21h
cms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS0teW1jYWFlbGQxYTRhNm9uYWhwM2VhPC9tYXJrOmxh
YmVsPjxtYXJrOmxhYmVsPnhuLS1tZ2JhYWRqY3kxYThtbWFnbzhkYTwvbWFyazpsYWJlbD48bWFy
azpnb29kc0FuZFNlcnZpY2VzPti62YrYqtin2LE8L21hcms6Z29vZHNBbmRTZXJ2aWNlcz48bWFy
azpyZWZOdW0+MTk4PC9tYXJrOnJlZk51bT48bWFyazpwcm9EYXRlPjIwMTUtMDktMTVUMDA6MDA6
MDAuMDAwWjwvbWFyazpwcm9EYXRlPjxtYXJrOmNjPk1BPC9tYXJrOmNjPjxtYXJrOmNvdXJ0TmFt
ZT7Yp9mE2K/Yp9ixINin2YTYqNmK2LbYp9ihPC9tYXJrOmNvdXJ0TmFtZT48L21hcms6Y291cnQ+
PC9tYXJrOm1hcms+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAw
MC8wOS94bWxkc2lnIyIgSWQ9Il9jZjNkMjI3Yy1kNmU4LTQzZGEtYmM4NC02MGViNzRiOWQ5YjUi
PjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0
cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhv
ZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1z
aGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI19mN2ZmYTA1ZC1lZTkwLTQ3OWMtOTkzNC1hZmI2
MWY5MTMxNWUiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8v
d3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFu
c2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMi
Lz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cu
dzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT53UTFJeXFUMTdk
MStoTkg3aHBKUVQxUVRzS05QWHNUaC85TVJVb0E4a09nPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpS
ZWZlcmVuY2U+PGRzOlJlZmVyZW5jZSBVUkk9IiNfMjM4MDNmMTUtZWZiOS00NTM5LTg3ZjYtZGFj
MDNhYjg3NTZlIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDov
L3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpE
aWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNz
aGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+OGh2S3BCNkVLeEZMbWU5QThKMnJqVmVmU0FBcGpZcmdh
Y29ORm4wNnlFbz08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5m
bz48ZHM6U2lnbmF0dXJlVmFsdWUgSWQ9Il8zZWZkNjM4MS1hYTAxLTQ3ZDYtODZkNy0wNzIzYTJm
MDYxYTciPmd3NVA3OFY5Sm9acmFBWk5kMEpmVEo2d2s3Qnp0YXAyREJmSzl3cng4YStJT3c4MVNl
a3ZBZU9MTU5aRE84LzFBY0xjVjdZVXRxRDkKMG4yUC9BYzdiOG9FdmdMcHgyTlA5eWNLNHNVekJi
WUZRb2Y3VHIvZHIzZmRFN3J1Ymx1cStaRWR0QlFuck9KUk9rakZsMkxOU01JNQp6Nlk2NDZsVnVx
dy9IQWpPalB1ZithUVQ5S3VGTkFFMi9mTTg0cWFDNkx1ZE9EWmpHVlkreWRzUHo3eUlXa1ZWaUNl
OGtMV1h3cWYzCktXZWwyQ0dYSjg3c3FJb3dtV1EvQ3hKWnJ3SXRKRk43djhLNmlWTG1Tam1zQldq
QlE3UHNHaHR3bkk1ck1yaFVycXFkRE9JUzNGUmoKdlBCSDJlRktna0pEK1E5ZTFPaEtOQlZySGFU
WHZSTkRkUXlOdmc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8gSWQ9Il8yMzgwM2Yx
NS1lZmI5LTQ1MzktODdmNi1kYWMwM2FiODc1NmUiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRp
ZmljYXRlPk1JSUZPekNDQkNPZ0F3SUJBZ0lnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBU
MDJGb2d4S0NmTmhaY3dEUVlKS29aSWh2Y04KQVFFTEJRQXdmREVMTUFrR0ExVUVCaE1DVlZNeFBE
QTZCZ05WQkFvVE0wbHVkR1Z5Ym1WMElFTnZjbkJ2Y21GMGFXOXVJR1p2Y2lCQgpjM05wWjI1bFpD
Qk9ZVzFsY3lCaGJtUWdUblZ0WW1WeWN6RXZNQzBHQTFVRUF4TW1TVU5CVGs0Z1ZISmhaR1Z0WVhK
cklFTnNaV0Z5CmFXNW5hRzkxYzJVZ1VHbHNiM1FnUTBFd0hoY05NVGd3TWpJNE1EQXdNREF3V2hj
Tk1qTXdNekF4TWpNMU9UVTVXakNCanpFTE1Ba0cKQTFVRUJoTUNRa1V4SURBZUJnTlZCQWdURjBK
eWRYTnpaV3h6TFVOaGNHbDBZV3dnVW1WbmFXOXVNUkV3RHdZRFZRUUhFd2hDY25WegpjMlZzY3pF
Uk1BOEdBMVVFQ2hNSVJHVnNiMmwwZEdVeE9EQTJCZ05WQkFNVEwwbERRVTVPSUZSTlEwZ2dRWFYw
YUc5eWFYcGxaQ0JVCmNtRmtaVzFoY21zZ1VHbHNiM1FnVm1Gc2FXUmhkRzl5TUlJQklqQU5CZ2tx
aGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEKeGxwM0twWUhYM1d5QXNGaFNrM0x3V2Zu
R2x4blVERnFGWkEzVW91TVlqL1hpZ2JNa05lRVhJamxrUk9LVDRPUEdmUngvTEF5UmxRUQpqQ012
NHFoYmtjWDFwN2FyNjNmbHE0U1pOVmNsMTVsN2gwdVQ1OEZ6U2ZubHowdTVya0hmSkltRDQzK21h
UC84Z3YzNkZSMjdqVzhSCjl3WTRoaytXczRJQjBpRlNkOFNYdjFLcjh3L0ptTVFTRGtpdUcrUmZJ
aXVid1EvZnk3RWtqNVFXaFBadyttTXhOS25IVUx5M3hZejIKTHdWZmZ0andVdWVhY3ZxTlJDa01Y
bENsT0FEcWZUOG9TWm9lRFhlaEh2bFBzTENlbUdCb1RLdXJza0lTNjlGMHlQRUg1Z3plMEgrZgo4
RlJPc0lvS1NzVlEzNEI0Uy9qb0U2N25wc0pQVGRLc05QSlR5UUlEQVFBQm80SUJrekNDQVk4d0RB
WURWUjBUQVFIL0JBSXdBREFkCkJnTlZIUTRFRmdRVW9GcFk3NnA1eW9ORFJHdFFwelZ1UjgxVVdR
MHdnY1lHQTFVZEl3U0J2akNCdTRBVXc2MCtwdFlSQUVXQVhEcFgKU29wdDNERU5ubkdoZ1lDa2Zq
QjhNUXN3Q1FZRFZRUUdFd0pWVXpFOE1Eb0dBMVVFQ2hNelNXNTBaWEp1WlhRZ1EyOXljRzl5WVhS
cApiMjRnWm05eUlFRnpjMmxuYm1Wa0lFNWhiV1Z6SUdGdVpDQk9kVzFpWlhKek1TOHdMUVlEVlFR
REV5WkpRMEZPVGlCVWNtRmtaVzFoCmNtc2dRMnhsWVhKcGJtZG9iM1Z6WlNCUWFXeHZkQ0JEUVlJ
Z0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9neEtDZk4KaFhrd0RnWURWUjBQQVFI
L0JBUURBZ2VBTURRR0ExVWRId1F0TUNzd0thQW5vQ1dHSTJoMGRIQTZMeTlqY213dWFXTmhibTR1
YjNKbgpMM1J0WTJoZmNHbHNiM1F1WTNKc01GRUdBMVVkSUFSS01FZ3dFQVlPS3dZQkJBR0N5UnNC
QllNN0RBb3dOQVlJS3dZQkJRVUhBZ0V3CktEQW1CZ2dyQmdFRkJRY0NBUllhYUhSMGNITTZMeTlq
WVM1cFkyRnViaTV2Y21jdmNHbHNiM1F3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFBdWpaMklj
UjJEVnJ0YVJyQTU5ZU5ZQ2w0eGNzSk11OERRQ0h2MjhmVGZpL0JpWlk0SXI3RjlrRnk5NkQ3T1o4
b0xZNXpqZgo0ZEh4RndIUHFIOERoNkpXc3pYdUhXMVphM1htbDBQYUh4Q1dSUzBYb2w4V3NISHBO
eWdqTUJZZkowb2RWTTg4NVRaMUVsOVNpdUVICm55bkZCZ1NtaUZjOTl1UWQvWURSWnVHdi9BMEh5
djd5Ujl0a0xFZEQzQTF1TkpCVzRQK0hKR3BkS2tZTDFRNXJVNytvSFZQdE1LS0kKM2lGa1VFc2JP
NDVBVmQ3dlAvai83SnRBWlBiNmtvT1Y1bFppMkgxUkxjY0d3emRlem5oSmdkME45b2JiMHZuRTQx
L1VTV2FmZFdSWgpWR2t3UHVxVGhsN3NDdHpySkg4WFkweGN1bStjZkx4MkVBSXdVbk9jYWI0PTwv
ZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0
dXJlPjwvc21kOnNpZ25lZE1hcms+
-----END ENCODED SMD-----
@@ -1,93 +0,0 @@
Marks: 证明&amp;标志
smdID: 000000701526320361385-65535
U-labels: xn----z33bn7p06br59e, xn--and-qy3f87yx4cc34g, xn--m6t41lkubhz2e
notBefore: 2018-05-14T17:52:41.385Z
notAfter: 2022-08-21T08:12:01.925Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8yNDI5
NTA5NC0zN2U3LTQwOWQtODM1OS01ZTI1ZjFhNzkxYjQiPjxzbWQ6aWQ+MDAwMDAwNzAxNTI2MzIw
MzYxMzg1LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo0MS4zODVaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODoxMjowMS45MjVaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDUxNTAzMDY0NjA2MTUwMzA2NDYwNi0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPuivgeaYjiZhbXA75qCH5b+XPC9tYXJrOm1hcmtOYW1lPjxtYXJrOmhvbGRlciBl
bnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm5hbWU+5p2O5bCP5pa5PC9tYXJrOm5hbWU+PG1hcms6
b3JnPua1i+ivlTwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+6aaZ5riv5Lic6Lev
NuWPt++8jDXlj7fmpbzvvIw45Y+35a6kIDwvbWFyazpzdHJlZXQ+PG1hcms6Y2l0eT7pnZLlspvl
uII8L21hcms6Y2l0eT48bWFyazpwYz4xMDAwPC9tYXJrOnBjPjxtYXJrOmNjPkNOPC9tYXJrOmNj
PjwvbWFyazphZGRyPjxtYXJrOnZvaWNlPis4Ni4xMDg0NjU3MTczPC9tYXJrOnZvaWNlPjxtYXJr
OmZheD4rODYuMTA4NDY1NzE3MzwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BleGFtcGxlLmV4
YW1wbGU8L21hcms6ZW1haWw+PC9tYXJrOmhvbGRlcj48bWFyazpsYWJlbD54bi0tLS16MzNibjdw
MDZicjU5ZTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tYW5kLXF5M2Y4N3l4NGNjMzRnPC9t
YXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1tNnQ0MWxrdWJoejJlPC9tYXJrOmxhYmVsPjxtYXJr
Omdvb2RzQW5kU2VydmljZXM+IOWQieS7ljwvbWFyazpnb29kc0FuZFNlcnZpY2VzPjxtYXJrOnJl
Zk51bT4xMjM0PC9tYXJrOnJlZk51bT48bWFyazpwcm9EYXRlPjIwMTMtMDEtMDFUMDA6MDA6MDAu
MDAwWjwvbWFyazpwcm9EYXRlPjxtYXJrOmNjPlVTPC9tYXJrOmNjPjxtYXJrOmNvdXJ0TmFtZT5U
ZXN0IENvdXJ0PC9tYXJrOmNvdXJ0TmFtZT48L21hcms6Y291cnQ+PC9tYXJrOm1hcms+PGRzOlNp
Z25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgSWQ9
Il9hM2YzMjFiOC05OTQ3LTQ3OTItOWM4OS03ZTk5OTNkYTczNmIiPjxkczpTaWduZWRJbmZvPjxk
czpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAw
MS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6
Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJl
bmNlIFVSST0iI18yNDI5NTA5NC0zN2U3LTQwOWQtODM1OS01ZTI1ZjFhNzkxYjQiPjxkczpUcmFu
c2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5
L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJo
dHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+
PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1s
ZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT50Z1MwY293eFdGdTk4dVcrSjNydjd4WndXZVRC
cDdja0lsaUJodUtNY20wPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PGRzOlJlZmVy
ZW5jZSBVUkk9IiNfNTQ1MDk4N2YtNjYwYS00OTE3LWI3NTktM2ZhNDczYjhmNTBiIj48ZHM6VHJh
bnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8x
MC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3Jp
dGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0
VmFsdWU+UEZKUEN3ZGEraE9YYXl1ZStjbEM5VjYwaFNUS3Q1cDdNRGRzZzcram1Saz08L2RzOkRp
Z2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFs
dWUgSWQ9Il81ZjE3M2ZmNy1hY2JmLTRiM2MtOGUxYy1lNjNlYTFlODZjNDAiPlJKMWQ4L0V3Znd6
cFJPYytsNTVVY0lKb2wwUEZIZnBuVEZDeXE4Y3NkVng0TUJjN1AwNXVuazlSbU5wVVF0ejJTekQ3
NDArUWdGWnIKc2VUdTI4aWFqQTBNYnpDY2N3NThERlY0MkhBUkJMYjFJaVZnRHBBRWVtbVlRd3VO
eFpjQzE3eHg3QkIzeXhrTXd0TDNnSnBmQkd3TApYMEdTamRBQjRSWkVVMDgrQnl5ajdmMGErdkFB
NmZHdGU2MU1sUGhpdElic2JKMEZRUkVxSk1Mb28xTnRLSEM1ekJveENEc3dVQnFYClhmeDduamgy
UmFRWGRTNmt0bjdNcW5PQko1eFRmTTJ4a2V0d2R3emkzY1FlN2ZNOXkvQy8wbytaU1VZOWRucmh6
cUc5N2ZBL0R4UDgKY09Lekx3YTlrclVTOERXWVhQc1hUdTJjek5XNUdwcENrWlJPWWc9PTwvZHM6
U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8gSWQ9Il81NDUwOTg3Zi02NjBhLTQ5MTctYjc1OS0z
ZmE0NzNiOGY1MGIiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUZPekNDQkNP
Z0F3SUJBZ0lnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTmhaY3dEUVlK
S29aSWh2Y04KQVFFTEJRQXdmREVMTUFrR0ExVUVCaE1DVlZNeFBEQTZCZ05WQkFvVE0wbHVkR1Z5
Ym1WMElFTnZjbkJ2Y21GMGFXOXVJR1p2Y2lCQgpjM05wWjI1bFpDQk9ZVzFsY3lCaGJtUWdUblZ0
WW1WeWN6RXZNQzBHQTFVRUF4TW1TVU5CVGs0Z1ZISmhaR1Z0WVhKcklFTnNaV0Z5CmFXNW5hRzkx
YzJVZ1VHbHNiM1FnUTBFd0hoY05NVGd3TWpJNE1EQXdNREF3V2hjTk1qTXdNekF4TWpNMU9UVTVX
akNCanpFTE1Ba0cKQTFVRUJoTUNRa1V4SURBZUJnTlZCQWdURjBKeWRYTnpaV3h6TFVOaGNHbDBZ
V3dnVW1WbmFXOXVNUkV3RHdZRFZRUUhFd2hDY25WegpjMlZzY3pFUk1BOEdBMVVFQ2hNSVJHVnNi
MmwwZEdVeE9EQTJCZ05WQkFNVEwwbERRVTVPSUZSTlEwZ2dRWFYwYUc5eWFYcGxaQ0JVCmNtRmta
VzFoY21zZ1VHbHNiM1FnVm1Gc2FXUmhkRzl5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FR
OEFNSUlCQ2dLQ0FRRUEKeGxwM0twWUhYM1d5QXNGaFNrM0x3V2ZuR2x4blVERnFGWkEzVW91TVlq
L1hpZ2JNa05lRVhJamxrUk9LVDRPUEdmUngvTEF5UmxRUQpqQ012NHFoYmtjWDFwN2FyNjNmbHE0
U1pOVmNsMTVsN2gwdVQ1OEZ6U2ZubHowdTVya0hmSkltRDQzK21hUC84Z3YzNkZSMjdqVzhSCjl3
WTRoaytXczRJQjBpRlNkOFNYdjFLcjh3L0ptTVFTRGtpdUcrUmZJaXVid1EvZnk3RWtqNVFXaFBa
dyttTXhOS25IVUx5M3hZejIKTHdWZmZ0andVdWVhY3ZxTlJDa01YbENsT0FEcWZUOG9TWm9lRFhl
aEh2bFBzTENlbUdCb1RLdXJza0lTNjlGMHlQRUg1Z3plMEgrZgo4RlJPc0lvS1NzVlEzNEI0Uy9q
b0U2N25wc0pQVGRLc05QSlR5UUlEQVFBQm80SUJrekNDQVk4d0RBWURWUjBUQVFIL0JBSXdBREFk
CkJnTlZIUTRFRmdRVW9GcFk3NnA1eW9ORFJHdFFwelZ1UjgxVVdRMHdnY1lHQTFVZEl3U0J2akNC
dTRBVXc2MCtwdFlSQUVXQVhEcFgKU29wdDNERU5ubkdoZ1lDa2ZqQjhNUXN3Q1FZRFZRUUdFd0pW
VXpFOE1Eb0dBMVVFQ2hNelNXNTBaWEp1WlhRZ1EyOXljRzl5WVhScApiMjRnWm05eUlFRnpjMmxu
Ym1Wa0lFNWhiV1Z6SUdGdVpDQk9kVzFpWlhKek1TOHdMUVlEVlFRREV5WkpRMEZPVGlCVWNtRmta
VzFoCmNtc2dRMnhsWVhKcGJtZG9iM1Z6WlNCUWFXeHZkQ0JEUVlJZ0xyQWJldm9hZTUyeTNmNkMy
dEIwU24zcDdYSm0wVDAyRm9neEtDZk4KaFhrd0RnWURWUjBQQVFIL0JBUURBZ2VBTURRR0ExVWRI
d1F0TUNzd0thQW5vQ1dHSTJoMGRIQTZMeTlqY213dWFXTmhibTR1YjNKbgpMM1J0WTJoZmNHbHNi
M1F1WTNKc01GRUdBMVVkSUFSS01FZ3dFQVlPS3dZQkJBR0N5UnNCQllNN0RBb3dOQVlJS3dZQkJR
VUhBZ0V3CktEQW1CZ2dyQmdFRkJRY0NBUllhYUhSMGNITTZMeTlqWVM1cFkyRnViaTV2Y21jdmNH
bHNiM1F3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFBdWpaMkljUjJEVnJ0YVJyQTU5ZU5ZQ2w0
eGNzSk11OERRQ0h2MjhmVGZpL0JpWlk0SXI3RjlrRnk5NkQ3T1o4b0xZNXpqZgo0ZEh4RndIUHFI
OERoNkpXc3pYdUhXMVphM1htbDBQYUh4Q1dSUzBYb2w4V3NISHBOeWdqTUJZZkowb2RWTTg4NVRa
MUVsOVNpdUVICm55bkZCZ1NtaUZjOTl1UWQvWURSWnVHdi9BMEh5djd5Ujl0a0xFZEQzQTF1TkpC
VzRQK0hKR3BkS2tZTDFRNXJVNytvSFZQdE1LS0kKM2lGa1VFc2JPNDVBVmQ3dlAvai83SnRBWlBi
NmtvT1Y1bFppMkgxUkxjY0d3emRlem5oSmdkME45b2JiMHZuRTQxL1VTV2FmZFdSWgpWR2t3UHVx
VGhsN3NDdHpySkg4WFkweGN1bStjZkx4MkVBSXdVbk9jYWI0PTwvZHM6WDUwOUNlcnRpZmljYXRl
PjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjwvc21kOnNpZ25lZE1h
cms+
-----END ENCODED SMD-----
@@ -1,96 +0,0 @@
Marks: Test &amp; Validate
smdID: 000000501526320343199-65535
U-labels: test---validate, test--validate, test-and-validate, test-andvalidate, test-validate, testand-validate, testandvalidate, testvalidate
notBefore: 2018-05-14T17:52:23.199Z
notAfter: 2022-08-21T08:12:19.525Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il81NmY5
ZjZiMC1kZTAxLTQyYzctYTRlNS1mNTdiZmQ5M2Q5NDQiPjxzbWQ6aWQ+MDAwMDAwNTAxNTI2MzIw
MzQzMTk5LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MjoyMy4xOTlaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODoxMjoxOS41MjVaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxMzYxNTAzMDU2NDc0MTUwMzA1NjQ3NC0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPlRlc3QgJmFtcDsgVmFsaWRhdGU8L21hcms6bWFya05hbWU+PG1hcms6aG9sZGVy
IGVudGl0bGVtZW50PSJvd25lciI+PG1hcms6bmFtZT5GcmFuayBXaGl0ZTwvbWFyazpuYW1lPjxt
YXJrOm9yZz5UZXN0IE9yZ2FuaXphdGlvbjwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJl
ZXQ+V2VzdCBBcnF1ZXMgQXZlbnVlIDEwMSA8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+U3Vubnl2
YWxlPC9tYXJrOmNpdHk+PG1hcms6c3A+Q0E8L21hcms6c3A+PG1hcms6cGM+MTAwMjMtMzI0MTwv
bWFyazpwYz48bWFyazpjYz5VUzwvbWFyazpjYz48L21hcms6YWRkcj48bWFyazp2b2ljZT4rMS4z
MDE0NTU2NjAwPC9tYXJrOnZvaWNlPjxtYXJrOmZheD4rMS4zMDE0NTU2NjAxPC9tYXJrOmZheD48
bWFyazplbWFpbD5pbmZvQGV4YW1wbGUuZXhhbXBsZTwvbWFyazplbWFpbD48L21hcms6aG9sZGVy
PjxtYXJrOmxhYmVsPnRlc3QtLS12YWxpZGF0ZTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD50ZXN0
LS12YWxpZGF0ZTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD50ZXN0LWFuZC12YWxpZGF0ZTwvbWFy
azpsYWJlbD48bWFyazpsYWJlbD50ZXN0LWFuZHZhbGlkYXRlPC9tYXJrOmxhYmVsPjxtYXJrOmxh
YmVsPnRlc3QtdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdGFuZC12YWxpZGF0
ZTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD50ZXN0YW5kdmFsaWRhdGU8L21hcms6bGFiZWw+PG1h
cms6bGFiZWw+dGVzdHZhbGlkYXRlPC9tYXJrOmxhYmVsPjxtYXJrOmdvb2RzQW5kU2VydmljZXM+
Z29sZDwvbWFyazpnb29kc0FuZFNlcnZpY2VzPjxtYXJrOnJlZk51bT4xMjM0PC9tYXJrOnJlZk51
bT48bWFyazpwcm9EYXRlPjIwMTMtMDEtMDFUMDA6MDA6MDAuMDAwWjwvbWFyazpwcm9EYXRlPjxt
YXJrOmNjPlVTPC9tYXJrOmNjPjxtYXJrOmNvdXJ0TmFtZT5Ib3ZlPC9tYXJrOmNvdXJ0TmFtZT48
L21hcms6Y291cnQ+PC9tYXJrOm1hcms+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3
dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgSWQ9Il9mNTdiOTJiYi05ZjMzLTQ2MDAtODAwMi0z
ZmIyODY5MmFlOGYiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFs
Z29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNp
Z25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNp
Zy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI181NmY5ZjZiMC1kZTAxLTQy
YzctYTRlNS1mNTdiZmQ5M2Q5NDQiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3Jp
dGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVy
ZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3ht
bC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09
Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1
ZT5Qby90dDBlVzZzdVpBTjIyaWxocHc4YjZUdVVuNzJ1R0NGVFdnUm1OM21ZPTwvZHM6RGlnZXN0
VmFsdWU+PC9kczpSZWZlcmVuY2U+PGRzOlJlZmVyZW5jZSBVUkk9IiNfYmUyZjIxYTYtZDA3NC00
ZmI0LWE5NTktMmNhYmUxODMxY2Q1Ij48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29y
aXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFu
c2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAx
LzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+b3c1aVhYdHhlVW5QNEswWXdJa24y
M2JWa0tHOVU1Q1FzSVoxbUZPZGFsWT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwv
ZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWUgSWQ9Il84N2U2NGVmMy1kODMxLTQyMzkt
Yjg3ZC05NjI2ZTIzNWQzNTUiPlUyWmgwR3Nnb1dtTUVkbEIvOTNDNmhKWUJ5Q3YyU3lKR0NEcDZw
NzhKWWxsajA1N200YlRFUllOYURCQzduTnNsUHI3UzYrakJHQTUKczBmSzNGZ0V3UkVMK2VjRWdp
WU1UMktaK1pza3VRMVIvQk0wMUZ3VTMvUDJZVzJtb1NEY0JGZ2VGNUgyaXFxeTdXY0N4NkI0OE5H
cgpmdE05NHJ5Vmc3SFhXVFBvWUhCejVmNWFZUU9sQWcwU1ZQeWhieWtaUnBIZHJ4aXhsTmRYM3JU
djArUDdSeks5clowbkpQdzdBTVI0CnZMZjNuY29RMVNpS2ZKMkVBRml4WmFLbTNoMFJUdStGNGZL
K2FRUk1CTnpmdERNeEY2WTVjTGt4andPMGJ6TnJvTlVpN0QyTjhseDgKYWxmY3N1QjkzbjBydmtN
UElEcW90YnZvM0ZDZ09FYXhMRlVFcFE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8g
SWQ9Il9iZTJmMjFhNi1kMDc0LTRmYjQtYTk1OS0yY2FiZTE4MzFjZDUiPjxkczpYNTA5RGF0YT48
ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUZPekNDQkNPZ0F3SUJBZ0lnTHJBYmV2b2FlNTJ5M2Y2QzJ0
QjBTbjNwN1hKbTBUMDJGb2d4S0NmTmhaY3dEUVlKS29aSWh2Y04KQVFFTEJRQXdmREVMTUFrR0Ex
VUVCaE1DVlZNeFBEQTZCZ05WQkFvVE0wbHVkR1Z5Ym1WMElFTnZjbkJ2Y21GMGFXOXVJR1p2Y2lC
QgpjM05wWjI1bFpDQk9ZVzFsY3lCaGJtUWdUblZ0WW1WeWN6RXZNQzBHQTFVRUF4TW1TVU5CVGs0
Z1ZISmhaR1Z0WVhKcklFTnNaV0Z5CmFXNW5hRzkxYzJVZ1VHbHNiM1FnUTBFd0hoY05NVGd3TWpJ
NE1EQXdNREF3V2hjTk1qTXdNekF4TWpNMU9UVTVXakNCanpFTE1Ba0cKQTFVRUJoTUNRa1V4SURB
ZUJnTlZCQWdURjBKeWRYTnpaV3h6TFVOaGNHbDBZV3dnVW1WbmFXOXVNUkV3RHdZRFZRUUhFd2hD
Y25WegpjMlZzY3pFUk1BOEdBMVVFQ2hNSVJHVnNiMmwwZEdVeE9EQTJCZ05WQkFNVEwwbERRVTVP
SUZSTlEwZ2dRWFYwYUc5eWFYcGxaQ0JVCmNtRmtaVzFoY21zZ1VHbHNiM1FnVm1Gc2FXUmhkRzl5
TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEKeGxwM0twWUhYM1d5
QXNGaFNrM0x3V2ZuR2x4blVERnFGWkEzVW91TVlqL1hpZ2JNa05lRVhJamxrUk9LVDRPUEdmUngv
TEF5UmxRUQpqQ012NHFoYmtjWDFwN2FyNjNmbHE0U1pOVmNsMTVsN2gwdVQ1OEZ6U2ZubHowdTVy
a0hmSkltRDQzK21hUC84Z3YzNkZSMjdqVzhSCjl3WTRoaytXczRJQjBpRlNkOFNYdjFLcjh3L0pt
TVFTRGtpdUcrUmZJaXVid1EvZnk3RWtqNVFXaFBadyttTXhOS25IVUx5M3hZejIKTHdWZmZ0andV
dWVhY3ZxTlJDa01YbENsT0FEcWZUOG9TWm9lRFhlaEh2bFBzTENlbUdCb1RLdXJza0lTNjlGMHlQ
RUg1Z3plMEgrZgo4RlJPc0lvS1NzVlEzNEI0Uy9qb0U2N25wc0pQVGRLc05QSlR5UUlEQVFBQm80
SUJrekNDQVk4d0RBWURWUjBUQVFIL0JBSXdBREFkCkJnTlZIUTRFRmdRVW9GcFk3NnA1eW9ORFJH
dFFwelZ1UjgxVVdRMHdnY1lHQTFVZEl3U0J2akNCdTRBVXc2MCtwdFlSQUVXQVhEcFgKU29wdDNE
RU5ubkdoZ1lDa2ZqQjhNUXN3Q1FZRFZRUUdFd0pWVXpFOE1Eb0dBMVVFQ2hNelNXNTBaWEp1WlhR
Z1EyOXljRzl5WVhScApiMjRnWm05eUlFRnpjMmxuYm1Wa0lFNWhiV1Z6SUdGdVpDQk9kVzFpWlhK
ek1TOHdMUVlEVlFRREV5WkpRMEZPVGlCVWNtRmtaVzFoCmNtc2dRMnhsWVhKcGJtZG9iM1Z6WlNC
UWFXeHZkQ0JEUVlJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9neEtDZk4KaFhr
d0RnWURWUjBQQVFIL0JBUURBZ2VBTURRR0ExVWRId1F0TUNzd0thQW5vQ1dHSTJoMGRIQTZMeTlq
Y213dWFXTmhibTR1YjNKbgpMM1J0WTJoZmNHbHNiM1F1WTNKc01GRUdBMVVkSUFSS01FZ3dFQVlP
S3dZQkJBR0N5UnNCQllNN0RBb3dOQVlJS3dZQkJRVUhBZ0V3CktEQW1CZ2dyQmdFRkJRY0NBUllh
YUhSMGNITTZMeTlqWVM1cFkyRnViaTV2Y21jdmNHbHNiM1F3RFFZSktvWklodmNOQVFFTEJRQUQK
Z2dFQkFBdWpaMkljUjJEVnJ0YVJyQTU5ZU5ZQ2w0eGNzSk11OERRQ0h2MjhmVGZpL0JpWlk0SXI3
RjlrRnk5NkQ3T1o4b0xZNXpqZgo0ZEh4RndIUHFIOERoNkpXc3pYdUhXMVphM1htbDBQYUh4Q1dS
UzBYb2w4V3NISHBOeWdqTUJZZkowb2RWTTg4NVRaMUVsOVNpdUVICm55bkZCZ1NtaUZjOTl1UWQv
WURSWnVHdi9BMEh5djd5Ujl0a0xFZEQzQTF1TkpCVzRQK0hKR3BkS2tZTDFRNXJVNytvSFZQdE1L
S0kKM2lGa1VFc2JPNDVBVmQ3dlAvai83SnRBWlBiNmtvT1Y1bFppMkgxUkxjY0d3emRlem5oSmdk
ME45b2JiMHZuRTQxL1VTV2FmZFdSWgpWR2t3UHVxVGhsN3NDdHpySkg4WFkweGN1bStjZkx4MkVB
SXdVbk9jYWI0PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZv
PjwvZHM6U2lnbmF0dXJlPjwvc21kOnNpZ25lZE1hcms+
-----END ENCODED SMD-----
@@ -1,99 +0,0 @@
Marks: Essai &amp; évaluation
smdID: 000000631526320349683-65535
U-labels: xn--essai---valuation-itb, xn--essai--valuation-hqb, xn--essai-and-valuation-kzb, xn--essai-andvaluation-jwb, xn--essai-valuation-gnb, xn--essaiand-valuation-jwb, xn--essaiandvaluation-itb, xn--essaiet-valuation-itb, xn--essaietvaluation-hqb, xn--essaivaluation-fkb
notBefore: 2018-05-14T17:52:29.683Z
notAfter: 2022-08-21T08:12:14.116Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8wNDQ1
ODM5Ni1hOTRlLTRlNzktYWQ1Zi1hZjMxYmE2NTIwNWEiPjxzbWQ6aWQ+MDAwMDAwNjMxNTI2MzIw
MzQ5NjgzLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MjoyOS42ODNaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODoxMjoxNC4xMTZaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxMzgxNTAzMDYwNDk2MTUwMzA2MDQ5Ni0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPkVzc2FpICZhbXA7IMOpdmFsdWF0aW9uPC9tYXJrOm1hcmtOYW1lPjxtYXJrOmhv
bGRlciBlbnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm5hbWU+SmVhbiBMZWJsYW5jPC9tYXJrOm5h
bWU+PG1hcms6b3JnPk9yYW5pc2F0aW9uIGRlIHRlc3Q8L21hcms6b3JnPjxtYXJrOmFkZHI+PG1h
cms6c3RyZWV0PlJVRSBST0dORSA0MCA8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+QVJUT0lTPC9t
YXJrOmNpdHk+PG1hcms6cGM+MjEzMDE8L21hcms6cGM+PG1hcms6Y2M+RlI8L21hcms6Y2M+PC9t
YXJrOmFkZHI+PG1hcms6dm9pY2U+KzMzLjI2NDk5NTAzMjwvbWFyazp2b2ljZT48bWFyazpmYXg+
KzMzLjI2NDk5NTAzMzwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BleGFtcGxlLmV4YW1wbGU8
L21hcms6ZW1haWw+PC9tYXJrOmhvbGRlcj48bWFyazpsYWJlbD54bi0tZXNzYWktLS12YWx1YXRp
b24taXRiPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaS0tdmFsdWF0aW9uLWhxYjwv
bWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tZXNzYWktYW5kLXZhbHVhdGlvbi1remI8L21hcms6
bGFiZWw+PG1hcms6bGFiZWw+eG4tLWVzc2FpLWFuZHZhbHVhdGlvbi1qd2I8L21hcms6bGFiZWw+
PG1hcms6bGFiZWw+eG4tLWVzc2FpLXZhbHVhdGlvbi1nbmI8L21hcms6bGFiZWw+PG1hcms6bGFi
ZWw+eG4tLWVzc2FpYW5kLXZhbHVhdGlvbi1qd2I8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4t
LWVzc2FpYW5kdmFsdWF0aW9uLWl0YjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tZXNzYWll
dC12YWx1YXRpb24taXRiPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaWV0dmFsdWF0
aW9uLWhxYjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tZXNzYWl2YWx1YXRpb24tZmtiPC9t
YXJrOmxhYmVsPjxtYXJrOmdvb2RzQW5kU2VydmljZXM+Z3VpdGFyZTwvbWFyazpnb29kc0FuZFNl
cnZpY2VzPjxtYXJrOnJlZk51bT4xMjM0PC9tYXJrOnJlZk51bT48bWFyazpwcm9EYXRlPjIwMTMt
MDEtMDFUMDA6MDA6MDAuMDAwWjwvbWFyazpwcm9EYXRlPjxtYXJrOmNjPlVTPC9tYXJrOmNjPjxt
YXJrOmNvdXJ0TmFtZT5Ib3ZlPC9tYXJrOmNvdXJ0TmFtZT48L21hcms6Y291cnQ+PC9tYXJrOm1h
cms+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxk
c2lnIyIgSWQ9Il9mZWEwOTIwMS1kMzQ0LTQzNjQtOGQwYS05NmQzNjJlYjZkMTciPjxkczpTaWdu
ZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53
My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0
aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48
ZHM6UmVmZXJlbmNlIFVSST0iI18wNDQ1ODM5Ni1hOTRlLTRlNzktYWQ1Zi1hZjMxYmE2NTIwNWEi
PjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9y
Zy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxn
b3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRy
YW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIw
MDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT4vUjJRYUhFUEFDSzlvY3FJZ2Ri
UVFuUlM1YzBTc0h4RjZYTUpGb1p0SytVPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+
PGRzOlJlZmVyZW5jZSBVUkk9IiNfYWY4NmNiNmUtOTM0Yi00YTk3LThhYjgtNzBmNGU1NDI2OGNj
Ij48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5v
cmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRo
b2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48
ZHM6RGlnZXN0VmFsdWU+c1NkY0tlbmlMQU5TOEJFcFVCUVU2bHBGS0F2MFJBT2RNRncwRFdoYzZF
Yz08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2ln
bmF0dXJlVmFsdWUgSWQ9Il9jODQ2YWY0Ny04NjAwLTQwNjUtYWI3Ni0xMjU0MzhiZmUzMGIiPmRP
Vm84amZMMS84YUdnQnhmTjVZeUNIZ240R3ByVFJyUFRqQVkzT2VkNnF6N2NNYmxFcTlUaU1aM2Nv
eWRwbmY4Mm04UGp1cVJmcFUKODhLenBmVnZMSVhXcUlCTlp1Mm5sVGg5SDFUUFZ1R0xjUDVGZ0M2
ZHVrV0VnQzJiUm1KZjhwazgzMWFHVElKOVJ3YkR0WHlvVmxRcQp3bWFGQzNLeDA0azlFaFFSdUs0
UldXdW13K3VXZGc1djFxZjhOWU5uaVhBTFo0SWx3RGZYczV2THhjMCt1RTNOM09tMS80dUNBMjE1
Cmlyb0Fzc2RqMm5nRk9ZUE1nVHNjanpuMGo3MnNIS3c4S0J4MUd6OUNOelpheFZpZFdiU1FxVnFV
T1VnSXJiSFNHQ25NZjVRV2ppZG0KOGRqZDV6SUZ0VHBXT1hQNUdjbmg2bEVWa3FqdDBWaTJvazBT
WWc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8gSWQ9Il9hZjg2Y2I2ZS05MzRiLTRh
OTctOGFiOC03MGY0ZTU0MjY4Y2MiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1J
SUZPekNDQkNPZ0F3SUJBZ0lnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0Nm
TmhaY3dEUVlKS29aSWh2Y04KQVFFTEJRQXdmREVMTUFrR0ExVUVCaE1DVlZNeFBEQTZCZ05WQkFv
VE0wbHVkR1Z5Ym1WMElFTnZjbkJ2Y21GMGFXOXVJR1p2Y2lCQgpjM05wWjI1bFpDQk9ZVzFsY3lC
aGJtUWdUblZ0WW1WeWN6RXZNQzBHQTFVRUF4TW1TVU5CVGs0Z1ZISmhaR1Z0WVhKcklFTnNaV0Z5
CmFXNW5hRzkxYzJVZ1VHbHNiM1FnUTBFd0hoY05NVGd3TWpJNE1EQXdNREF3V2hjTk1qTXdNekF4
TWpNMU9UVTVXakNCanpFTE1Ba0cKQTFVRUJoTUNRa1V4SURBZUJnTlZCQWdURjBKeWRYTnpaV3h6
TFVOaGNHbDBZV3dnVW1WbmFXOXVNUkV3RHdZRFZRUUhFd2hDY25WegpjMlZzY3pFUk1BOEdBMVVF
Q2hNSVJHVnNiMmwwZEdVeE9EQTJCZ05WQkFNVEwwbERRVTVPSUZSTlEwZ2dRWFYwYUc5eWFYcGxa
Q0JVCmNtRmtaVzFoY21zZ1VHbHNiM1FnVm1Gc2FXUmhkRzl5TUlJQklqQU5CZ2txaGtpRzl3MEJB
UUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEKeGxwM0twWUhYM1d5QXNGaFNrM0x3V2ZuR2x4blVERnFG
WkEzVW91TVlqL1hpZ2JNa05lRVhJamxrUk9LVDRPUEdmUngvTEF5UmxRUQpqQ012NHFoYmtjWDFw
N2FyNjNmbHE0U1pOVmNsMTVsN2gwdVQ1OEZ6U2ZubHowdTVya0hmSkltRDQzK21hUC84Z3YzNkZS
MjdqVzhSCjl3WTRoaytXczRJQjBpRlNkOFNYdjFLcjh3L0ptTVFTRGtpdUcrUmZJaXVid1EvZnk3
RWtqNVFXaFBadyttTXhOS25IVUx5M3hZejIKTHdWZmZ0andVdWVhY3ZxTlJDa01YbENsT0FEcWZU
OG9TWm9lRFhlaEh2bFBzTENlbUdCb1RLdXJza0lTNjlGMHlQRUg1Z3plMEgrZgo4RlJPc0lvS1Nz
VlEzNEI0Uy9qb0U2N25wc0pQVGRLc05QSlR5UUlEQVFBQm80SUJrekNDQVk4d0RBWURWUjBUQVFI
L0JBSXdBREFkCkJnTlZIUTRFRmdRVW9GcFk3NnA1eW9ORFJHdFFwelZ1UjgxVVdRMHdnY1lHQTFV
ZEl3U0J2akNCdTRBVXc2MCtwdFlSQUVXQVhEcFgKU29wdDNERU5ubkdoZ1lDa2ZqQjhNUXN3Q1FZ
RFZRUUdFd0pWVXpFOE1Eb0dBMVVFQ2hNelNXNTBaWEp1WlhRZ1EyOXljRzl5WVhScApiMjRnWm05
eUlFRnpjMmxuYm1Wa0lFNWhiV1Z6SUdGdVpDQk9kVzFpWlhKek1TOHdMUVlEVlFRREV5WkpRMEZP
VGlCVWNtRmtaVzFoCmNtc2dRMnhsWVhKcGJtZG9iM1Z6WlNCUWFXeHZkQ0JEUVlJZ0xyQWJldm9h
ZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9neEtDZk4KaFhrd0RnWURWUjBQQVFIL0JBUURBZ2VB
TURRR0ExVWRId1F0TUNzd0thQW5vQ1dHSTJoMGRIQTZMeTlqY213dWFXTmhibTR1YjNKbgpMM1J0
WTJoZmNHbHNiM1F1WTNKc01GRUdBMVVkSUFSS01FZ3dFQVlPS3dZQkJBR0N5UnNCQllNN0RBb3dO
QVlJS3dZQkJRVUhBZ0V3CktEQW1CZ2dyQmdFRkJRY0NBUllhYUhSMGNITTZMeTlqWVM1cFkyRnVi
aTV2Y21jdmNHbHNiM1F3RFFZSktvWklodmNOQVFFTEJRQUQKZ2dFQkFBdWpaMkljUjJEVnJ0YVJy
QTU5ZU5ZQ2w0eGNzSk11OERRQ0h2MjhmVGZpL0JpWlk0SXI3RjlrRnk5NkQ3T1o4b0xZNXpqZgo0
ZEh4RndIUHFIOERoNkpXc3pYdUhXMVphM1htbDBQYUh4Q1dSUzBYb2w4V3NISHBOeWdqTUJZZkow
b2RWTTg4NVRaMUVsOVNpdUVICm55bkZCZ1NtaUZjOTl1UWQvWURSWnVHdi9BMEh5djd5Ujl0a0xF
ZEQzQTF1TkpCVzRQK0hKR3BkS2tZTDFRNXJVNytvSFZQdE1LS0kKM2lGa1VFc2JPNDVBVmQ3dlAv
ai83SnRBWlBiNmtvT1Y1bFppMkgxUkxjY0d3emRlem5oSmdkME45b2JiMHZuRTQxL1VTV2FmZFdS
WgpWR2t3UHVxVGhsN3NDdHpySkg4WFkweGN1bStjZkx4MkVBSXdVbk9jYWI0PTwvZHM6WDUwOUNl
cnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjwvc21k
OnNpZ25lZE1hcms+
-----END ENCODED SMD-----
@@ -1,99 +0,0 @@
Marks: Сертификация &amp; логотип
smdID: 000000671526320355540-65535
U-labels: xn------5cdshvabepr3bbqcpum2a9b4n, xn-----6kcogsabdop0bbpcotl1a7b8m, xn---and--3ve0aj1aabgrv9bbscrwo4a3c9n, xn---and-43dwiyabfqt6bbrcqvn3a1c0o, xn----7sbkfpabcnn7abocnsk0a5bzn, xn--and--43dwiyabfqt6bbrcqvn3a1c0o, xn--and-5cdshvabepr3bbqcpum2a9b4n, xn--80agemabbml4abncmrjz3b2m
notBefore: 2018-05-14T17:52:35.540Z
notAfter: 2022-08-21T08:12:08.921Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il82MDE3
YWQxYy01NzE0LTRjMDEtOTg0OC1iZWYyZjVmYzc2NTUiPjxzbWQ6aWQ+MDAwMDAwNjcxNTI2MzIw
MzU1NTQwLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MjozNS41NDBaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODoxMjowOC45MjFaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazpj
b3VydD48bWFyazppZD4wMDAxNDAxNTAzMDYzMjQ3MTUwMzA2MzI0Ny0xPC9tYXJrOmlkPjxtYXJr
Om1hcmtOYW1lPtCh0LXRgNGC0LjRhNC40LrQsNGG0LjRjyAmYW1wOyDQu9C+0LPQvtGC0LjQvzwv
bWFyazptYXJrTmFtZT48bWFyazpob2xkZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpuYW1l
PtCd0LDRgtCw0LvRjNGPINCQ0L3RgtC+0L3QvtCy0LA8L21hcms6bmFtZT48bWFyazpvcmc+0JDQ
vdGC0L7QvdC+0LLQsDwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+0J/RgNC+0YHQ
v9C10LrRgiDQktC10YDQvdCw0LTRgdC60L7Qs9C+IDE1PC9tYXJrOnN0cmVldD48bWFyazpjaXR5
PtCc0L7RgdC60LLQsDwvbWFyazpjaXR5PjxtYXJrOnBjPjExNzQ4NTwvbWFyazpwYz48bWFyazpj
Yz5SVTwvbWFyazpjYz48L21hcms6YWRkcj48bWFyazp2b2ljZT4rNy45MTg4MjIxNjc0PC9tYXJr
OnZvaWNlPjxtYXJrOmVtYWlsPmluZm9AZXhhbXBsZS5leGFtcGxlPC9tYXJrOmVtYWlsPjwvbWFy
azpob2xkZXI+PG1hcms6bGFiZWw+eG4tLS0tLS01Y2RzaHZhYmVwcjNiYnFjcHVtMmE5YjRuPC9t
YXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS02a2NvZ3NhYmRvcDBiYnBjb3RsMWE3YjhtPC9t
YXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tYW5kLS0zdmUwYWoxYWFiZ3J2OWJic2Nyd280YTNj
OW48L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS1hbmQtNDNkd2l5YWJmcXQ2YmJyY3F2bjNh
MWMwbzwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tLS03c2JrZnBhYmNubjdhYm9jbnNrMGE1
YnpuPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1hbmQtLTQzZHdpeWFiZnF0NmJicmNxdm4z
YTFjMG88L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLWFuZC01Y2RzaHZhYmVwcjNiYnFjcHVt
MmE5YjRuPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS04MGFnZW1hYmJtbDRhYm5jbXJqejNi
Mm08L21hcms6bGFiZWw+PG1hcms6Z29vZHNBbmRTZXJ2aWNlcz5ndWl0YXI8L21hcms6Z29vZHNB
bmRTZXJ2aWNlcz48bWFyazpyZWZOdW0+MTIzNDwvbWFyazpyZWZOdW0+PG1hcms6cHJvRGF0ZT4y
MDEzLTAxLTAxVDAwOjAwOjAwLjAwMFo8L21hcms6cHJvRGF0ZT48bWFyazpjYz5VUzwvbWFyazpj
Yz48bWFyazpjb3VydE5hbWU+SG92ZTwvbWFyazpjb3VydE5hbWU+PC9tYXJrOmNvdXJ0PjwvbWFy
azptYXJrPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkv
eG1sZHNpZyMiIElkPSJfZTU4ZDE5MzAtNjRjNi00N2EyLTk3ZDItMGU3ZGQ3ODY4NjUxIj48ZHM6
U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93
d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxn
b3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2
Ii8+PGRzOlJlZmVyZW5jZSBVUkk9IiNfNjAxN2FkMWMtNTcxNC00YzAxLTk4NDgtYmVmMmY1ZmM3
NjU1Ij48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53
My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3Jt
IEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9k
czpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9y
Zy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+T0NFUlcxYWVrdkhUWWZZ
UUZadVkwbUdpanlXYWwyQ09heklZRk9NTUZCTT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJl
bmNlPjxkczpSZWZlcmVuY2UgVVJJPSIjXzE5ODYwMmNjLWFiNGItNGEzNC04NjAzLTUzZGM0MzVk
YmVmNSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cu
dzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0
TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2
Ii8+PGRzOkRpZ2VzdFZhbHVlPlVNbW5uazB2MTM1NzJEN3FxMVYzZXI1eUtQcmNpbkRYcHNVUXVE
Z3lURDQ9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8+PGRz
OlNpZ25hdHVyZVZhbHVlIElkPSJfZTVmODNjZGItZTgxNi00NDRkLTg3NDktODZkODZiY2YyNjBh
Ij5xQ1I1VDFiamV1TVJSZWgvNTRSeEphTUdIdTNSNmJlVy94cWRiMUJ2bDN0Y3VXU3FtYVdEaGow
SXlWQVlibURQYS8ybHJoYmpMVTI2CnRacG9aWGRuU2lOdERkQ3F5NmN3WVdITlRpU1NTdDc2dzA4
cncrV21GOGQ3UklnOGdPQVdUUWxhM0RNdk4waFNsZHZDb3JjNjBPdlIKeWtrWFU3cGhPZVFnUHBH
VjcrNmY5a01nUndUQ0pGdy9TK25GZDI3ekR5c1Bwb01mbEZTVVdTTE44QXhZZkxsZThxUVdQdzVS
Y2ppdwoxV3JIeHBveFp0T3RFUms5YzZvRzFlUlNGclQ5ZEJMY0JoYWFnWEJPNkxOOHk4WE1IZzdn
dGQ3ZVozZUtJR3dHdVZPSTNPTmFML0dzCkdBNWljUnhYWDZaYVhUZUl4dXE4ZEV1Y2oxNVN0cExI
TjE4L0JRPT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZvIElkPSJfMTk4NjAyY2MtYWI0
Yi00YTM0LTg2MDMtNTNkYzQzNWRiZWY1Ij48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0
ZT5NSUlGT3pDQ0JDT2dBd0lCQWdJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9n
eEtDZk5oWmN3RFFZSktvWklodmNOCkFRRUxCUUF3ZkRFTE1Ba0dBMVVFQmhNQ1ZWTXhQREE2QmdO
VkJBb1RNMGx1ZEdWeWJtVjBJRU52Y25CdmNtRjBhVzl1SUdadmNpQkIKYzNOcFoyNWxaQ0JPWVcx
bGN5QmhibVFnVG5WdFltVnljekV2TUMwR0ExVUVBeE1tU1VOQlRrNGdWSEpoWkdWdFlYSnJJRU5z
WldGeQphVzVuYUc5MWMyVWdVR2xzYjNRZ1EwRXdIaGNOTVRnd01qSTRNREF3TURBd1doY05Nak13
TXpBeE1qTTFPVFU1V2pDQmp6RUxNQWtHCkExVUVCaE1DUWtVeElEQWVCZ05WQkFnVEYwSnlkWE56
Wld4ekxVTmhjR2wwWVd3Z1VtVm5hVzl1TVJFd0R3WURWUVFIRXdoQ2NuVnoKYzJWc2N6RVJNQThH
QTFVRUNoTUlSR1ZzYjJsMGRHVXhPREEyQmdOVkJBTVRMMGxEUVU1T0lGUk5RMGdnUVhWMGFHOXlh
WHBsWkNCVQpjbUZrWlcxaGNtc2dVR2xzYjNRZ1ZtRnNhV1JoZEc5eU1JSUJJakFOQmdrcWhraUc5
dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnhscDNLcFlIWDNXeUFzRmhTazNMd1dmbkdseG5V
REZxRlpBM1VvdU1Zai9YaWdiTWtOZUVYSWpsa1JPS1Q0T1BHZlJ4L0xBeVJsUVEKakNNdjRxaGJr
Y1gxcDdhcjYzZmxxNFNaTlZjbDE1bDdoMHVUNThGelNmbmx6MHU1cmtIZkpJbUQ0MyttYVAvOGd2
MzZGUjI3alc4Ugo5d1k0aGsrV3M0SUIwaUZTZDhTWHYxS3I4dy9KbU1RU0RraXVHK1JmSWl1YndR
L2Z5N0VrajVRV2hQWncrbU14TktuSFVMeTN4WXoyCkx3VmZmdGp3VXVlYWN2cU5SQ2tNWGxDbE9B
RHFmVDhvU1pvZURYZWhIdmxQc0xDZW1HQm9US3Vyc2tJUzY5RjB5UEVINWd6ZTBIK2YKOEZST3NJ
b0tTc1ZRMzRCNFMvam9FNjducHNKUFRkS3NOUEpUeVFJREFRQUJvNElCa3pDQ0FZOHdEQVlEVlIw
VEFRSC9CQUl3QURBZApCZ05WSFE0RUZnUVVvRnBZNzZwNXlvTkRSR3RRcHpWdVI4MVVXUTB3Z2NZ
R0ExVWRJd1NCdmpDQnU0QVV3NjArcHRZUkFFV0FYRHBYClNvcHQzREVObm5HaGdZQ2tmakI4TVFz
d0NRWURWUVFHRXdKVlV6RThNRG9HQTFVRUNoTXpTVzUwWlhKdVpYUWdRMjl5Y0c5eVlYUnAKYjI0
Z1ptOXlJRUZ6YzJsbmJtVmtJRTVoYldWeklHRnVaQ0JPZFcxaVpYSnpNUzh3TFFZRFZRUURFeVpK
UTBGT1RpQlVjbUZrWlcxaApjbXNnUTJ4bFlYSnBibWRvYjNWelpTQlFhV3h2ZENCRFFZSWdMckFi
ZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOCmhYa3dEZ1lEVlIwUEFRSC9CQVFE
QWdlQU1EUUdBMVVkSHdRdE1Dc3dLYUFub0NXR0kyaDBkSEE2THk5amNtd3VhV05oYm00dWIzSm4K
TDNSdFkyaGZjR2xzYjNRdVkzSnNNRkVHQTFVZElBUktNRWd3RUFZT0t3WUJCQUdDeVJzQkJZTTdE
QW93TkFZSUt3WUJCUVVIQWdFdwpLREFtQmdnckJnRUZCUWNDQVJZYWFIUjBjSE02THk5allTNXBZ
MkZ1Ymk1dmNtY3ZjR2xzYjNRd0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBQXVqWjJJY1IyRFZy
dGFSckE1OWVOWUNsNHhjc0pNdThEUUNIdjI4ZlRmaS9CaVpZNElyN0Y5a0Z5OTZEN09aOG9MWTV6
amYKNGRIeEZ3SFBxSDhEaDZKV3N6WHVIVzFaYTNYbWwwUGFIeENXUlMwWG9sOFdzSEhwTnlnak1C
WWZKMG9kVk04ODVUWjFFbDlTaXVFSApueW5GQmdTbWlGYzk5dVFkL1lEUlp1R3YvQTBIeXY3eVI5
dGtMRWREM0ExdU5KQlc0UCtISkdwZEtrWUwxUTVyVTcrb0hWUHRNS0tJCjNpRmtVRXNiTzQ1QVZk
N3ZQL2ovN0p0QVpQYjZrb09WNWxaaTJIMVJMY2NHd3pkZXpuaEpnZDBOOW9iYjB2bkU0MS9VU1dh
ZmRXUloKVkdrd1B1cVRobDdzQ3R6ckpIOFhZMHhjdW0rY2ZMeDJFQUl3VW5PY2FiND08L2RzOlg1
MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48
L3NtZDpzaWduZWRNYXJrPg==
-----END ENCODED SMD-----
@@ -1,99 +0,0 @@
Marks: الاختبار &amp; لتقييم
smdID: 000000771526320375015-65535
U-labels: xn------nzeaagpf7azb2ppajr3fa, xn-----btdaafne4a7azpoaiq8ea, xn----ymcaaeld1a4a6onahp3ea, xn--mgbaadjcy1a8mmago8da
notBefore: 2018-05-14T17:52:55.015Z
notAfter: 2022-08-18T14:27:18.209Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il85NWNl
ZjgzNC0wZTkxLTQ1ODQtOGNiYy1iNmFiMDU1ZmFlOWYiPjxzbWQ6aWQ+MDAwMDAwNzcxNTI2MzIw
Mzc1MDE1LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo1NS4wMTVaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDoyNzoxOC4yMDlaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTQ0MTUwMzA2NjE5NTE1MDMwNjYxOTUtMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT7Yp9mE2KfYrtiq2KjYp9ixICZhbXA7INmE2KrZgtmK2YrZhTwvbWFyazpt
YXJrTmFtZT48bWFyazpob2xkZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpuYW1lPtmF2YfZ
htiv2LMg2KfZhNmF2LnZhNmI2YXYp9iq2YrYqTwvbWFyazpuYW1lPjxtYXJrOmFkZHI+PG1hcms6
c3RyZWV0Ptis2LnZgdixINin2KjZhiDYs9mK2YbYp9ihIDc1PC9tYXJrOnN0cmVldD48bWFyazpj
aXR5PtmF2YPZhtin2LM8L21hcms6Y2l0eT48bWFyazpwYz4yOTAwPC9tYXJrOnBjPjxtYXJrOmNj
Pk1BPC9tYXJrOmNjPjwvbWFyazphZGRyPjwvbWFyazpob2xkZXI+PG1hcms6Y29udGFjdCB0eXBl
PSJhZ2VudCI+PG1hcms6bmFtZT7ZhdmH2YbYr9izINin2YTZhdi52YTZiNmF2KfYqtmK2Kk8L21h
cms6bmFtZT48bWFyazpvcmc+2YjZg9in2YTYqTwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpz
dHJlZXQ+2LTYp9ix2Lkg2KzYudmB2LEg2KfYqNmGINiz2YrZhtin2KEgNzU8L21hcms6c3RyZWV0
PjxtYXJrOmNpdHk+2YXZg9mG2KfYszwvbWFyazpjaXR5PjxtYXJrOnBjPjI5MDA8L21hcms6cGM+
PG1hcms6Y2M+TUE8L21hcms6Y2M+PC9tYXJrOmFkZHI+PG1hcms6dm9pY2U+KzIxMi41MjI1Mzkw
NDA8L21hcms6dm9pY2U+PG1hcms6ZmF4PisyMTIuNTIyNTM5MDQxPC9tYXJrOmZheD48bWFyazpl
bWFpbD5pbmZvQGFnZW5jeS1tYXJvY2NvLmNvbTwvbWFyazplbWFpbD48L21hcms6Y29udGFjdD48
bWFyazpqdXJpc2RpY3Rpb24+VVM8L21hcms6anVyaXNkaWN0aW9uPjxtYXJrOmNsYXNzPjE1PC9t
YXJrOmNsYXNzPjxtYXJrOmxhYmVsPnhuLS0tLS0tbnplYWFncGY3YXpiMnBwYWpyM2ZhPC9tYXJr
OmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS1idGRhYWZuZTRhN2F6cG9haXE4ZWE8L21hcms6bGFi
ZWw+PG1hcms6bGFiZWw+eG4tLS0teW1jYWFlbGQxYTRhNm9uYWhwM2VhPC9tYXJrOmxhYmVsPjxt
YXJrOmxhYmVsPnhuLS1tZ2JhYWRqY3kxYThtbWFnbzhkYTwvbWFyazpsYWJlbD48bWFyazpnb29k
c0FuZFNlcnZpY2VzPti62YrYqtin2LE8L21hcms6Z29vZHNBbmRTZXJ2aWNlcz48bWFyazpyZWdO
dW0+MTIzNDwvbWFyazpyZWdOdW0+PG1hcms6cmVnRGF0ZT4yMDEzLTAxLTAxVDAwOjAwOjAwLjAw
MFo8L21hcms6cmVnRGF0ZT48L21hcms6dHJhZGVtYXJrPjwvbWFyazptYXJrPjxkczpTaWduYXR1
cmUgeG1sbnM6ZHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIElkPSJfOGU0
ZGUzYTMtNjAyZC00ZWM2LThiOWYtODIxN2UzY2I4ZDY3Ij48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fu
b25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAv
eG1sLWV4Yy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3
LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+PGRzOlJlZmVyZW5jZSBV
Ukk9IiNfOTVjZWY4MzQtMGU5MS00NTg0LThjYmMtYjZhYjA1NWZhZTlmIj48ZHM6VHJhbnNmb3Jt
cz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxk
c2lnI2VudmVsb3BlZC1zaWduYXR1cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDov
L3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpE
aWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNz
aGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+RFFpMjZGVVFsRW1WYU41TkFPN2VFUVIwVGhZa2d2Tit2
YzdKN0ZqV0FtUT08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJlbmNlPjxkczpSZWZlcmVuY2Ug
VVJJPSIjX2ZkZTI3NjYxLTI5ZWMtNDAxMS1hODlkLThjODc0M2ViZWE3MiI+PGRzOlRyYW5zZm9y
bXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1s
LWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0i
aHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVl
PjVxSjR0Q2o5Slg0ZXQ5ZERpdEliNUVreUQrVlhCRFJ3bi9mQ3VtK1JjZEU9PC9kczpEaWdlc3RW
YWx1ZT48L2RzOlJlZmVyZW5jZT48L2RzOlNpZ25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlIElk
PSJfNTBmY2QzMDYtZGFkZi00M2M0LWI3MzMtNjFkNTMyZGI3NTZkIj5JeWpBZFgzMW5YOGN2bkov
dFFZRURFZ04rWGF1SWJPemlqTWV4R1ZPTEhIblpqaTgwb0Q0Mjg3VHNwWUt0b2ZVczM3ZURuenc1
ZVZ2CmdqazUvcnlleis3Wi8rVVYwVEpGeFhGc3ZDS3p1dHZyQkF3YzJvR3Z3Ni9XcjVtNW1SWkh6
eit2eTJ3SWhaYytIRmx5a1NNdm84a0IKaXVJUFUreHRXZ0FvSFRrNUtMRktYZDhPT3duOFdMbElh
WDlpMlVqYzdZemY0VEh5dlRJcGthSjZVS2U5Z2pIZ3VaN0NHME9TeFVqYgp5WTErZTBhMWFNZllU
cWFFVUVEb2ErbjVuMVorQkVRajlzR2ZkUWYwS0FraE1vQmVVVUZGazVWNDFPZTJlRngwN1EybXYv
ZG5HRzQyCmV5SzQ0czBhQWNtdUtMUEtDSlFkUHpsMlFBZUlMaVFCYTFQcVBnPT08L2RzOlNpZ25h
dHVyZVZhbHVlPjxkczpLZXlJbmZvIElkPSJfZmRlMjc2NjEtMjllYy00MDExLWE4OWQtOGM4NzQz
ZWJlYTcyIj48ZHM6WDUwOURhdGE+PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlGT3pDQ0JDT2dBd0lC
QWdJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9neEtDZk5oWmN3RFFZSktvWklo
dmNOCkFRRUxCUUF3ZkRFTE1Ba0dBMVVFQmhNQ1ZWTXhQREE2QmdOVkJBb1RNMGx1ZEdWeWJtVjBJ
RU52Y25CdmNtRjBhVzl1SUdadmNpQkIKYzNOcFoyNWxaQ0JPWVcxbGN5QmhibVFnVG5WdFltVnlj
ekV2TUMwR0ExVUVBeE1tU1VOQlRrNGdWSEpoWkdWdFlYSnJJRU5zWldGeQphVzVuYUc5MWMyVWdV
R2xzYjNRZ1EwRXdIaGNOTVRnd01qSTRNREF3TURBd1doY05Nak13TXpBeE1qTTFPVFU1V2pDQmp6
RUxNQWtHCkExVUVCaE1DUWtVeElEQWVCZ05WQkFnVEYwSnlkWE56Wld4ekxVTmhjR2wwWVd3Z1Vt
Vm5hVzl1TVJFd0R3WURWUVFIRXdoQ2NuVnoKYzJWc2N6RVJNQThHQTFVRUNoTUlSR1ZzYjJsMGRH
VXhPREEyQmdOVkJBTVRMMGxEUVU1T0lGUk5RMGdnUVhWMGFHOXlhWHBsWkNCVQpjbUZrWlcxaGNt
c2dVR2xzYjNRZ1ZtRnNhV1JoZEc5eU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJ
QkNnS0NBUUVBCnhscDNLcFlIWDNXeUFzRmhTazNMd1dmbkdseG5VREZxRlpBM1VvdU1Zai9YaWdi
TWtOZUVYSWpsa1JPS1Q0T1BHZlJ4L0xBeVJsUVEKakNNdjRxaGJrY1gxcDdhcjYzZmxxNFNaTlZj
bDE1bDdoMHVUNThGelNmbmx6MHU1cmtIZkpJbUQ0MyttYVAvOGd2MzZGUjI3alc4Ugo5d1k0aGsr
V3M0SUIwaUZTZDhTWHYxS3I4dy9KbU1RU0RraXVHK1JmSWl1YndRL2Z5N0VrajVRV2hQWncrbU14
TktuSFVMeTN4WXoyCkx3VmZmdGp3VXVlYWN2cU5SQ2tNWGxDbE9BRHFmVDhvU1pvZURYZWhIdmxQ
c0xDZW1HQm9US3Vyc2tJUzY5RjB5UEVINWd6ZTBIK2YKOEZST3NJb0tTc1ZRMzRCNFMvam9FNjdu
cHNKUFRkS3NOUEpUeVFJREFRQUJvNElCa3pDQ0FZOHdEQVlEVlIwVEFRSC9CQUl3QURBZApCZ05W
SFE0RUZnUVVvRnBZNzZwNXlvTkRSR3RRcHpWdVI4MVVXUTB3Z2NZR0ExVWRJd1NCdmpDQnU0QVV3
NjArcHRZUkFFV0FYRHBYClNvcHQzREVObm5HaGdZQ2tmakI4TVFzd0NRWURWUVFHRXdKVlV6RThN
RG9HQTFVRUNoTXpTVzUwWlhKdVpYUWdRMjl5Y0c5eVlYUnAKYjI0Z1ptOXlJRUZ6YzJsbmJtVmtJ
RTVoYldWeklHRnVaQ0JPZFcxaVpYSnpNUzh3TFFZRFZRUURFeVpKUTBGT1RpQlVjbUZrWlcxaApj
bXNnUTJ4bFlYSnBibWRvYjNWelpTQlFhV3h2ZENCRFFZSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNu
M3A3WEptMFQwMkZvZ3hLQ2ZOCmhYa3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1EUUdBMVVkSHdRdE1D
c3dLYUFub0NXR0kyaDBkSEE2THk5amNtd3VhV05oYm00dWIzSm4KTDNSdFkyaGZjR2xzYjNRdVkz
SnNNRkVHQTFVZElBUktNRWd3RUFZT0t3WUJCQUdDeVJzQkJZTTdEQW93TkFZSUt3WUJCUVVIQWdF
dwpLREFtQmdnckJnRUZCUWNDQVJZYWFIUjBjSE02THk5allTNXBZMkZ1Ymk1dmNtY3ZjR2xzYjNR
d0RRWUpLb1pJaHZjTkFRRUxCUUFECmdnRUJBQXVqWjJJY1IyRFZydGFSckE1OWVOWUNsNHhjc0pN
dThEUUNIdjI4ZlRmaS9CaVpZNElyN0Y5a0Z5OTZEN09aOG9MWTV6amYKNGRIeEZ3SFBxSDhEaDZK
V3N6WHVIVzFaYTNYbWwwUGFIeENXUlMwWG9sOFdzSEhwTnlnak1CWWZKMG9kVk04ODVUWjFFbDlT
aXVFSApueW5GQmdTbWlGYzk5dVFkL1lEUlp1R3YvQTBIeXY3eVI5dGtMRWREM0ExdU5KQlc0UCtI
SkdwZEtrWUwxUTVyVTcrb0hWUHRNS0tJCjNpRmtVRXNiTzQ1QVZkN3ZQL2ovN0p0QVpQYjZrb09W
NWxaaTJIMVJMY2NHd3pkZXpuaEpnZDBOOW9iYjB2bkU0MS9VU1dhZmRXUloKVkdrd1B1cVRobDdz
Q3R6ckpIOFhZMHhjdW0rY2ZMeDJFQUl3VW5PY2FiND08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2Rz
Olg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25hdHVyZT48L3NtZDpzaWduZWRNYXJrPg==
-----END ENCODED SMD-----
@@ -1,98 +0,0 @@
Marks: 审判&amp;错误
smdID: 000000801526320380861-65535
U-labels: xn----ke8al50aln4ceuj, xn--and-ui2eu74b9t4egon, xn--et-pg5cw37ax04dfrl, xn--fcr14u8t4bdxh
notBefore: 2018-05-14T17:53:00.861Z
notAfter: 2022-08-18T14:36:50.931Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8wMDE5
NmU0Ni1iYjE3LTQxNzgtYWU5MS1kMTNlZmM5MDU5YzEiPjxzbWQ6aWQ+MDAwMDAwODAxNTI2MzIw
MzgwODYxLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzowMC44NjFaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDozNjo1MC45MzFaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTQ2MTUwMzA2Njc5NTE1MDMwNjY3OTUtMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT7lrqHliKQmYW1wO+mUmeivrzwvbWFyazptYXJrTmFtZT48bWFyazpob2xk
ZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpvcmc+5bel56iL5aSEPC9tYXJrOm9yZz48bWFy
azphZGRyPjxtYXJrOnN0cmVldD7pppnmuK/kuJzot6825Y+377yMNeWPt+alvO+8jDjlj7flrqQ8
L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+6Z2S5bKb5biCPC9tYXJrOmNpdHk+PG1hcms6cGM+MzUw
MDwvbWFyazpwYz48bWFyazpjYz5DTjwvbWFyazpjYz48L21hcms6YWRkcj48L21hcms6aG9sZGVy
PjxtYXJrOmNvbnRhY3QgdHlwZT0iYWdlbnQiPjxtYXJrOm5hbWU+5p2O5bCP5pa5PC9tYXJrOm5h
bWU+PG1hcms6b3JnPuW3peeoi+WkhDwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+
6aaZ5riv5Lic6LevNuWPt++8jDXlj7fmpbzvvIw45Y+35a6kPC9tYXJrOnN0cmVldD48bWFyazpj
aXR5PumdkuWym+W4gjwvbWFyazpjaXR5PjxtYXJrOnBjPjM1MDA8L21hcms6cGM+PG1hcms6Y2M+
Q048L21hcms6Y2M+PC9tYXJrOmFkZHI+PG1hcms6dm9pY2U+Kzg2LjEwODQ2NTcxNzM8L21hcms6
dm9pY2U+PG1hcms6ZmF4Pis4Ni4xMDg0NjU3MTc1PC9tYXJrOmZheD48bWFyazplbWFpbD5pbmZv
QGNoaW5lc2UtYWdlbmN5LmNvbTwvbWFyazplbWFpbD48L21hcms6Y29udGFjdD48bWFyazpqdXJp
c2RpY3Rpb24+VVM8L21hcms6anVyaXNkaWN0aW9uPjxtYXJrOmNsYXNzPjE1PC9tYXJrOmNsYXNz
PjxtYXJrOmxhYmVsPnhuLS0tLWtlOGFsNTBhbG40Y2V1ajwvbWFyazpsYWJlbD48bWFyazpsYWJl
bD54bi0tYW5kLXVpMmV1NzRiOXQ0ZWdvbjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tZXQt
cGc1Y3czN2F4MDRkZnJsPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1mY3IxNHU4dDRiZHho
PC9tYXJrOmxhYmVsPjxtYXJrOmdvb2RzQW5kU2VydmljZXM+5ZCJ5LuWPC9tYXJrOmdvb2RzQW5k
U2VydmljZXM+PG1hcms6cmVnTnVtPjEyMzQ8L21hcms6cmVnTnVtPjxtYXJrOnJlZ0RhdGU+MjAx
My0wMS0wMVQwMDowMDowMC4wMDBaPC9tYXJrOnJlZ0RhdGU+PC9tYXJrOnRyYWRlbWFyaz48L21h
cms6bWFyaz48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5
L3htbGRzaWcjIiBJZD0iX2I2ZmZkNDE3LWNkODktNGM5ZS1iMDVkLTY2MjQ0ZDNhZmVjNiI+PGRz
OlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8v
d3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFs
Z29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1
NiIvPjxkczpSZWZlcmVuY2UgVVJJPSIjXzAwMTk2ZTQ2LWJiMTctNDE3OC1hZTkxLWQxM2VmYzkw
NTljMSI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cu
dzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9y
bSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwv
ZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5v
cmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPlJNakxrK09ScVlyRmZl
UGg1TWNxRklNc2pUYWJGbGZudWhJNWwxRjdyWlU9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVy
ZW5jZT48ZHM6UmVmZXJlbmNlIFVSST0iI19mOWY3OGUwOS05MzkyLTRlZTItYTExZi0zOTUzM2Iz
NDg1M2YiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3
LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2Vz
dE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1
NiIvPjxkczpEaWdlc3RWYWx1ZT4zVzFBZjY4U0F3dlRjUEVjN21RZnV1VUZKaVN3eWlkWTlUZXBv
ZXc3U3JzPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxk
czpTaWduYXR1cmVWYWx1ZSBJZD0iXzMxZjlmNTEzLWQwYjktNDcwNC04NGE1LTNiYjBmOTE3MzY1
MCI+Rm9iTGpncVA0TllOUXFGeVRReHkvMGV1N05nRk5NYXgzYjRCaG5oL1Q0bkFjdWtCZ2NCK0xx
d3NranVGZUR3NDNybjY2bm9sdFBtTwphOGdDQWNNdUdjM1drcjVYdDl2N1J4dEViOFdrN3hVRXZh
WnM2R0tpNDBZQlRodElNbHhKQyswRGlaRHEzLy9SZjFzSGxDT1k3S2htCjBXeXhMOFFFbmh1RUpJ
T09mRDBFbTZzUU9yMG90N0pQVGZ1MDc3bjFuY3FYbEZqSU9JOGZLRVd1d0ZPV0JYL1BTRDNDSENl
MCtIeTIKbHI3Q0xyWGVGbWVybmt3OEFDZDZKU3h6WjBqc2ZyVWsrOXY2MmNqQjdSY2FJTjhnTk44
ZUdvSCtzR0s2M1BGWHJBQU54YXZxem9tWgp5NXhtVkwzVHUyT1gvUlc5b0xrZVdKUzhEQnlLNGIy
WnArTXE5QT09PC9kczpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbyBJZD0iX2Y5Zjc4ZTA5LTkz
OTItNGVlMi1hMTFmLTM5NTMzYjM0ODUzZiI+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNh
dGU+TUlJRk96Q0NCQ09nQXdJQkFnSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZv
Z3hLQ2ZOaFpjd0RRWUpLb1pJaHZjTgpBUUVMQlFBd2ZERUxNQWtHQTFVRUJoTUNWVk14UERBNkJn
TlZCQW9UTTBsdWRHVnlibVYwSUVOdmNuQnZjbUYwYVc5dUlHWnZjaUJCCmMzTnBaMjVsWkNCT1lX
MWxjeUJoYm1RZ1RuVnRZbVZ5Y3pFdk1DMEdBMVVFQXhNbVNVTkJUazRnVkhKaFpHVnRZWEpySUVO
c1pXRnkKYVc1bmFHOTFjMlVnVUdsc2IzUWdRMEV3SGhjTk1UZ3dNakk0TURBd01EQXdXaGNOTWpN
d016QXhNak0xT1RVNVdqQ0JqekVMTUFrRwpBMVVFQmhNQ1FrVXhJREFlQmdOVkJBZ1RGMEp5ZFhO
elpXeHpMVU5oY0dsMFlXd2dVbVZuYVc5dU1SRXdEd1lEVlFRSEV3aENjblZ6CmMyVnNjekVSTUE4
R0ExVUVDaE1JUkdWc2IybDBkR1V4T0RBMkJnTlZCQU1UTDBsRFFVNU9JRlJOUTBnZ1FYVjBhRzl5
YVhwbFpDQlUKY21Ga1pXMWhjbXNnVUdsc2IzUWdWbUZzYVdSaGRHOXlNSUlCSWpBTkJna3Foa2lH
OXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQQp4bHAzS3BZSFgzV3lBc0ZoU2szTHdXZm5HbHhu
VURGcUZaQTNVb3VNWWovWGlnYk1rTmVFWElqbGtST0tUNE9QR2ZSeC9MQXlSbFFRCmpDTXY0cWhi
a2NYMXA3YXI2M2ZscTRTWk5WY2wxNWw3aDB1VDU4RnpTZm5sejB1NXJrSGZKSW1ENDMrbWFQLzhn
djM2RlIyN2pXOFIKOXdZNGhrK1dzNElCMGlGU2Q4U1h2MUtyOHcvSm1NUVNEa2l1RytSZklpdWJ3
US9meTdFa2o1UVdoUFp3K21NeE5LbkhVTHkzeFl6MgpMd1ZmZnRqd1V1ZWFjdnFOUkNrTVhsQ2xP
QURxZlQ4b1Nab2VEWGVoSHZsUHNMQ2VtR0JvVEt1cnNrSVM2OUYweVBFSDVnemUwSCtmCjhGUk9z
SW9LU3NWUTM0QjRTL2pvRTY3bnBzSlBUZEtzTlBKVHlRSURBUUFCbzRJQmt6Q0NBWTh3REFZRFZS
MFRBUUgvQkFJd0FEQWQKQmdOVkhRNEVGZ1FVb0ZwWTc2cDV5b05EUkd0UXB6VnVSODFVV1Ewd2dj
WUdBMVVkSXdTQnZqQ0J1NEFVdzYwK3B0WVJBRVdBWERwWApTb3B0M0RFTm5uR2hnWUNrZmpCOE1R
c3dDUVlEVlFRR0V3SlZVekU4TURvR0ExVUVDaE16U1c1MFpYSnVaWFFnUTI5eWNHOXlZWFJwCmIy
NGdabTl5SUVGemMybG5ibVZrSUU1aGJXVnpJR0Z1WkNCT2RXMWlaWEp6TVM4d0xRWURWUVFERXla
SlEwRk9UaUJVY21Ga1pXMWgKY21zZ1EyeGxZWEpwYm1kb2IzVnpaU0JRYVd4dmRDQkRRWUlnTHJB
YmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTgpoWGt3RGdZRFZSMFBBUUgvQkFR
REFnZUFNRFFHQTFVZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5OWpjbXd1YVdOaGJtNHViM0pu
CkwzUnRZMmhmY0dsc2IzUXVZM0pzTUZFR0ExVWRJQVJLTUVnd0VBWU9Ld1lCQkFHQ3lSc0JCWU03
REFvd05BWUlLd1lCQlFVSEFnRXcKS0RBbUJnZ3JCZ0VGQlFjQ0FSWWFhSFIwY0hNNkx5OWpZUzVw
WTJGdWJpNXZjbWN2Y0dsc2IzUXdEUVlKS29aSWh2Y05BUUVMQlFBRApnZ0VCQUF1aloySWNSMkRW
cnRhUnJBNTllTllDbDR4Y3NKTXU4RFFDSHYyOGZUZmkvQmlaWTRJcjdGOWtGeTk2RDdPWjhvTFk1
empmCjRkSHhGd0hQcUg4RGg2Sldzelh1SFcxWmEzWG1sMFBhSHhDV1JTMFhvbDhXc0hIcE55Z2pN
QllmSjBvZFZNODg1VFoxRWw5U2l1RUgKbnluRkJnU21pRmM5OXVRZC9ZRFJadUd2L0EwSHl2N3lS
OXRrTEVkRDNBMXVOSkJXNFArSEpHcGRLa1lMMVE1clU3K29IVlB0TUtLSQozaUZrVUVzYk80NUFW
ZDd2UC9qLzdKdEFaUGI2a29PVjVsWmkySDFSTGNjR3d6ZGV6bmhKZ2QwTjlvYmIwdm5FNDEvVVNX
YWZkV1JaClZHa3dQdXFUaGw3c0N0enJKSDhYWTB4Y3VtK2NmTHgyRUFJd1VuT2NhYjQ9PC9kczpY
NTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+
PC9zbWQ6c2lnbmVkTWFyaz4=
-----END ENCODED SMD-----
@@ -1,102 +0,0 @@
Marks: Test &amp; Validate
smdID: 000000871526320392536-65535
U-labels: test---validate, test--validate, test-and-validate, test-andvalidate, test-validate, testand-validate, testandvalidate, testet-validate, testetvalidate, testvalidate
notBefore: 2018-05-14T17:53:12.536Z
notAfter: 2022-08-18T14:57:36.681Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8wOTJk
YzQ4Yi02ZDZhLTRiNzQtYTRhZS1mOThmZDQ0NmQ1OGEiPjxzbWQ6aWQ+MDAwMDAwODcxNTI2MzIw
MzkyNTM2LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzoxMi41MzZaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDo1NzozNi42ODFaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTM3MTUwMzA2ODA0OTE1MDMwNjgwNDktMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT5UZXN0ICZhbXA7IFZhbGlkYXRlPC9tYXJrOm1hcmtOYW1lPjxtYXJrOmhv
bGRlciBlbnRpdGxlbWVudD0ib3duZXIiPjxtYXJrOm5hbWU+VG9ueSBIb2xsYW5kPC9tYXJrOm5h
bWU+PG1hcms6b3JnPkFnIGNvcnBvcmF0aW9uPC9tYXJrOm9yZz48bWFyazphZGRyPjxtYXJrOnN0
cmVldD4xMzA1IEJyaWdodCBBdmVudWU8L21hcms6c3RyZWV0PjxtYXJrOmNpdHk+QXJjYWRpYTwv
bWFyazpjaXR5PjxtYXJrOnBjPjkwMDI4PC9tYXJrOnBjPjxtYXJrOmNjPlVTPC9tYXJrOmNjPjwv
bWFyazphZGRyPjwvbWFyazpob2xkZXI+PG1hcms6Y29udGFjdCB0eXBlPSJhZ2VudCI+PG1hcms6
bmFtZT5Ub255IEhvbGxhbmQ8L21hcms6bmFtZT48bWFyazpvcmc+QWcgY29ycG9yYXRpb248L21h
cms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3RyZWV0PkJyaWdodCBBdmVudWUgMTMwNSA8L21hcms6
c3RyZWV0PjxtYXJrOmNpdHk+QXJjYWRpYTwvbWFyazpjaXR5PjxtYXJrOnNwPkNBPC9tYXJrOnNw
PjxtYXJrOnBjPjkwMDI4PC9tYXJrOnBjPjxtYXJrOmNjPlVTPC9tYXJrOmNjPjwvbWFyazphZGRy
PjxtYXJrOnZvaWNlPisxLjIwMjU1NjIzMDI8L21hcms6dm9pY2U+PG1hcms6ZmF4PisxLjIwMjU1
NjIzMDE8L21hcms6ZmF4PjxtYXJrOmVtYWlsPmluZm9AYWdjb3Jwb3JhdGlvbi5jb208L21hcms6
ZW1haWw+PC9tYXJrOmNvbnRhY3Q+PG1hcms6anVyaXNkaWN0aW9uPlVTPC9tYXJrOmp1cmlzZGlj
dGlvbj48bWFyazpjbGFzcz4xNTwvbWFyazpjbGFzcz48bWFyazpsYWJlbD50ZXN0LS0tdmFsaWRh
dGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdC0tdmFsaWRhdGU8L21hcms6bGFiZWw+PG1h
cms6bGFiZWw+dGVzdC1hbmQtdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+dGVzdC1h
bmR2YWxpZGF0ZTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD50ZXN0LXZhbGlkYXRlPC9tYXJrOmxh
YmVsPjxtYXJrOmxhYmVsPnRlc3RhbmQtdmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+
dGVzdGFuZHZhbGlkYXRlPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnRlc3RldC12YWxpZGF0ZTwv
bWFyazpsYWJlbD48bWFyazpsYWJlbD50ZXN0ZXR2YWxpZGF0ZTwvbWFyazpsYWJlbD48bWFyazps
YWJlbD50ZXN0dmFsaWRhdGU8L21hcms6bGFiZWw+PG1hcms6Z29vZHNBbmRTZXJ2aWNlcz5ndWl0
YXI8L21hcms6Z29vZHNBbmRTZXJ2aWNlcz48bWFyazpyZWdOdW0+MTIzNDwvbWFyazpyZWdOdW0+
PG1hcms6cmVnRGF0ZT4yMDEzLTAxLTAxVDAwOjAwOjAwLjAwMFo8L21hcms6cmVnRGF0ZT48L21h
cms6dHJhZGVtYXJrPjwvbWFyazptYXJrPjxkczpTaWduYXR1cmUgeG1sbnM6ZHM9Imh0dHA6Ly93
d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIElkPSJfMzI5OGQ0OGItMzMyMS00OWU1LThiMDct
YTE4Y2RlODYxNmU0Ij48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBB
bGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjxkczpT
aWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRz
aWctbW9yZSNyc2Etc2hhMjU2Ii8+PGRzOlJlZmVyZW5jZSBVUkk9IiNfMDkyZGM0OGItNmQ2YS00
Yjc0LWE0YWUtZjk4ZmQ0NDZkNThhIj48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3JtIEFsZ29y
aXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1
cmUiLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94
bWwtZXhjLWMxNG4jIi8+PC9kczpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGht
PSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFs
dWU+dU5TZ2VTclIvbXpHVmdUdmVjRHZCVFdiZDVqTWdKbENEODNrandIemJ4Zz08L2RzOkRpZ2Vz
dFZhbHVlPjwvZHM6UmVmZXJlbmNlPjxkczpSZWZlcmVuY2UgVVJJPSIjX2U0YTNhNjEzLTAzYTEt
NGZiMi05NWIwLTU2ODVlZDAzYjI4NyI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJh
bnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAw
MS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPkZVbjdMcmVhWFVUQzQ3dkVueXQw
aXZZRXhVZUdJblBVMU5FUWY4NXNyUk09PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48
L2RzOlNpZ25lZEluZm8+PGRzOlNpZ25hdHVyZVZhbHVlIElkPSJfMjdjODQxOWUtOTk3Yy00NmQz
LWIxNTEtOTUwODQ1ZjgwOWE3Ij5pSmpxWnFaczdXcE91UzZVNVU0bS8zRzB4ZG9Ya3ZORk93UmNq
QjI3UFlFNEQ3cVd4d3JDeUZYUTdtNXhkcTAxR1NpeHRpYjlKOXIwClpzZEROaXZyR0c2b05JTGNs
a0J1UzRlR3pDMWo3cEZ0alYvRjFNclNiRlI3ZUN3eDhXd2p0N3lBdGlEYXQ0L3VSQkEwQlEyeEpV
QSsKQ3IxRml4ckdHSkZNREsxRzBRSU5FU0grK3lNUFZKM0x1ckFTSEJjY0syeVlQTWN6ME5yenJF
b0RHd0R0QVk5YXpmQTZndlRDZHZCVwpxOXpxR2NSaTIxOXAvb3c0aW5CcmNsQ05qMGdrUDRwMk5t
UTVmM29WSEI2MFVBQ2FFaDV1aUROZ2Q0QkszdDN0N0JQUHN2bStyb0N0CjNIR2V0dnFzK3RQdlE2
Mm1RRWFZVGtCSTZCS0M0TEVYYjRwdzRRPT08L2RzOlNpZ25hdHVyZVZhbHVlPjxkczpLZXlJbmZv
IElkPSJfZTRhM2E2MTMtMDNhMS00ZmIyLTk1YjAtNTY4NWVkMDNiMjg3Ij48ZHM6WDUwOURhdGE+
PGRzOlg1MDlDZXJ0aWZpY2F0ZT5NSUlGT3pDQ0JDT2dBd0lCQWdJZ0xyQWJldm9hZTUyeTNmNkMy
dEIwU24zcDdYSm0wVDAyRm9neEtDZk5oWmN3RFFZSktvWklodmNOCkFRRUxCUUF3ZkRFTE1Ba0dB
MVVFQmhNQ1ZWTXhQREE2QmdOVkJBb1RNMGx1ZEdWeWJtVjBJRU52Y25CdmNtRjBhVzl1SUdadmNp
QkIKYzNOcFoyNWxaQ0JPWVcxbGN5QmhibVFnVG5WdFltVnljekV2TUMwR0ExVUVBeE1tU1VOQlRr
NGdWSEpoWkdWdFlYSnJJRU5zWldGeQphVzVuYUc5MWMyVWdVR2xzYjNRZ1EwRXdIaGNOTVRnd01q
STRNREF3TURBd1doY05Nak13TXpBeE1qTTFPVFU1V2pDQmp6RUxNQWtHCkExVUVCaE1DUWtVeElE
QWVCZ05WQkFnVEYwSnlkWE56Wld4ekxVTmhjR2wwWVd3Z1VtVm5hVzl1TVJFd0R3WURWUVFIRXdo
Q2NuVnoKYzJWc2N6RVJNQThHQTFVRUNoTUlSR1ZzYjJsMGRHVXhPREEyQmdOVkJBTVRMMGxEUVU1
T0lGUk5RMGdnUVhWMGFHOXlhWHBsWkNCVQpjbUZrWlcxaGNtc2dVR2xzYjNRZ1ZtRnNhV1JoZEc5
eU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBCnhscDNLcFlIWDNX
eUFzRmhTazNMd1dmbkdseG5VREZxRlpBM1VvdU1Zai9YaWdiTWtOZUVYSWpsa1JPS1Q0T1BHZlJ4
L0xBeVJsUVEKakNNdjRxaGJrY1gxcDdhcjYzZmxxNFNaTlZjbDE1bDdoMHVUNThGelNmbmx6MHU1
cmtIZkpJbUQ0MyttYVAvOGd2MzZGUjI3alc4Ugo5d1k0aGsrV3M0SUIwaUZTZDhTWHYxS3I4dy9K
bU1RU0RraXVHK1JmSWl1YndRL2Z5N0VrajVRV2hQWncrbU14TktuSFVMeTN4WXoyCkx3VmZmdGp3
VXVlYWN2cU5SQ2tNWGxDbE9BRHFmVDhvU1pvZURYZWhIdmxQc0xDZW1HQm9US3Vyc2tJUzY5RjB5
UEVINWd6ZTBIK2YKOEZST3NJb0tTc1ZRMzRCNFMvam9FNjducHNKUFRkS3NOUEpUeVFJREFRQUJv
NElCa3pDQ0FZOHdEQVlEVlIwVEFRSC9CQUl3QURBZApCZ05WSFE0RUZnUVVvRnBZNzZwNXlvTkRS
R3RRcHpWdVI4MVVXUTB3Z2NZR0ExVWRJd1NCdmpDQnU0QVV3NjArcHRZUkFFV0FYRHBYClNvcHQz
REVObm5HaGdZQ2tmakI4TVFzd0NRWURWUVFHRXdKVlV6RThNRG9HQTFVRUNoTXpTVzUwWlhKdVpY
UWdRMjl5Y0c5eVlYUnAKYjI0Z1ptOXlJRUZ6YzJsbmJtVmtJRTVoYldWeklHRnVaQ0JPZFcxaVpY
SnpNUzh3TFFZRFZRUURFeVpKUTBGT1RpQlVjbUZrWlcxaApjbXNnUTJ4bFlYSnBibWRvYjNWelpT
QlFhV3h2ZENCRFFZSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOCmhY
a3dEZ1lEVlIwUEFRSC9CQVFEQWdlQU1EUUdBMVVkSHdRdE1Dc3dLYUFub0NXR0kyaDBkSEE2THk5
amNtd3VhV05oYm00dWIzSm4KTDNSdFkyaGZjR2xzYjNRdVkzSnNNRkVHQTFVZElBUktNRWd3RUFZ
T0t3WUJCQUdDeVJzQkJZTTdEQW93TkFZSUt3WUJCUVVIQWdFdwpLREFtQmdnckJnRUZCUWNDQVJZ
YWFIUjBjSE02THk5allTNXBZMkZ1Ymk1dmNtY3ZjR2xzYjNRd0RRWUpLb1pJaHZjTkFRRUxCUUFE
CmdnRUJBQXVqWjJJY1IyRFZydGFSckE1OWVOWUNsNHhjc0pNdThEUUNIdjI4ZlRmaS9CaVpZNEly
N0Y5a0Z5OTZEN09aOG9MWTV6amYKNGRIeEZ3SFBxSDhEaDZKV3N6WHVIVzFaYTNYbWwwUGFIeENX
UlMwWG9sOFdzSEhwTnlnak1CWWZKMG9kVk04ODVUWjFFbDlTaXVFSApueW5GQmdTbWlGYzk5dVFk
L1lEUlp1R3YvQTBIeXY3eVI5dGtMRWREM0ExdU5KQlc0UCtISkdwZEtrWUwxUTVyVTcrb0hWUHRN
S0tJCjNpRmtVRXNiTzQ1QVZkN3ZQL2ovN0p0QVpQYjZrb09WNWxaaTJIMVJMY2NHd3pkZXpuaEpn
ZDBOOW9iYjB2bkU0MS9VU1dhZmRXUloKVkdrd1B1cVRobDdzQ3R6ckpIOFhZMHhjdW0rY2ZMeDJF
QUl3VW5PY2FiND08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5m
bz48L2RzOlNpZ25hdHVyZT48L3NtZDpzaWduZWRNYXJrPg==
-----END ENCODED SMD-----
@@ -1,103 +0,0 @@
Marks: Essai &amp; évaluation
smdID: 000000831526320386700-65535
U-labels: xn--essai---valuation-itb, xn--essai--valuation-hqb, xn--essai-and-valuation-kzb, xn--essai-andvaluation-jwb, xn--essai-valuation-gnb, xn--essaiand-valuation-jwb, xn--essaiandvaluation-itb, xn--essaiet-valuation-itb, xn--essaietvaluation-hqb, xn--essaivaluation-fkb
notBefore: 2018-05-14T17:53:06.700Z
notAfter: 2022-08-18T14:46:53.013Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8wNDc1
MzkxZi03MzU1LTQ2ZTctODAxOC0yMDdkOWY4OGIzNjYiPjxzbWQ6aWQ+MDAwMDAwODMxNTI2MzIw
Mzg2NzAwLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzowNi43MDBaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDo0Njo1My4wMTNaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTM5MTUwMzA2NzM4MjE1MDMwNjczODItMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT5Fc3NhaSAmYW1wOyDDqXZhbHVhdGlvbjwvbWFyazptYXJrTmFtZT48bWFy
azpob2xkZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpvcmc+QWdlbmNlIGVuIEZyYW5jZTwv
bWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+MTAgQXZlbnVlIFJvdXNzZWF1eDwvbWFy
azpzdHJlZXQ+PG1hcms6Y2l0eT5WZXJzYWlsbGVzPC9tYXJrOmNpdHk+PG1hcms6cGM+MzMwODE8
L21hcms6cGM+PG1hcms6Y2M+RlI8L21hcms6Y2M+PC9tYXJrOmFkZHI+PC9tYXJrOmhvbGRlcj48
bWFyazpjb250YWN0IHR5cGU9ImFnZW50Ij48bWFyazpuYW1lPkZyYW5jIExlYnJ1bjwvbWFyazpu
YW1lPjxtYXJrOm9yZz5BZ2VuY2UgZW4gRnJhbmNlPC9tYXJrOm9yZz48bWFyazphZGRyPjxtYXJr
OnN0cmVldD5BdmVudWUgUm91c3NlYXV4IDEwIDwvbWFyazpzdHJlZXQ+PG1hcms6Y2l0eT5WZXJz
YWlsbGVzPC9tYXJrOmNpdHk+PG1hcms6cGM+MzMwODE8L21hcms6cGM+PG1hcms6Y2M+RlI8L21h
cms6Y2M+PC9tYXJrOmFkZHI+PG1hcms6dm9pY2U+KzMzLjEyNTc4MTI1MDwvbWFyazp2b2ljZT48
bWFyazpmYXg+KzMzLjEyNTc4MTI1MTwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BhZ2VuY2Ut
ZW4tZnJhbmNlLmZyPC9tYXJrOmVtYWlsPjwvbWFyazpjb250YWN0PjxtYXJrOmp1cmlzZGljdGlv
bj5VUzwvbWFyazpqdXJpc2RpY3Rpb24+PG1hcms6Y2xhc3M+MTU8L21hcms6Y2xhc3M+PG1hcms6
bGFiZWw+eG4tLWVzc2FpLS0tdmFsdWF0aW9uLWl0YjwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54
bi0tZXNzYWktLXZhbHVhdGlvbi1ocWI8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLWVzc2Fp
LWFuZC12YWx1YXRpb24ta3piPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaS1hbmR2
YWx1YXRpb24tandiPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaS12YWx1YXRpb24t
Z25iPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaWFuZC12YWx1YXRpb24tandiPC9t
YXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1lc3NhaWFuZHZhbHVhdGlvbi1pdGI8L21hcms6bGFi
ZWw+PG1hcms6bGFiZWw+eG4tLWVzc2FpZXQtdmFsdWF0aW9uLWl0YjwvbWFyazpsYWJlbD48bWFy
azpsYWJlbD54bi0tZXNzYWlldHZhbHVhdGlvbi1ocWI8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+
eG4tLWVzc2FpdmFsdWF0aW9uLWZrYjwvbWFyazpsYWJlbD48bWFyazpnb29kc0FuZFNlcnZpY2Vz
Pmd1aXRhcjwvbWFyazpnb29kc0FuZFNlcnZpY2VzPjxtYXJrOnJlZ051bT4xMjM0PC9tYXJrOnJl
Z051bT48bWFyazpyZWdEYXRlPjIwMTMtMDEtMDFUMDA6MDA6MDAuMDAwWjwvbWFyazpyZWdEYXRl
PjwvbWFyazp0cmFkZW1hcms+PC9tYXJrOm1hcms+PGRzOlNpZ25hdHVyZSB4bWxuczpkcz0iaHR0
cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgSWQ9Il9kODJkMWNjZC01NDE1LTQ1ZGMt
YmFlZS02YjQ0MTQyZjRiZjEiPjxkczpTaWduZWRJbmZvPjxkczpDYW5vbmljYWxpemF0aW9uTWV0
aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+
PGRzOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQv
eG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48ZHM6UmVmZXJlbmNlIFVSST0iI18wNDc1MzkxZi03
MzU1LTQ2ZTctODAxOC0yMDdkOWY4OGIzNjYiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0g
QWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNp
Z25hdHVyZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAx
LzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdl
c3RWYWx1ZT5CTWRyLzg3cVpocHQ1SXVvVXdTUFpiQ3JsMEQvYzMvS2RLM1ZTV2RFUmo0PTwvZHM6
RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PGRzOlJlZmVyZW5jZSBVUkk9IiNfNDhiZjM0ZTgt
NWM3MC00ZDRlLTg2MDItNWEwNTAwYWYyNWQ3Ij48ZHM6VHJhbnNmb3Jtcz48ZHM6VHJhbnNmb3Jt
IEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+PC9k
czpUcmFuc2Zvcm1zPjxkczpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9y
Zy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHM6RGlnZXN0VmFsdWU+cEZ0RTkxTEwyZ2h0SDZ0
cmtyR2ppWE1pZlpyQ1pNMUhXRXFZSmtTQ1ZwND08L2RzOkRpZ2VzdFZhbHVlPjwvZHM6UmVmZXJl
bmNlPjwvZHM6U2lnbmVkSW5mbz48ZHM6U2lnbmF0dXJlVmFsdWUgSWQ9Il8yNGVjYWRhNS1kYjZj
LTQ4MmEtOWM3Mi0wYWJiYjUyNmU1OGIiPlNTbjRXeWVZNDZyVmdMZGQzNUNJQlAva2taMFFMWFpO
ajd0ZUhhUU1OVC9ROU5sRWNicmo0Y2djWFZNNXlsT1M5SXQvdjdvQ09jckMKK2cxbTdINjB1Vkg3
U0w0bWl5dWVyYW5vZy9GU2ZTd1J1akc4Z0MyWEhqQUNEU2dxbnFYN3YzempWRkI4VFZrYjhLWHJh
a29jM0tRUAo2ZjlDNmcxcll3QlBiVnZNV1FUd3BwSHJBbmRnRFlUb3pUOWowRmVzcWljbm14UzhG
ZU1DRHl4UkYydmxCQ05RaUk0QmZ6NVpYcHhFClhRdnEvdjBkVmk0cnl0UWY3K29UMnBHSlJNUVV3
ZHpXVmJOZnZvU2ZMUDBlRHFkUHcxczI1MVpHamhyRm9LOWRZRDBOMmo2RG5mSUgKUG9LbjNXSCtl
bVBvaGt3UlFGUmZlT2JUbnhwOGwyNmRsMWNVOVE9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktl
eUluZm8gSWQ9Il80OGJmMzRlOC01YzcwLTRkNGUtODYwMi01YTA1MDBhZjI1ZDciPjxkczpYNTA5
RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUZPekNDQkNPZ0F3SUJBZ0lnTHJBYmV2b2FlNTJ5
M2Y2QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTmhaY3dEUVlKS29aSWh2Y04KQVFFTEJRQXdmREVM
TUFrR0ExVUVCaE1DVlZNeFBEQTZCZ05WQkFvVE0wbHVkR1Z5Ym1WMElFTnZjbkJ2Y21GMGFXOXVJ
R1p2Y2lCQgpjM05wWjI1bFpDQk9ZVzFsY3lCaGJtUWdUblZ0WW1WeWN6RXZNQzBHQTFVRUF4TW1T
VU5CVGs0Z1ZISmhaR1Z0WVhKcklFTnNaV0Z5CmFXNW5hRzkxYzJVZ1VHbHNiM1FnUTBFd0hoY05N
VGd3TWpJNE1EQXdNREF3V2hjTk1qTXdNekF4TWpNMU9UVTVXakNCanpFTE1Ba0cKQTFVRUJoTUNR
a1V4SURBZUJnTlZCQWdURjBKeWRYTnpaV3h6TFVOaGNHbDBZV3dnVW1WbmFXOXVNUkV3RHdZRFZR
UUhFd2hDY25WegpjMlZzY3pFUk1BOEdBMVVFQ2hNSVJHVnNiMmwwZEdVeE9EQTJCZ05WQkFNVEww
bERRVTVPSUZSTlEwZ2dRWFYwYUc5eWFYcGxaQ0JVCmNtRmtaVzFoY21zZ1VHbHNiM1FnVm1Gc2FX
UmhkRzl5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEKeGxwM0tw
WUhYM1d5QXNGaFNrM0x3V2ZuR2x4blVERnFGWkEzVW91TVlqL1hpZ2JNa05lRVhJamxrUk9LVDRP
UEdmUngvTEF5UmxRUQpqQ012NHFoYmtjWDFwN2FyNjNmbHE0U1pOVmNsMTVsN2gwdVQ1OEZ6U2Zu
bHowdTVya0hmSkltRDQzK21hUC84Z3YzNkZSMjdqVzhSCjl3WTRoaytXczRJQjBpRlNkOFNYdjFL
cjh3L0ptTVFTRGtpdUcrUmZJaXVid1EvZnk3RWtqNVFXaFBadyttTXhOS25IVUx5M3hZejIKTHdW
ZmZ0andVdWVhY3ZxTlJDa01YbENsT0FEcWZUOG9TWm9lRFhlaEh2bFBzTENlbUdCb1RLdXJza0lT
NjlGMHlQRUg1Z3plMEgrZgo4RlJPc0lvS1NzVlEzNEI0Uy9qb0U2N25wc0pQVGRLc05QSlR5UUlE
QVFBQm80SUJrekNDQVk4d0RBWURWUjBUQVFIL0JBSXdBREFkCkJnTlZIUTRFRmdRVW9GcFk3NnA1
eW9ORFJHdFFwelZ1UjgxVVdRMHdnY1lHQTFVZEl3U0J2akNCdTRBVXc2MCtwdFlSQUVXQVhEcFgK
U29wdDNERU5ubkdoZ1lDa2ZqQjhNUXN3Q1FZRFZRUUdFd0pWVXpFOE1Eb0dBMVVFQ2hNelNXNTBa
WEp1WlhRZ1EyOXljRzl5WVhScApiMjRnWm05eUlFRnpjMmxuYm1Wa0lFNWhiV1Z6SUdGdVpDQk9k
VzFpWlhKek1TOHdMUVlEVlFRREV5WkpRMEZPVGlCVWNtRmtaVzFoCmNtc2dRMnhsWVhKcGJtZG9i
M1Z6WlNCUWFXeHZkQ0JEUVlJZ0xyQWJldm9hZTUyeTNmNkMydEIwU24zcDdYSm0wVDAyRm9neEtD
Zk4KaFhrd0RnWURWUjBQQVFIL0JBUURBZ2VBTURRR0ExVWRId1F0TUNzd0thQW5vQ1dHSTJoMGRI
QTZMeTlqY213dWFXTmhibTR1YjNKbgpMM1J0WTJoZmNHbHNiM1F1WTNKc01GRUdBMVVkSUFSS01F
Z3dFQVlPS3dZQkJBR0N5UnNCQllNN0RBb3dOQVlJS3dZQkJRVUhBZ0V3CktEQW1CZ2dyQmdFRkJR
Y0NBUllhYUhSMGNITTZMeTlqWVM1cFkyRnViaTV2Y21jdmNHbHNiM1F3RFFZSktvWklodmNOQVFF
TEJRQUQKZ2dFQkFBdWpaMkljUjJEVnJ0YVJyQTU5ZU5ZQ2w0eGNzSk11OERRQ0h2MjhmVGZpL0Jp
Wlk0SXI3RjlrRnk5NkQ3T1o4b0xZNXpqZgo0ZEh4RndIUHFIOERoNkpXc3pYdUhXMVphM1htbDBQ
YUh4Q1dSUzBYb2w4V3NISHBOeWdqTUJZZkowb2RWTTg4NVRaMUVsOVNpdUVICm55bkZCZ1NtaUZj
OTl1UWQvWURSWnVHdi9BMEh5djd5Ujl0a0xFZEQzQTF1TkpCVzRQK0hKR3BkS2tZTDFRNXJVNytv
SFZQdE1LS0kKM2lGa1VFc2JPNDVBVmQ3dlAvai83SnRBWlBiNmtvT1Y1bFppMkgxUkxjY0d3emRl
em5oSmdkME45b2JiMHZuRTQxL1VTV2FmZFdSWgpWR2t3UHVxVGhsN3NDdHpySkg4WFkweGN1bStj
Zkx4MkVBSXdVbk9jYWI0PTwvZHM6WDUwOUNlcnRpZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpL
ZXlJbmZvPjwvZHM6U2lnbmF0dXJlPjwvc21kOnNpZ25lZE1hcms+
-----END ENCODED SMD-----
@@ -1,104 +0,0 @@
Marks: суда &amp; ошибки
smdID: 000000741526320369172-65535
U-labels: xn------5cdin6abr1b1ay5e, xn-----6kcgl1abp7azaw9d, xn---and--3vemr6bbv9b5a2a7f, xn---and-43dkp1bbt5b3a0a1f, xn----7sbejwbn3axu3d, xn--and--43dkp1bbt5b3a0a1f, xn--and-5cdin6abr1b1ay5e, xn--et--5cdin6abr1b1ay5e, xn--et-6kcgl1abp7azaw9d, xn--80achrblzvs7c
notBefore: 2018-05-14T17:52:49.172Z
notAfter: 2022-08-18T14:16:55.554Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il8zZmM4
NjdlYy0yODlhLTQwMzEtYmQ2Mi1jNDdhZWUzOGNkZGMiPjxzbWQ6aWQ+MDAwMDAwNzQxNTI2MzIw
MzY5MTcyLTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1Mjo0OS4xNzJaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0xOFQxNDoxNjo1NS41NTRaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTQxMTUwMzA2NTU1MDE1MDMwNjU1NTAtMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT7RgdGD0LTQsCAmYW1wOyDQvtGI0LjQsdC60Lg8L21hcms6bWFya05hbWU+
PG1hcms6aG9sZGVyIGVudGl0bGVtZW50PSJvd25lciI+PG1hcms6b3JnPtCQ0LPQtdC90YLRgdGC
0LLQvjwvbWFyazpvcmc+PG1hcms6YWRkcj48bWFyazpzdHJlZXQ+0J/RgNC+0YHQv9C10LrRgiDQ
ktC10YDQvdCw0LTRgdC60L7Qs9C+IDE1PC9tYXJrOnN0cmVldD48bWFyazpjaXR5PtCc0L7RgdC6
0LLQsDwvbWFyazpjaXR5PjxtYXJrOnBjPjExNzQ4NTwvbWFyazpwYz48bWFyazpjYz5SVTwvbWFy
azpjYz48L21hcms6YWRkcj48L21hcms6aG9sZGVyPjxtYXJrOmNvbnRhY3QgdHlwZT0iYWdlbnQi
PjxtYXJrOm5hbWU+0J3QsNGC0LDQu9GM0Y8g0JDQvdGC0L7QvdC+0LLQsDwvbWFyazpuYW1lPjxt
YXJrOm9yZz7QkNCz0LXQvdGC0YHRgtCy0L48L21hcms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3Ry
ZWV0PtCf0YDQvtGB0L/QtdC60YIg0JLQtdGA0L3QsNC00YHQutC+0LPQviAxNTwvbWFyazpzdHJl
ZXQ+PG1hcms6Y2l0eT7QnNC+0YHQutCy0LA8L21hcms6Y2l0eT48bWFyazpwYz4xMTc0ODU8L21h
cms6cGM+PG1hcms6Y2M+UlU8L21hcms6Y2M+PC9tYXJrOmFkZHI+PG1hcms6dm9pY2U+KzcuOTE4
ODIyMTY3NDwvbWFyazp2b2ljZT48bWFyazpmYXg+KzcuOTE4ODIyMTY3MzwvbWFyazpmYXg+PG1h
cms6ZW1haWw+aW5mb0BhZ2VuY3kucnU8L21hcms6ZW1haWw+PC9tYXJrOmNvbnRhY3Q+PG1hcms6
anVyaXNkaWN0aW9uPlVTPC9tYXJrOmp1cmlzZGljdGlvbj48bWFyazpjbGFzcz4xNTwvbWFyazpj
bGFzcz48bWFyazpsYWJlbD54bi0tLS0tLTVjZGluNmFicjFiMWF5NWU8L21hcms6bGFiZWw+PG1h
cms6bGFiZWw+eG4tLS0tLTZrY2dsMWFicDdhemF3OWQ8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+
eG4tLS1hbmQtLTN2ZW1yNmJidjliNWEyYTdmPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0t
YW5kLTQzZGtwMWJidDViM2EwYTFmPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLTdzYmVq
d2JuM2F4dTNkPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1hbmQtLTQzZGtwMWJidDViM2Ew
YTFmPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS1hbmQtNWNkaW42YWJyMWIxYXk1ZTwvbWFy
azpsYWJlbD48bWFyazpsYWJlbD54bi0tZXQtLTVjZGluNmFicjFiMWF5NWU8L21hcms6bGFiZWw+
PG1hcms6bGFiZWw+eG4tLWV0LTZrY2dsMWFicDdhemF3OWQ8L21hcms6bGFiZWw+PG1hcms6bGFi
ZWw+eG4tLTgwYWNocmJsenZzN2M8L21hcms6bGFiZWw+PG1hcms6Z29vZHNBbmRTZXJ2aWNlcz7Q
s9C40YLQsNGA0LAgPC9tYXJrOmdvb2RzQW5kU2VydmljZXM+PG1hcms6cmVnTnVtPjEyMzQ8L21h
cms6cmVnTnVtPjxtYXJrOnJlZ0RhdGU+MjAxMy0wMS0wMVQwMDowMDowMC4wMDBaPC9tYXJrOnJl
Z0RhdGU+PC9tYXJrOnRyYWRlbWFyaz48L21hcms6bWFyaz48ZHM6U2lnbmF0dXJlIHhtbG5zOmRz
PSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJZD0iXzJkYzkzZmYwLWE2OTEt
NGI5Ni05ZWQxLWQ0MjEyMjAxN2UxMyI+PGRzOlNpZ25lZEluZm8+PGRzOkNhbm9uaWNhbGl6YXRp
b25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0
biMiLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAw
MS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZlcmVuY2UgVVJJPSIjXzNmYzg2
N2VjLTI4OWEtNDAzMS1iZDYyLWM0N2FlZTM4Y2RkYyI+PGRzOlRyYW5zZm9ybXM+PGRzOlRyYW5z
Zm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9w
ZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3Jn
LzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9k
IEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8+PGRz
OkRpZ2VzdFZhbHVlPnFRMThOYktsOW0zS2NSS291aFRMWTErSXd3WFNkeEhTZlRMMk80cjFnSU09
PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48ZHM6UmVmZXJlbmNlIFVSST0iI18xNGQ1
MzQ4MS04MTUzLTRhNDItOGI3OS0xNWYwMzI1N2FjYjYiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFu
c2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMi
Lz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cu
dzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT5IcUplczRqN0dw
ODUrdmNvMVo2Q1A0VjA1dFU3c01FbDBQR0gwSDlJYjR3PTwvZHM6RGlnZXN0VmFsdWU+PC9kczpS
ZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZSBJZD0iXzVjNDllNzcw
LTJjYjMtNDg0OC05OWY1LWNhOTBlMDdhYmJhZSI+bmg1eGhwQ2tHdElmbnhVUGdUMmV6Uk5ZVWQ5
bjRGT2E2N1pSaW81QzdkbzkybjU0OTAzdTUwbThIV0FDTmdUdGVWTitvQ2lMNGNXdgpnQ1prNDJ0
bHdiY3dhb0I3cjJmK3ZsTzR6eDdFbUc2UDZPYWl3aWRYYjVabUdoOVc4dVplVk54VUtjLytjenNk
d0xBUmVQeXpZL2JOCjEzT3ZoSEkrbHM3TitDUkhNdTlwZUdIZXdBQlpIV0RKYXpXZWxPQVZkcVNY
L2hEOVVBSGY5QXo2RjdhZEp3RTVUN2JMOGxuRlVGaWMKQ3BlRDMxN0ZGOU1YTWdqU1hXMWpOVDdP
aUlLeXUxeXQ1WXFIZUtFU2ZiSklpY01WUVZDa3NVMUw1YWpWYzMyOUNudDM5N09Bb0JHdgpDei9N
SzhvV0o2UmluUHB3dThQN05TVzF1eWRVaTBKZE1CL0cyZz09PC9kczpTaWduYXR1cmVWYWx1ZT48
ZHM6S2V5SW5mbyBJZD0iXzE0ZDUzNDgxLTgxNTMtNGE0Mi04Yjc5LTE1ZjAzMjU3YWNiNiI+PGRz
Olg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRk96Q0NCQ09nQXdJQkFnSWdMckFiZXZv
YWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOaFpjd0RRWUpLb1pJaHZjTgpBUUVMQlFB
d2ZERUxNQWtHQTFVRUJoTUNWVk14UERBNkJnTlZCQW9UTTBsdWRHVnlibVYwSUVOdmNuQnZjbUYw
YVc5dUlHWnZjaUJCCmMzTnBaMjVsWkNCT1lXMWxjeUJoYm1RZ1RuVnRZbVZ5Y3pFdk1DMEdBMVVF
QXhNbVNVTkJUazRnVkhKaFpHVnRZWEpySUVOc1pXRnkKYVc1bmFHOTFjMlVnVUdsc2IzUWdRMEV3
SGhjTk1UZ3dNakk0TURBd01EQXdXaGNOTWpNd016QXhNak0xT1RVNVdqQ0JqekVMTUFrRwpBMVVF
QmhNQ1FrVXhJREFlQmdOVkJBZ1RGMEp5ZFhOelpXeHpMVU5oY0dsMFlXd2dVbVZuYVc5dU1SRXdE
d1lEVlFRSEV3aENjblZ6CmMyVnNjekVSTUE4R0ExVUVDaE1JUkdWc2IybDBkR1V4T0RBMkJnTlZC
QU1UTDBsRFFVNU9JRlJOUTBnZ1FYVjBhRzl5YVhwbFpDQlUKY21Ga1pXMWhjbXNnVUdsc2IzUWdW
bUZzYVdSaGRHOXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQQp4
bHAzS3BZSFgzV3lBc0ZoU2szTHdXZm5HbHhuVURGcUZaQTNVb3VNWWovWGlnYk1rTmVFWElqbGtS
T0tUNE9QR2ZSeC9MQXlSbFFRCmpDTXY0cWhia2NYMXA3YXI2M2ZscTRTWk5WY2wxNWw3aDB1VDU4
RnpTZm5sejB1NXJrSGZKSW1ENDMrbWFQLzhndjM2RlIyN2pXOFIKOXdZNGhrK1dzNElCMGlGU2Q4
U1h2MUtyOHcvSm1NUVNEa2l1RytSZklpdWJ3US9meTdFa2o1UVdoUFp3K21NeE5LbkhVTHkzeFl6
MgpMd1ZmZnRqd1V1ZWFjdnFOUkNrTVhsQ2xPQURxZlQ4b1Nab2VEWGVoSHZsUHNMQ2VtR0JvVEt1
cnNrSVM2OUYweVBFSDVnemUwSCtmCjhGUk9zSW9LU3NWUTM0QjRTL2pvRTY3bnBzSlBUZEtzTlBK
VHlRSURBUUFCbzRJQmt6Q0NBWTh3REFZRFZSMFRBUUgvQkFJd0FEQWQKQmdOVkhRNEVGZ1FVb0Zw
WTc2cDV5b05EUkd0UXB6VnVSODFVV1Ewd2djWUdBMVVkSXdTQnZqQ0J1NEFVdzYwK3B0WVJBRVdB
WERwWApTb3B0M0RFTm5uR2hnWUNrZmpCOE1Rc3dDUVlEVlFRR0V3SlZVekU4TURvR0ExVUVDaE16
U1c1MFpYSnVaWFFnUTI5eWNHOXlZWFJwCmIyNGdabTl5SUVGemMybG5ibVZrSUU1aGJXVnpJR0Z1
WkNCT2RXMWlaWEp6TVM4d0xRWURWUVFERXlaSlEwRk9UaUJVY21Ga1pXMWgKY21zZ1EyeGxZWEpw
Ym1kb2IzVnpaU0JRYVd4dmRDQkRRWUlnTHJBYmV2b2FlNTJ5M2Y2QzJ0QjBTbjNwN1hKbTBUMDJG
b2d4S0NmTgpoWGt3RGdZRFZSMFBBUUgvQkFRREFnZUFNRFFHQTFVZEh3UXRNQ3N3S2FBbm9DV0dJ
MmgwZEhBNkx5OWpjbXd1YVdOaGJtNHViM0puCkwzUnRZMmhmY0dsc2IzUXVZM0pzTUZFR0ExVWRJ
QVJLTUVnd0VBWU9Ld1lCQkFHQ3lSc0JCWU03REFvd05BWUlLd1lCQlFVSEFnRXcKS0RBbUJnZ3JC
Z0VGQlFjQ0FSWWFhSFIwY0hNNkx5OWpZUzVwWTJGdWJpNXZjbWN2Y0dsc2IzUXdEUVlKS29aSWh2
Y05BUUVMQlFBRApnZ0VCQUF1aloySWNSMkRWcnRhUnJBNTllTllDbDR4Y3NKTXU4RFFDSHYyOGZU
ZmkvQmlaWTRJcjdGOWtGeTk2RDdPWjhvTFk1empmCjRkSHhGd0hQcUg4RGg2Sldzelh1SFcxWmEz
WG1sMFBhSHhDV1JTMFhvbDhXc0hIcE55Z2pNQllmSjBvZFZNODg1VFoxRWw5U2l1RUgKbnluRkJn
U21pRmM5OXVRZC9ZRFJadUd2L0EwSHl2N3lSOXRrTEVkRDNBMXVOSkJXNFArSEpHcGRLa1lMMVE1
clU3K29IVlB0TUtLSQozaUZrVUVzYk80NUFWZDd2UC9qLzdKdEFaUGI2a29PVjVsWmkySDFSTGNj
R3d6ZGV6bmhKZ2QwTjlvYmIwdm5FNDEvVVNXYWZkV1JaClZHa3dQdXFUaGw3c0N0enJKSDhYWTB4
Y3VtK2NmTHgyRUFJd1VuT2NhYjQ9PC9kczpYNTA5Q2VydGlmaWNhdGU+PC9kczpYNTA5RGF0YT48
L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PC9zbWQ6c2lnbmVkTWFyaz4=
-----END ENCODED SMD-----
@@ -1,99 +0,0 @@
Marks: الاختبار &amp; لتقييم
smdID: 000000901526320396418-65535
U-labels: xn------nzeaagpf7azb2ppajr3fa, xn-----btdaafne4a7azpoaiq8ea, xn----ymcaaeld1a4a6onahp3ea, xn-----btdaafne4a7azpoaiq4byba, xn----ymcaaeld1a4a6onahp2b7aa, xn--mgbaadjcy1a8mmago8da, xn----ymcaaeld1a4a6onahp1b8aa, xn--mgbaadjcy1a8mmago9a5aa
notBefore: 2018-05-14T17:53:16.418Z
notAfter: 2022-08-21T08:59:34.305Z
-----BEGIN ENCODED SMD-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHNtZDpzaWduZWRNYXJrIHht
bG5zOnNtZD0idXJuOmlldGY6cGFyYW1zOnhtbDpuczpzaWduZWRNYXJrLTEuMCIgaWQ9Il83YWMz
NWQ1MS1mZTgyLTQ5ODYtYTgzMC1iZjg1NDI4MzI1YWMiPjxzbWQ6aWQ+MDAwMDAwOTAxNTI2MzIw
Mzk2NDE4LTY1NTM1PC9zbWQ6aWQ+PHNtZDppc3N1ZXJJbmZvIGlzc3VlcklEPSI2NTUzNSI+PHNt
ZDpvcmc+SUNBTk4gVE1DSCBURVNUSU5HIFRNVjwvc21kOm9yZz48c21kOmVtYWlsPm5vdGF2YWls
YWJsZUBleGFtcGxlLmNvbTwvc21kOmVtYWlsPjxzbWQ6dXJsPnd3dy5leGFtcGxlLmNvbTwvc21k
OnVybD48c21kOnZvaWNlPiszMi4yMDAwMDAwMDwvc21kOnZvaWNlPjwvc21kOmlzc3VlckluZm8+
PHNtZDpub3RCZWZvcmU+MjAxOC0wNS0xNFQxNzo1MzoxNi40MThaPC9zbWQ6bm90QmVmb3JlPjxz
bWQ6bm90QWZ0ZXI+MjAyMi0wOC0yMVQwODo1OTozNC4zMDVaPC9zbWQ6bm90QWZ0ZXI+PG1hcms6
bWFyayB4bWxuczptYXJrPSJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOm1hcmstMS4wIj48bWFyazp0
cmFkZW1hcms+PG1hcms6aWQ+MDAwMTQyMTUwMzMwNTI5OTE1MDMzMDUyOTktMTwvbWFyazppZD48
bWFyazptYXJrTmFtZT7Yp9mE2KfYrtiq2KjYp9ixICZhbXA7INmE2KrZgtmK2YrZhTwvbWFyazpt
YXJrTmFtZT48bWFyazpob2xkZXIgZW50aXRsZW1lbnQ9Im93bmVyIj48bWFyazpuYW1lPtmF2YfZ
htiv2LMg2KfZhNmF2LnZhNmI2YXYp9iq2YrYqTwvbWFyazpuYW1lPjxtYXJrOm9yZz7Yp9iu2KrY
qNin2LE8L21hcms6b3JnPjxtYXJrOmFkZHI+PG1hcms6c3RyZWV0Ptis2LnZgdixINin2KjZhiDY
s9mK2YbYp9ihIDc1PC9tYXJrOnN0cmVldD48bWFyazpjaXR5PtmF2YPZhtin2LM8L21hcms6Y2l0
eT48bWFyazpwYz4yOTAwPC9tYXJrOnBjPjxtYXJrOmNjPk1BPC9tYXJrOmNjPjwvbWFyazphZGRy
PjxtYXJrOnZvaWNlPisyMTIuNTIyNTM5MDQwPC9tYXJrOnZvaWNlPjxtYXJrOmZheD4rMjEyLjUy
MjUzOTA0MTwvbWFyazpmYXg+PG1hcms6ZW1haWw+aW5mb0BleGFtcGxlLmV4YW1wbGU8L21hcms6
ZW1haWw+PC9tYXJrOmhvbGRlcj48bWFyazpqdXJpc2RpY3Rpb24+TUE8L21hcms6anVyaXNkaWN0
aW9uPjxtYXJrOmNsYXNzPjE1PC9tYXJrOmNsYXNzPjxtYXJrOmxhYmVsPnhuLS0tLS0tbnplYWFn
cGY3YXpiMnBwYWpyM2ZhPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS1idGRhYWZuZTRh
N2F6cG9haXE4ZWE8L21hcms6bGFiZWw+PG1hcms6bGFiZWw+eG4tLS0teW1jYWFlbGQxYTRhNm9u
YWhwM2VhPC9tYXJrOmxhYmVsPjxtYXJrOmxhYmVsPnhuLS0tLS1idGRhYWZuZTRhN2F6cG9haXE0
YnliYTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tLS15bWNhYWVsZDFhNGE2b25haHAyYjdh
YTwvbWFyazpsYWJlbD48bWFyazpsYWJlbD54bi0tbWdiYWFkamN5MWE4bW1hZ284ZGE8L21hcms6
bGFiZWw+PG1hcms6bGFiZWw+eG4tLS0teW1jYWFlbGQxYTRhNm9uYWhwMWI4YWE8L21hcms6bGFi
ZWw+PG1hcms6bGFiZWw+eG4tLW1nYmFhZGpjeTFhOG1tYWdvOWE1YWE8L21hcms6bGFiZWw+PG1h
cms6Z29vZHNBbmRTZXJ2aWNlcz7YutmK2KrYp9ixPC9tYXJrOmdvb2RzQW5kU2VydmljZXM+PG1h
cms6cmVnTnVtPjEyMzQ8L21hcms6cmVnTnVtPjxtYXJrOnJlZ0RhdGU+MjAxMy0wMS0wMVQwMDow
MDowMC4wMDBaPC9tYXJrOnJlZ0RhdGU+PC9tYXJrOnRyYWRlbWFyaz48L21hcms6bWFyaz48ZHM6
U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIiBJ
ZD0iXzA5ODIzYjE3LWU5YjQtNGU2My05ZjdjLTVlMjI0ODExZWJjZCI+PGRzOlNpZ25lZEluZm8+
PGRzOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8y
MDAxLzEwL3htbC1leGMtYzE0biMiLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0
cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIvPjxkczpSZWZl
cmVuY2UgVVJJPSIjXzdhYzM1ZDUxLWZlODItNDk4Ni1hODMwLWJmODU0MjgzMjVhYyI+PGRzOlRy
YW5zZm9ybXM+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAv
MDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8+PGRzOlRyYW5zZm9ybSBBbGdvcml0aG09
Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvZHM6VHJhbnNmb3Jt
cz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94
bWxlbmMjc2hhMjU2Ii8+PGRzOkRpZ2VzdFZhbHVlPkJsOTBqOE5QMENpWExpTGZ3bGw1czZwUFo0
RkhndnNERGdONmpsU0VZdUk9PC9kczpEaWdlc3RWYWx1ZT48L2RzOlJlZmVyZW5jZT48ZHM6UmVm
ZXJlbmNlIFVSST0iI19kYmJkODUzMy1mM2JhLTRlYmItODIwOC00ZTQyNjA3OWZkYTgiPjxkczpU
cmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAx
LzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2VzdE1ldGhvZCBBbGdv
cml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPjxkczpEaWdl
c3RWYWx1ZT5NZGhmNjBmN0l4c0t6ODVLemVvbndtRlg5SGR1ZnBUZDhiYmNpODJhWkhZPTwvZHM6
RGlnZXN0VmFsdWU+PC9kczpSZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVW
YWx1ZSBJZD0iX2I5YmJmYjU0LWVjNWEtNDA2Mi04OGE2LTlmNDg4YjY1ZjJhNyI+cjc5R08xZGFy
dDBuZ1lFak8rZkNCTzVKZHU2K0hWdDA3WDMvc2V3VUhHOG5tNmF3NGJESEM0aG0vcEMrSmR2NkpT
NkJLN2I1YTF3MQpTbWRzSUxxWmxMdmF4K0ZBTmlCQzRaVXpFZUN2cHFqZ2hFTThJN3g0MWdhUnFj
aDh3Y0kyUTdvSEdNbVo3N2crSU1PdHJBa0taZkxOCjV4c0RZbFkwUTVCWEJoNmVES0V5VHFwMmtJ
dGc3WVlJZDgvWGNYbldVQTRONDY3RE14b0RyekdJbFI0ZFpmMWMvdzZ3WXhMTFdMak0KZThpYzcr
cGpRMmFXVjNpQ25pZ2pnQlIvendQMHNzZEwxUGhoNVptUU5PSE9TZ2tEN2c2U2pzRUlJRkhRblZl
ZGVxaHB0cXBtRjVBYgpzdDFwWk1BWS8rRVIwY2NoMGFmSjRBZURVRjdpYVBWODM1cTEwZz09PC9k
czpTaWduYXR1cmVWYWx1ZT48ZHM6S2V5SW5mbyBJZD0iX2RiYmQ4NTMzLWYzYmEtNGViYi04MjA4
LTRlNDI2MDc5ZmRhOCI+PGRzOlg1MDlEYXRhPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJRk96Q0NC
Q09nQXdJQkFnSWdMckFiZXZvYWU1MnkzZjZDMnRCMFNuM3A3WEptMFQwMkZvZ3hLQ2ZOaFpjd0RR
WUpLb1pJaHZjTgpBUUVMQlFBd2ZERUxNQWtHQTFVRUJoTUNWVk14UERBNkJnTlZCQW9UTTBsdWRH
VnlibVYwSUVOdmNuQnZjbUYwYVc5dUlHWnZjaUJCCmMzTnBaMjVsWkNCT1lXMWxjeUJoYm1RZ1Ru
VnRZbVZ5Y3pFdk1DMEdBMVVFQXhNbVNVTkJUazRnVkhKaFpHVnRZWEpySUVOc1pXRnkKYVc1bmFH
OTFjMlVnVUdsc2IzUWdRMEV3SGhjTk1UZ3dNakk0TURBd01EQXdXaGNOTWpNd016QXhNak0xT1RV
NVdqQ0JqekVMTUFrRwpBMVVFQmhNQ1FrVXhJREFlQmdOVkJBZ1RGMEp5ZFhOelpXeHpMVU5oY0ds
MFlXd2dVbVZuYVc5dU1SRXdEd1lEVlFRSEV3aENjblZ6CmMyVnNjekVSTUE4R0ExVUVDaE1JUkdW
c2IybDBkR1V4T0RBMkJnTlZCQU1UTDBsRFFVNU9JRlJOUTBnZ1FYVjBhRzl5YVhwbFpDQlUKY21G
a1pXMWhjbXNnVUdsc2IzUWdWbUZzYVdSaGRHOXlNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9D
QVE4QU1JSUJDZ0tDQVFFQQp4bHAzS3BZSFgzV3lBc0ZoU2szTHdXZm5HbHhuVURGcUZaQTNVb3VN
WWovWGlnYk1rTmVFWElqbGtST0tUNE9QR2ZSeC9MQXlSbFFRCmpDTXY0cWhia2NYMXA3YXI2M2Zs
cTRTWk5WY2wxNWw3aDB1VDU4RnpTZm5sejB1NXJrSGZKSW1ENDMrbWFQLzhndjM2RlIyN2pXOFIK
OXdZNGhrK1dzNElCMGlGU2Q4U1h2MUtyOHcvSm1NUVNEa2l1RytSZklpdWJ3US9meTdFa2o1UVdo
UFp3K21NeE5LbkhVTHkzeFl6MgpMd1ZmZnRqd1V1ZWFjdnFOUkNrTVhsQ2xPQURxZlQ4b1Nab2VE
WGVoSHZsUHNMQ2VtR0JvVEt1cnNrSVM2OUYweVBFSDVnemUwSCtmCjhGUk9zSW9LU3NWUTM0QjRT
L2pvRTY3bnBzSlBUZEtzTlBKVHlRSURBUUFCbzRJQmt6Q0NBWTh3REFZRFZSMFRBUUgvQkFJd0FE
QWQKQmdOVkhRNEVGZ1FVb0ZwWTc2cDV5b05EUkd0UXB6VnVSODFVV1Ewd2djWUdBMVVkSXdTQnZq
Q0J1NEFVdzYwK3B0WVJBRVdBWERwWApTb3B0M0RFTm5uR2hnWUNrZmpCOE1Rc3dDUVlEVlFRR0V3
SlZVekU4TURvR0ExVUVDaE16U1c1MFpYSnVaWFFnUTI5eWNHOXlZWFJwCmIyNGdabTl5SUVGemMy
bG5ibVZrSUU1aGJXVnpJR0Z1WkNCT2RXMWlaWEp6TVM4d0xRWURWUVFERXlaSlEwRk9UaUJVY21G
a1pXMWgKY21zZ1EyeGxZWEpwYm1kb2IzVnpaU0JRYVd4dmRDQkRRWUlnTHJBYmV2b2FlNTJ5M2Y2
QzJ0QjBTbjNwN1hKbTBUMDJGb2d4S0NmTgpoWGt3RGdZRFZSMFBBUUgvQkFRREFnZUFNRFFHQTFV
ZEh3UXRNQ3N3S2FBbm9DV0dJMmgwZEhBNkx5OWpjbXd1YVdOaGJtNHViM0puCkwzUnRZMmhmY0ds
c2IzUXVZM0pzTUZFR0ExVWRJQVJLTUVnd0VBWU9Ld1lCQkFHQ3lSc0JCWU03REFvd05BWUlLd1lC
QlFVSEFnRXcKS0RBbUJnZ3JCZ0VGQlFjQ0FSWWFhSFIwY0hNNkx5OWpZUzVwWTJGdWJpNXZjbWN2
Y0dsc2IzUXdEUVlKS29aSWh2Y05BUUVMQlFBRApnZ0VCQUF1aloySWNSMkRWcnRhUnJBNTllTllD
bDR4Y3NKTXU4RFFDSHYyOGZUZmkvQmlaWTRJcjdGOWtGeTk2RDdPWjhvTFk1empmCjRkSHhGd0hQ
cUg4RGg2Sldzelh1SFcxWmEzWG1sMFBhSHhDV1JTMFhvbDhXc0hIcE55Z2pNQllmSjBvZFZNODg1
VFoxRWw5U2l1RUgKbnluRkJnU21pRmM5OXVRZC9ZRFJadUd2L0EwSHl2N3lSOXRrTEVkRDNBMXVO
SkJXNFArSEpHcGRLa1lMMVE1clU3K29IVlB0TUtLSQozaUZrVUVzYk80NUFWZDd2UC9qLzdKdEFa
UGI2a29PVjVsWmkySDFSTGNjR3d6ZGV6bmhKZ2QwTjlvYmIwdm5FNDEvVVNXYWZkV1JaClZHa3dQ
dXFUaGw3c0N0enJKSDhYWTB4Y3VtK2NmTHgyRUFJd1VuT2NhYjQ9PC9kczpYNTA5Q2VydGlmaWNh
dGU+PC9kczpYNTA5RGF0YT48L2RzOktleUluZm8+PC9kczpTaWduYXR1cmU+PC9zbWQ6c2lnbmVk
TWFyaz4=
-----END ENCODED SMD-----

Some files were not shown because too many files have changed in this diff Show More