From 668536212a244b2419731747e99fa54bb560fbc9 Mon Sep 17 00:00:00 2001 From: MattiSG Date: Thu, 20 Jun 2024 15:50:25 +0000 Subject: [PATCH] deploy: f6ac746545e2d99991118c3f92a1e2ef42299d87 --- api/collection/index.html | 4 +- api/federation/index.html | 4 +- api/node/index.html | 4 +- collections/create/index.html | 4 +- collections/federation/index.html | 4 +- collections/governance/index.html | 4 +- collections/metadata/index.html | 4 +- contributing-terms/index.html | 208 +----------------- ...419cc98391447c9c8f16cf306ed80d0b8af6f.css} | 2 +- design-principles/index.html | 4 +- en/sitemap.xml | 2 +- fr/index.html | 2 +- guidelines/choosing-selectors/index.html | 6 +- guidelines/declaring/index.html | 6 +- guidelines/index.xml | 2 +- guidelines/reviewing/index.html | 8 +- guidelines/targeting/index.html | 4 +- index.html | 6 +- index.xml | 30 ++- jsdoc/Record.html | 2 +- jsdoc/archivist_extract_index.js.html | 2 +- jsdoc/archivist_fetcher_index.js.html | 2 +- jsdoc/archivist_recorder_record.js.html | 2 +- ...st_recorder_repositories_interface.js.html | 2 +- jsdoc/collection-api_routes_services.js.html | 2 +- jsdoc/collection-api_routes_versions.js.html | 2 +- jsdoc/global.html | 2 +- jsdoc/index.html | 2 +- memos/copywriting-reference/index.html | 4 +- memos/how-to-publish/index.html | 4 +- navigate-history/index.html | 8 +- subscribe-rss/index.html | 8 +- terms/declarations-maintenance/index.html | 49 +++++ .../index.html | 8 + .../index.html | 7 + terms/how-to-navigate-history/index.html | 8 + terms/index.xml | 11 + terms/reference/index.html | 161 ++++++++++++++ terms/tracking-new-terms/index.html | 11 + 39 files changed, 324 insertions(+), 281 deletions(-) rename css/{loader.min.ca92c1a7804f2e7bd9ab5796a635b95c6ec04243851c23aa4845f82931dd4c0c.css => loader.min.ec497ac5595176f384307b2f0b9419cc98391447c9c8f16cf306ed80d0b8af6f.css} (90%) create mode 100644 terms/declarations-maintenance/index.html create mode 100644 terms/how-to-add-terms-using-with-the-graphical-contribution-interface/index.html create mode 100644 terms/how-to-be-notified-of-terms-changes/index.html create mode 100644 terms/how-to-navigate-history/index.html create mode 100644 terms/index.xml create mode 100644 terms/reference/index.html create mode 100644 terms/tracking-new-terms/index.html diff --git a/api/collection/index.html b/api/collection/index.html index e2e48c3f..188d5e1c 100644 --- a/api/collection/index.html +++ b/api/collection/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Collection

Collection Web API [Beta]

As Open Terms Archive is decentralised, each instance embarks its own API. The documentation relevant to the specific version of the engine on that instance is provided on that instance itself.

The Collection API exposes JSON data over HTTP. Its OpenAPI specification can be found at http://localhost:<port>/<basePath>/<API version>/docs.

That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.

For example, the documentation of the Demo collection is publicly available for exploration.


+Close

Collection Web API [Beta]

As Open Terms Archive is decentralised, each instance embarks its own API. The documentation relevant to the specific version of the engine on that instance is provided on that instance itself.

The Collection API exposes JSON data over HTTP. Its OpenAPI specification can be found at http://localhost:<port>/<basePath>/<API version>/docs.

That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.

For example, the documentation of the Demo collection is publicly available for exploration.


\ No newline at end of file diff --git a/api/federation/index.html b/api/federation/index.html index 9cc8c04a..94c17a9c 100644 --- a/api/federation/index.html +++ b/api/federation/index.html @@ -1,8 +1,8 @@ -Open Terms Archive - Federation

Federation API

Open Terms Archive is a decentralised system that tracks collections of services’ terms across multiple servers. Each collection operates its own API, and the Federation API unifies search and discovery across collections, fostering collaboration with external applications.

The Federation API exposes JSON data over HTTP. Its documentation is provided in a dedicated, interactive interface.

That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.

Beta

This API is offered as a preview, based on a first use case defined with partner ToS;DR. Unexpected problems or missing functionality may arise. Please provide feedback through issues in the dedicated repository.

Source code

The codebase for the Federation API is available on github.com/OpenTermsArchive/federation-api.

Configuring

The default configuration can be found in config/default.json. The full reference is given below. In the vast majority of cases, the default values should be sufficient and only the email sending data should be changed.

{
+Close

Federation API

Open Terms Archive is a decentralised system that tracks collections of services’ terms across multiple servers. Each collection operates its own API, and the Federation API unifies search and discovery across collections, fostering collaboration with external applications.

The Federation API exposes JSON data over HTTP. Its documentation is provided in a dedicated, interactive interface.

That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.

Beta

This API is offered as a preview, based on a first use case defined with partner ToS;DR. Unexpected problems or missing functionality may arise. Please provide feedback through issues in the dedicated repository.

Source code

The codebase for the Federation API is available on github.com/OpenTermsArchive/federation-api.

Configuring

The default configuration can be found in config/default.json. The full reference is given below. In the vast majority of cases, the default values should be sufficient and only the email sending data should be changed.

{
   "@opentermsarchive/federation-api": {
     "logger": { // Logging mechanism to be notified upon error
       "smtp": {
diff --git a/api/node/index.html b/api/node/index.html
index c3729b70..4005f1f6 100644
--- a/api/node/index.html
+++ b/api/node/index.html
@@ -1,8 +1,8 @@
-Open Terms Archive - Node

Node.js API [Beta]

As a Node module dependency, the engine exposes a JavaScript API that can be called in your own code. The following modules are available.

fetch

The fetch module gets the MIME type and content of a document from its URL

import fetch from '@opentermsarchive/engine/fetch';
+Close

Node.js API [Beta]

As a Node module dependency, the engine exposes a JavaScript API that can be called in your own code. The following modules are available.

fetch

The fetch module gets the MIME type and content of a document from its URL

import fetch from '@opentermsarchive/engine/fetch';
 

Documentation on how to use fetch is provided as JSDoc.

Headless browser management

If you pass the executeClientScripts option to fetch, a headless browser will be used to download and execute the page before serialising its DOM. For performance reasons, the starting and stopping of the browser is your responsibility to avoid instantiating a browser on each fetch. Here is an example on how to use this feature:

import fetch, { launchHeadlessBrowser, stopHeadlessBrowser } from '@opentermsarchive/engine/fetch';
 
 await launchHeadlessBrowser();
diff --git a/collections/create/index.html b/collections/create/index.html
index b2becee3..c6a4e3bf 100644
--- a/collections/create/index.html
+++ b/collections/create/index.html
@@ -1,8 +1,8 @@
-Open Terms Archive - Creating a collection

Creating a collection

You are considering creating a new collection to track terms with Open Terms Archive? Amazing!

Define metadata

First of all, define the metadata of the collection you would like to create.

Check existing collections

Now that you have a clear idea what you would like to track, double-check that there are no existing federated collections that you could contribute to. If you have a doubt about whether some terms you want to track would fit a collection, reach out to the collection maintainers.

If no existing collection could be a good host for the terms you would like to track, then it is relevant to create your own.

Inform the community

Starting a new collection is an exciting endeavour, and would strongly benefit from the support of the community who already maintains existing collections. It is strongly recommended to share your intention to create a new collection as early as possible in the process, to get support and identify potential partners.

You can inform the community by posting on the instant messaging system, or sending an email to the core team.

Define governance

Setting up and maintaining a collection over time needs fulfilling certain tasks on a regular basis. These tasks are handled through roles. To make sure that all these roles are covered, define the governance of your collection.

At any time, feel free to ask for help or partners in the community.

Create repositories

Collections rely on three git repositories being set up to hold the data.

The instructions below assume the usage of GitHub to host repositories. If you don’t use GitHub, try to set up the equivalent metadata in your git hosting platform. Contributions to the documentation to make it independent from GitHub are very welcome!

Declarations

Create the collection declarations repository by using the demo-declarations repository as template.

  • Go to the demo-declarations repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-declarations. For example: pga-declarations.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Click on the little cogwheel icon next to the “About” block.
  • Set the description to “Declarations for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://opentermsarchive.org, or any other relevant dedicated website.
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Releases”, “Packages” and “Deployments”.

Define repository settings

These settings ease the whole contribution process.

  • In “General → Features”
    • Disable “Wikis”.
    • Disable “Projects”.
  • In “General → Pull Requests”
    • Check only the “Allow squash merging” option, and set it to “Default to pull request title and commit details”.
    • Enable “Allow auto-merge”.
    • Enable “Automatically delete head branches”.
  • In “Branches”
    • Add a branch protection rule for main.
      • Check “Require a pull request before merging”, check “Require approvals” and set “Required number of approvals before merging” to 1.
      • Check “Require status checks to pass before merging” and add validate_modified_declarations and validate_schema as required status checks.
  • In “Actions → General → Actions permissions”
    • Select “Allow all actions and reusable workflows”.

Remove default labels

Issues labels will be added by the engine as problems are encountered when tracking. The default labels offered by GitHub, such as question or wontfix, are relevant for software development but less so for the process prescribed by Open Terms Archive.

  • Remove all default labels.

Update README

  • Update the README file with proper metadata: topic, maintainers, jurisdictions, languages…

Snapshots

Create the snapshots repository by using the demo-snapshots repository as template:

  • Go to the demo-snapshots repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-snapshots.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Set the description: “Documents snapshots for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://opentermsarchive.org.
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Releases”, “Packages” and “Deployments”.

Define repository settings

These settings aim at minimising the otherwise overwhelming amount of information and click targets.

  • In “General → Features”
    • Uncheck “Wikis”.
    • Uncheck “Issues”.
    • Uncheck “Discussions”.
    • Uncheck “Projects”.
  • In “Actions → General → Actions permissions”
    • Select “Disable actions”.

Versions

Create the versions repository by using the demo-versions repository as template:

  • Go to the demo-versions repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-versions.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Set the description: “Terms versions for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://docs.opentermsarchive.org/navigate-history/
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Packages”.
  • Uncheck “Deployments”.

Define repository settings

These settings aim at minimising the otherwise overwhelming amount of information and click targets.

  • In “General → Features”
    • Uncheck “Wikis”.
    • Uncheck “Issues”.
    • Uncheck “Discussions”.
    • Uncheck “Projects”.
  • In “Actions → General → Actions permissions”
    • Select “Disable actions”.

Update README

  • Update the README file with proper metadata.

Set up GitHub teams

For collections to be included in the Open Terms Archive organisation only. For third parties, handle rights however you see fit.

  • Create a new collection team
  • Give it the name of the collection
  • Set as avatar the collection icon from the website
  • Set as description: “Maintainers of the <collection_name> collection”
  • Add selected members to the team
  • Add the declarations repository to the collection team, with “Maintain” access rights
  • Add the snapshots repository to the collection team, with “Triage” access rights (giving them more would enable them to corrupt data)
  • Add the versions repository to the collection team, with “Triage” access rights (giving them more would enable them to corrupt data)
  • Add the declarations, snapshots and versions repositories to the Bots team with “Write” access

Set up deployment

Check server configuration

Before proceeding with deployment, ensure that the server meets the following requirements:

  • Verify that the server provides an Ed25519 fingerprint for its SSH host key:

    • Retrieve the Ed25519 SSH host key from the server ssh-keyscan -t ed25519 <server_address>
    • If the server has an Ed25519 SSH host key defined, the output will display the corresponding fingerprint. It will look something like this:
      <server_address> ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJM6fCKWkiKv+uysoHsklIAuUOH6Dpc3crzHxk7GwrD
    +Close

Creating a collection

You are considering creating a new collection to track terms with Open Terms Archive? Amazing!

Define metadata

First of all, define the metadata of the collection you would like to create.

Check existing collections

Now that you have a clear idea what you would like to track, double-check that there are no existing federated collections that you could contribute to. If you have a doubt about whether some terms you want to track would fit a collection, reach out to the collection maintainers.

If no existing collection could be a good host for the terms you would like to track, then it is relevant to create your own.

Inform the community

Starting a new collection is an exciting endeavour, and would strongly benefit from the support of the community who already maintains existing collections. It is strongly recommended to share your intention to create a new collection as early as possible in the process, to get support and identify potential partners.

You can inform the community by posting on the instant messaging system, or sending an email to the core team.

Define governance

Setting up and maintaining a collection over time needs fulfilling certain tasks on a regular basis. These tasks are handled through roles. To make sure that all these roles are covered, define the governance of your collection.

At any time, feel free to ask for help or partners in the community.

Create repositories

Collections rely on three git repositories being set up to hold the data.

The instructions below assume the usage of GitHub to host repositories. If you don’t use GitHub, try to set up the equivalent metadata in your git hosting platform. Contributions to the documentation to make it independent from GitHub are very welcome!

Declarations

Create the collection declarations repository by using the demo-declarations repository as template.

  • Go to the demo-declarations repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-declarations. For example: pga-declarations.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Click on the little cogwheel icon next to the “About” block.
  • Set the description to “Declarations for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://opentermsarchive.org, or any other relevant dedicated website.
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Releases”, “Packages” and “Deployments”.

Define repository settings

These settings ease the whole contribution process.

  • In “General → Features”
    • Disable “Wikis”.
    • Disable “Projects”.
  • In “General → Pull Requests”
    • Check only the “Allow squash merging” option, and set it to “Default to pull request title and commit details”.
    • Enable “Allow auto-merge”.
    • Enable “Automatically delete head branches”.
  • In “Branches”
    • Add a branch protection rule for main.
      • Check “Require a pull request before merging”, check “Require approvals” and set “Required number of approvals before merging” to 1.
      • Check “Require status checks to pass before merging” and add validate_modified_declarations and validate_schema as required status checks.
  • In “Actions → General → Actions permissions”
    • Select “Allow all actions and reusable workflows”.

Remove default labels

Issues labels will be added by the engine as problems are encountered when tracking. The default labels offered by GitHub, such as question or wontfix, are relevant for software development but less so for the process prescribed by Open Terms Archive.

  • Remove all default labels.

Update README

  • Update the README file with proper metadata: topic, maintainers, jurisdictions, languages…

Snapshots

Create the snapshots repository by using the demo-snapshots repository as template:

  • Go to the demo-snapshots repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-snapshots.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Set the description: “Documents snapshots for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://opentermsarchive.org.
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Releases”, “Packages” and “Deployments”.

Define repository settings

These settings aim at minimising the otherwise overwhelming amount of information and click targets.

  • In “General → Features”
    • Uncheck “Wikis”.
    • Uncheck “Issues”.
    • Uncheck “Discussions”.
    • Uncheck “Projects”.
  • In “Actions → General → Actions permissions”
    • Select “Disable actions”.

Versions

Create the versions repository by using the demo-versions repository as template:

  • Go to the demo-versions repository
  • Click on the “Use this template” dropdown and select “Create a new repository”
  • Set the repository name to <collection_id>-versions.
  • When redirected to the newly generated repository, wait a minute or two for the automatic setup to run. You can check the status of the first-time-setup GitHub action to make sure that everything ran fine.

Fill the “About” section

  • Set the description: “Terms versions for <collection_name>. Maintained by <maintainer>.”
  • Set website to https://docs.opentermsarchive.org/terms/how-to-navigate-history/
  • Add the following tags: terms-of-service, terms-of-service-agreements, terms-and-conditions, open-terms-archive.
  • Uncheck “Packages”.
  • Uncheck “Deployments”.

Define repository settings

These settings aim at minimising the otherwise overwhelming amount of information and click targets.

  • In “General → Features”
    • Uncheck “Wikis”.
    • Uncheck “Issues”.
    • Uncheck “Discussions”.
    • Uncheck “Projects”.
  • In “Actions → General → Actions permissions”
    • Select “Disable actions”.

Update README

  • Update the README file with proper metadata.

Set up GitHub teams

For collections to be included in the Open Terms Archive organisation only. For third parties, handle rights however you see fit.

  • Create a new collection team
  • Give it the name of the collection
  • Set as avatar the collection icon from the website
  • Set as description: “Maintainers of the <collection_name> collection”
  • Add selected members to the team
  • Add the declarations repository to the collection team, with “Maintain” access rights
  • Add the snapshots repository to the collection team, with “Triage” access rights (giving them more would enable them to corrupt data)
  • Add the versions repository to the collection team, with “Triage” access rights (giving them more would enable them to corrupt data)
  • Add the declarations, snapshots and versions repositories to the Bots team with “Write” access

Set up deployment

Check server configuration

Before proceeding with deployment, ensure that the server meets the following requirements:

  • Verify that the server provides an Ed25519 fingerprint for its SSH host key:

    • Retrieve the Ed25519 SSH host key from the server ssh-keyscan -t ed25519 <server_address>
    • If the server has an Ed25519 SSH host key defined, the output will display the corresponding fingerprint. It will look something like this:
      <server_address> ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJM6fCKWkiKv+uysoHsklIAuUOH6Dpc3crzHxk7GwrD
     
    • If no output is displayed or if the output does not include an Ed25519 SSH host key fingerprint, it indicates that the server does not have an Ed25519 SSH host key defined. Here’s an example of the output when no Ed25519 SSH host key is defined:
      # <server_address> SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.3
       <server_address> ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDqruXk1P6vIVvN2i6ffLO6TlYCcC6lqF3oBYT7sC+nfIb5C9HYsUFWptSxohOy41wV3AbSzjHqEjxCt9MeJ4HXrLItti8Qr3fRBYgs45+L44bMZ9sA/EO+YiXQU9cQJb2qjK5EYQyFyEnGUMbh+zzRiCRQTI0A2nlnJ9zWQJr/4jIrlNJ6N0lV1GQzN/iIpCJto6ZmhbEgW5W3H+zB5qj72uKoyLlm8Lh+AF5ljtTnOuXgrh2nN6EN1hjRf52VtQZ93guIBkn5+riZ3gYYp3fl4sYbIAZRRs5rOcyFk9d/jo+kBw/Pxht4KABVHJHMPQ9cI2Fn2VbEOvZ+RrWLXc5Am3qwbUWpqYmp7n7wwdTrkYeCBMsXk7xQl5TJh+5Rkr6k0YRkcbvP+J+I1TJwob1DOyWBpRA3v9LYimEmy9eheQuKYzH5sQ/0r/7ZwhBL5/lB5kpv3kmwA7DZy1J5UbgChtSey3Du0N+6p/vgfybIgcZD5Csz8+dF3c+gZBCfRd4XpKgLoxLPZO69tM8/3z/3W0gOfXgEw6QKwJ6KoFXeBdRG9c/CCsR8dF3iIeZYWZvj+8nC/Y7hF6Dedr/6CHc0O4xwqE0GQzF3YUZI7HcqjxIIFsIsG+loUGWYB7a0HHn0FrAq79Q==
       <server_address> ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLe8sKzXq4KReWp0Dz1lC8AKOcYNtPuk7GOqJRSVGkG1xRhP94gReTp7S1WnF6LgFt3vlC2k62BkSoXgryY3+8=
    diff --git a/collections/federation/index.html b/collections/federation/index.html
    index a6dccefe..2a4464ac 100644
    --- a/collections/federation/index.html
    +++ b/collections/federation/index.html
    @@ -1,7 +1,7 @@
    -Open Terms Archive - Federation

    Federation

    Open Terms Archive is a decentralised system. It aims at enabling any entity set up their own collections and track terms on their own.

    In order to maximise discoverability, collaboration and political power, public collections are federated within a single ecosystem. This makes their data mutually discoverable and enables mutualising effort.

    Benefits

    A collection that joins the federation enjoys the following benefits:

    1. Visibility on the Open Terms Archive website lists of collections and datasets.
    2. Access to the Open Terms Archive GitHub organisation, administered by the Open Terms Archive core team.
    3. Collection logo provided by the Open Terms Archive core team.
    4. Referencing in the official collections list, enabling off-the-shelf discovery in the Federation API.
    5. Referencing in the official datasets list, providing visibility to analysts.
    6. Dedicated channel on the Open Terms Archive instant messaging system.
    7. API uptime tracking.
    8. Public announcement through all Open Terms Archive communication channels upon joining.

    Criteria

    A collection can join the Open Terms Archive federation if it abides by the following quality criteria:

    1. Clearly defined collection metadata.
    2. Clearly defined collection governance.
    3. The vast majority of versions are readable, as evidenced by a sample assessment.
    4. Frequency of at least one track a day, as evidenced by snapshots.
    5. Public and open-licensed declarations, as evidenced by the LICENSE file in the declarations repository.
    6. Public and open-licensed snapshots, as evidenced by the LICENSE file in the snapshots repository.
    7. Public and open-licensed versions, as evidenced by the LICENSE file in the versions repository.
    8. Regular, public, and open-licensed dataset releases, as evidenced by the LICENSE file in the datasets.
    9. Publicly accessible API with median response time under 20ms, as evidenced by uptime tracking logs.
    10. Abide by all Open Terms Archive software and data licenses.

    How to join

    An official request for joining the federation can be sent by the collection administrator or curator to the core team over email, GitHub or instant messages. That request should contain all necessary content or links that enable assessing the criteria.

    The core team will confirm reception of the request and assess the criteria within 4 weeks. The result of the assessment will be provided to the requester through the same means the request was sent, along with a positive decision or a list of improvements that need to be done before a new request can be sent.

    Once a positive decision has been issued, the core team will provide the requester with a timeline for joining the federation, on which they will jointly agree.

    Disclaimer

    Please note that establishing the federation is an ongoing effort. While criteria are assessed and refined to strike the right balance between accessibility and quality, the Open Terms Archive core team is responsible for assessing which collections may join the federation, and has the right to update the criteria as requests for joining are made.

    The core team has the right to re-assess the federated status of any collection at any given time. In case the federated status of a collection is changed, the collection administrator will be informed immediately, and if possible before the action is made.

    +Close

Federation

Open Terms Archive is a decentralised system. It aims at enabling any entity set up their own collections and track terms on their own.

In order to maximise discoverability, collaboration and political power, public collections are federated within a single ecosystem. This makes their data mutually discoverable and enables mutualising effort.

Benefits

A collection that joins the federation enjoys the following benefits:

  1. Visibility on the Open Terms Archive website lists of collections and datasets.
  2. Access to the Open Terms Archive GitHub organisation, administered by the Open Terms Archive core team.
  3. Collection logo provided by the Open Terms Archive core team.
  4. Referencing in the official collections list, enabling off-the-shelf discovery in the Federation API.
  5. Referencing in the official datasets list, providing visibility to analysts.
  6. Dedicated channel on the Open Terms Archive instant messaging system.
  7. API uptime tracking.
  8. Public announcement through all Open Terms Archive communication channels upon joining.

Criteria

A collection can join the Open Terms Archive federation if it abides by the following quality criteria:

  1. Clearly defined collection metadata.
  2. Clearly defined collection governance.
  3. The vast majority of versions are readable, as evidenced by a sample assessment.
  4. Frequency of at least one track a day, as evidenced by snapshots.
  5. Public and open-licensed declarations, as evidenced by the LICENSE file in the declarations repository.
  6. Public and open-licensed snapshots, as evidenced by the LICENSE file in the snapshots repository.
  7. Public and open-licensed versions, as evidenced by the LICENSE file in the versions repository.
  8. Regular, public, and open-licensed dataset releases, as evidenced by the LICENSE file in the datasets.
  9. Publicly accessible API with median response time under 20ms, as evidenced by uptime tracking logs.
  10. Abide by all Open Terms Archive software and data licenses.

How to join

An official request for joining the federation can be sent by the collection administrator or curator to the core team over email, GitHub or instant messages. That request should contain all necessary content or links that enable assessing the criteria.

The core team will confirm reception of the request and assess the criteria within 4 weeks. The result of the assessment will be provided to the requester through the same means the request was sent, along with a positive decision or a list of improvements that need to be done before a new request can be sent.

Once a positive decision has been issued, the core team will provide the requester with a timeline for joining the federation, on which they will jointly agree.

Disclaimer

Please note that establishing the federation is an ongoing effort. While criteria are assessed and refined to strike the right balance between accessibility and quality, the Open Terms Archive core team is responsible for assessing which collections may join the federation, and has the right to update the criteria as requests for joining are made.

The core team has the right to re-assess the federated status of any collection at any given time. In case the federated status of a collection is changed, the collection administrator will be informed immediately, and if possible before the action is made.

\ No newline at end of file diff --git a/collections/governance/index.html b/collections/governance/index.html index 622a0cb2..b282188d 100644 --- a/collections/governance/index.html +++ b/collections/governance/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Governance

Collection governance

Setting up and maintaining a collection needs fulfilling certain tasks. These tasks are handled through roles. Each of these roles can be volunteer or paid, and can be handled by one single or several different entities. The Open Terms Archive core team provides processes and tools to support all of these roles.

Host

This role ensures that a server and internet access is available to run the engine on and fetch the terms, either by using its own infrastructure or renting a server on a hosting provider.

Administrator

This role takes responsibility for ensuring that the engine and associated software tools are functional and up to date.

Curator

This role decides which services and terms are welcome in the collection.

Maintainer

This role guarantees the quality of the tracked versions by reviewing contributions.

Contributor

This role adds declarations and keeps them up to date.

This optional role supports the existence of the collection by funding other roles, providing agent time, political support, or any other relevant non-operational contribution.

+Close

Collection governance

Setting up and maintaining a collection needs fulfilling certain tasks. These tasks are handled through roles. Each of these roles can be volunteer or paid, and can be handled by one single or several different entities. The Open Terms Archive core team provides processes and tools to support all of these roles.

Host

This role ensures that a server and internet access is available to run the engine on and fetch the terms, either by using its own infrastructure or renting a server on a hosting provider.

Administrator

This role takes responsibility for ensuring that the engine and associated software tools are functional and up to date.

Curator

This role decides which services and terms are welcome in the collection.

Maintainer

This role guarantees the quality of the tracked versions by reviewing contributions.

Contributor

This role adds declarations and keeps them up to date.

This optional role supports the existence of the collection by funding other roles, providing agent time, political support, or any other relevant non-operational contribution.

\ No newline at end of file diff --git a/collections/metadata/index.html b/collections/metadata/index.html index ab598aca..bec3eb4c 100644 --- a/collections/metadata/index.html +++ b/collections/metadata/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Metadata

Collection metadata

A collection is defined by the following metadata.

Description

A concise description of the collection topic.

Examples

  • Largest global social media
  • Most used social media in France
  • Dating apps
  • Platforms providing services to businesses

Name

Three words maximum.

Examples

  • Platform Governance Archive
  • France Élections
  • Dating
  • P2B Compliance Assessment

ID

An identifier derived from the collection name that can more easily be referenced in code. Use acronyms and replace spaces with dashes.

Examples

  • pga
  • France-elections
  • dating
  • p2b-compliance

Language

The expected language of the terms in the collection.

Examples

  • English
  • French
  • All EU languages

Jurisdiction

The expected jurisdiction in which the terms in the collection apply.

Examples

  • EU
  • France
  • EEA
  • USA
  • global

Roles

The name, URL and logo of the entities that will take responsibility for each of the necessary governance roles.

+Close

Collection metadata

A collection is defined by the following metadata.

Description

A concise description of the collection topic.

Examples

  • Largest global social media
  • Most used social media in France
  • Dating apps
  • Platforms providing services to businesses

Name

Three words maximum.

Examples

  • Platform Governance Archive
  • France Élections
  • Dating
  • P2B Compliance Assessment

ID

An identifier derived from the collection name that can more easily be referenced in code. Use acronyms and replace spaces with dashes.

Examples

  • pga
  • France-elections
  • dating
  • p2b-compliance

Language

The expected language of the terms in the collection.

Examples

  • English
  • French
  • All EU languages

Jurisdiction

The expected jurisdiction in which the terms in the collection apply.

Examples

  • EU
  • France
  • EEA
  • USA
  • global

Roles

The name, URL and logo of the entities that will take responsibility for each of the necessary governance roles.

\ No newline at end of file diff --git a/contributing-terms/index.html b/contributing-terms/index.html index 2a9eb1de..50346e82 100644 --- a/contributing-terms/index.html +++ b/contributing-terms/index.html @@ -1,207 +1 @@ -Open Terms Archive - Contributing terms

Contributing terms

Tracking new terms

Tracking terms is done by declaring them and the service they are associated with. Such a declaration is achieved by editing JSON files in the declarations folder.

Before adding new terms, open the declarations folder and check if the service you want to track terms for is already declared. If a JSON file with the name of the service is already present, you can jump straight to declaring terms. Otherwise, keep reading!

Declaring a new service

Before declaring a service, you will need to choose the service name and service ID. The service ID will be the name of the JSON file in which the service will be declared. It is a normalised version of the service name.

Service name

The service name is exposed to end users. It should reflect as closely as possible the official service name, as referenced in the terms or “about” pages, so that it can be recognised easily and unambiguously.

  • The service name should be the one used by the service itself, no matter the alphabet, UTF symbols, spaces, and casing.
    • Example: eBay.
    • Example: hi5.
    • Example: LINE.
    • Example: App Store.
    • Example: туту.ру (Cyrillic).
    • Example: 抖音短视频 (Simplified Chinese characters).
  • Domain name extensions (TLDs) are allowed when they are part of the official service name.
    • Example: Booking.com.
    • Example: historielærer.dk.
  • Service names can be prefixed by the provider name, separated by a space, when it would otherwise be too generic or ambiguous.
    • Example: Ads (by Facebook) → Facebook Ads.
    • Example: Analytics (by Google) → Google Analytics.
    • Example: Firebase (by Google) → Firebase.
    • Example: App Store (by Apple) → App Store.

If you have a hard time finding the service name, check out the practical guidelines to find the service name, and feel free to mention your uncertainties in the pull request! We will help you improve the service name if necessary 🙂

Service ID

The service ID is exposed to developers. It should be easy to handle with scripts and other tools.

  • Non-ASCII characters are not supported. Service IDs are derived from the service name by normalising it into ASCII.
    • Example: RTÉRTE.
    • Example: historielærer.dkhistorielaerer.dk.
    • Example: туту.руtutu.ru.
    • Example: 抖音短视频Douyin.
  • Punctuation is supported, except characters that have meaning at filesystem level (:, /, \). These are replaced with a dash (-). The dot (.) is supported, but the service ID cannot be solely . or .. as these have specific meanings in the filesystem.
    • Example: Booking.comBooking.com.
    • Example: Yahoo!Yahoo!.
    • Example: re:startre-start.
    • Example: we://we---.
  • Capitals and spaces are supported. Casing and spacing are expected to reflect the official service name casing and spacing.
    • Example: App StoreApp Store.
    • Example: DeviantArtDeviantArt.

If you have a hard time defining the service ID, check out the practical guidelines to derive the ID from the service name, and feel free to mention your uncertainties in the pull request! We will help you improve the service ID if necessary 🙂

More details on the ID and naming constraints and recommendations can be found in the relevant decision record.

Service declaration

Once you have the service name and the service ID, create a JSON file in the declarations folder named after the ID of the service you want to add, with the following structure:

{
-  "name": "<service name>",
-  "documents": {}
-}
-

Within the documents JSON object, you will now declare terms.


Declaring terms

Terms are declared in a service declaration file, under the documents property.

Most of the time, terms are written in only one source document (for example Facebook Terms of Service) but sometimes terms can be spread across multiple online source documents, and their combination constitutes the terms (for example Facebook Community Guidelines).

Source document

The way in which a source document is obtained is defined in a JSON object:

{
-  "fetch": "The URL where the document can be found",
-  "executeClientScripts": "A boolean to execute client-side JavaScript loaded by the document before accessing the content, in case the DOM modifications are needed to access the content; defaults to false (fetch HTML only)",
-  "filter": "An array of service specific filter function names",
-  "remove": "A CSS selector, a range selector or an array of selectors that target the insignificant parts of the document that has to be removed. Useful to remove parts that are inside the selected parts",
-  "select": "A CSS selector, a range selector or an array of selectors that target the meaningful parts of the document, excluding elements such as headers, footers and navigation"
-}
-
  • For HTML files, fetch and select are mandatory.
  • For PDF files, only fetch is mandatory.

Let’s start by defining these keys!

fetch

This property should simply contain the URL at which the terms you want to track can be downloaded. HTML and PDF files are supported.

When terms coexist in different languages and jurisdictions, please refer to the scope of the collection to which you are contributing. This scope is usually defined in the README.

select

This property is not needed for PDF documents.

Most of the time, contractual documents are exposed as web pages, with a header, a footer, navigation menus, possibly ads… We aim at tracking only the significant parts of the document. In order to achieve that, the select property allows to extract only those parts in the process of converting from snapshot to version.

The select value can be either a CSS selector, a range selector or an array of those.

CSS selectors

CSS selectors should be provided as a string. See the specification for how to write CSS selectors.

For example, the following selector will select the content in the <main> tag of the HTML document:

"select": "main"
-
Range selectors

A range selector is defined with a start and an end CSS selector. It is also necessary to define if the range starts before or after the element targeted by the start CSS selector and to define if it ends before or after the element targeted by the end CSS selector.

To that end, a range selector is a JSON object containing two keys out of the four that are available: startBefore, startAfter, endBefore and endAfter.

{
-  "start[Before|After]": "<CSS selector>",
-  "end[Before|After]": "<CSS selector>"
-}
-

For example, the following selector will select the content between the element targeted by the CSS selector #privacy-eea, including it, and the element targeted by the CSS selector footer, excluding it:

{
-  "startBefore": "#privacy-eea",
-  "endBefore": "footer"
-}
-

remove

This property is optional.

Beyond selecting a subset of a web page, some documents will have non-significant parts in the middle of otherwise significant parts. For example, they can have “go to top” links or banner ads. These can be removed by listing CSS selectors, range selectors or an array of them under the remove property.

Example

Let’s assume a web page contains the following content:

<main>
-  <div class="filter-holder">
-    <select class="filter-options">
-        <option value="https://www.example.com/policies/user-agreement" selected>User Agreement</option>
-        <option value="https://www.example.com/policies/privacy-policy">Privacy Policy</option>
-        <option value="https://www.example.com/policies/content-policy">Content Policy</option>
-        <option value="https://www.example.com/policies/broadcasting-content-policy">Broadcasting Content Policy</option>
-    </select>
-  </div>
-  <h1>User Agreement</h1>
-  <div>…terms…</div>
-</main>
-

If only main is used in select, the following version will be extracted:

User Agreement Privacy Policy Content Policy Broadcasting Content Policy Moderator Guidelines Transparency Report 2017 Transparency Report 2018 Guidelines for Law Enforcement Transparency Report 2019
-
-User Agreement
-==============
-
-…terms…
-

Whereas we want instead:

User Agreement
-==============
-
-…terms…
-

This result can be obtained with the following declaration:

{
-  "fetch": "https://example.com/user-agreement",
-  "select": "main",
-  "remove": ".filter-holder"
-}
-
Complex selectors examples
{
- "fetch": "https://support.google.com/adsense/answer/48182",
- "select": ".article-container",
- "remove": ".print-button, .go-to-top"
-}
-
{
- "fetch": "https://www.wechat.com/en/service_terms.html",
- "select": "#agreement",
- "remove": {
-   "startBefore": "#wechat-terms-of-service-usa-specific-terms-",
-   "endBefore": "#wechat-terms-of-service-european-union-specific-terms-"
- }
-}
-
{
- "fetch": "https://fr-fr.facebook.com/legal/terms/plain_text_terms",
- "select": "div[role=main]",
- "remove": [
-   {
-     "startBefore": "[role=\"separator\"]",
-     "endAfter": "body"
-   },
-   "[style=\"display:none\"]"
- ]
-}
-

executeClientScripts

This property is optional.

In some cases, the content of the document is only loaded (or is modified dynamically) by client scripts. -When set to true, this boolean property loads the page in a headless browser to load all assets and execute client scripts before trying to get the document contents.

Since the performance cost of this approach is high, it is set to false by default, relying on the HTML content only.

filter

This property is optional.

Finally, some documents will need more complex filtering beyond simple element selection and removal, for example to remove noise (changes in textual content that are not meaningful to the terms of services). Such filters are declared as JavaScript functions that modify the downloaded web page through the DOM API.

Filters take the document DOM and the terms declaration as parameters and are:

  • in-place: they modify the document structure and content directly;
  • idempotent: they should return the same document structure and content even if run repeatedly on their own result.

Filters are loaded automatically from files named after the service they operate on. For example, filters for the Meetup service, which is declared in declarations/Meetup.json, are loaded from declarations/Meetup.filters.js.

The generic function signature for a filter is:

export [async] function filterName(document, documentDeclaration)
-

Each filter is exposed as a named function export that takes a document parameter and behaves like the document object in a browser DOM. These functions can be async, but they will still run sequentially. The whole document declaration is passed as second parameter.

The document parameter is actually a JSDOM document instance.

You can learn more about usual noise and ways to handle it in the guidelines.

Example

Let’s assume a service adds a unique clickId parameter in the query string of all link destinations. These parameters change on each page load, leading to recording noise in versions. Since links should still be recorded, it is not appropriate to use remove to remove the links entirely. Instead, a filter will manipulate the links destinations to remove the always-changing parameter. Concretely, the goal is to apply the following filter:

- Read the <a href="https://example.com/example-page?clickId=349A2033B&lang=en">list of our affiliates</a>.
-+ Read the <a href="https://example.com/example-page?lang=en">list of our affiliates</a>.
-

The code below implements this filter:

function removeTrackingIdsQueryParam(document) {
-  const QUERY_PARAM_TO_REMOVE = 'clickId';
-
-  document.querySelectorAll('a').forEach(link => {  // iterate over every link in the page
-    const url = new URL(link.getAttribute('href'), document.location);  // URL is part of the DOM API, see https://developer.mozilla.org/en-US/docs/Web/API/URL
-    const params = new URLSearchParams(url.search);  // URLSearchParams is part of the DOM API, see https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
-
-    params.delete(QUERY_PARAM_TO_REMOVE);  // we use the DOM API instead of RegExp because we can't know in advance in which order parameters will be written
-    url.search = params.toString();  // store the query string without the parameter
-    link.setAttribute('href', url.toString());  // write the destination URL without the parameter
-  });
-}
-
Example usage of declaration parameter

The second parameter can be used to access the defined document URL or selector inside the filter.

Let’s assume a service stores some of its legally-binding terms in images. To track these changes properly, images should be stored as part of the terms. By default, images are not stored since they significantly increase the document size. The filter below will store images inline in the terms, encoded in a data URL. In order to download the images for conversion, the base URL of the web page is needed to resolve relative links. This information is obtained from the declaration.

import fetch from 'isomorphic-fetch';
-
-export async function convertImagesToBase64(document, documentDeclaration) {
-  const { fetch: baseUrl, select: selector } = documentDeclaration;
-  
-  const images = Array.from(document.querySelectorAll(`${selector} img`));
-
-  return Promise.all(images.map(async ({ src }, index) => {
-    const imageAbsoluteUrl = new URL(src, baseUrl).href;
-    const response = await fetch(imageAbsoluteUrl);
-    const mimeType = response.headers.get('content-type');
-    const content = await response.arrayBuffer();
-
-    const base64Image = btoa(String.fromCharCode(...new Uint8Array(content)));
-
-    images[index].src = `data:${mimeType};base64,${base64Image}`;
-  }));
-}
-

Terms with a single source document

In the case where terms are extracted from one single source document, they are declared by simply declaring that source document:

  
-  "documents": {
-    "<terms type>": {
-      "fetch": "…",
-      "executeClientScripts": "…",
-      "filter": "…",
-      "remove": "…",
-      "select": "…"
-    }
-  }
-  
-

Terms with multiple source documents

When the terms are spread across multiple source documents, they should be declared by declaring their combination:

  
-  "documents": {
-    "<terms type>": {
-        "combine": [
-        {
-          "fetch": "…",
-          "executeClientScripts": "…",
-          "filter": "…",
-          "remove": "…",
-          "select": "…"
-        },
-        {
-          "fetch": "…",
-          "executeClientScripts": "…",
-          "filter": "…",
-          "remove": "…",
-          "select": "…"
-        }
-      ]
-    }
-  }
-  
-

If some parts of the source documents are repeated, they can be factorised. For example, it is common for the structure of HTML pages to be similar from page to page, so select, remove and filter would be the same. These elements can be shared instead of being duplicated:

  
-  "documents": {
-    "<terms type>": 
-      "executeClientScripts": "…",
-      "filter": "…",
-      "remove": "…",
-      "select": "…",
-      "combine": [
-        {
-          "fetch": "…",
-        },
-        {
-          "fetch": "…",
-        }
-      ]
-  }
-  
-

Terms type

Great, your terms declaration is now almost complete! You simply need to write it under the appropriate terms type in the documents JSON object within the service declaration.

In order to distinguish between the many terms that can be associated with a service and enable cross-services comparison of similar terms, we maintain a unique list of terms types in a dedicated repository.

Please note, the terms type may differ from the exact name provided by the service, but it should align with the underlying commitment. For example, some providers might call “Terms and Conditions” or “Terms of Use” what some others call “Terms of Service”.

If the terms you want to add don’t match an existing type, you can suggest a new one.

Testing your declaration

You can test the declarations you created or changed by running the following command:

npm test [$service_id [$another_service_id …]]
-

Since this operation fetches documents and could be long, you can also validate the declaration structure only:

npm run test:schema [$service_id [$another_service_id …]]
-

Linting

In order to ensure consistency across declarations, all declarations files have to be formatted homogeneously.

In order to achieve this, you can use the following command:

npm run lint [$service_id [$another_service_id …]]
-

Maintaining declarations

All parts of a terms declaration (web location, selection, noise removal, distribution across multiple documents…) can change over time. The process of updating these elements to enable continued tracking is called maintenance. Without it, terms can become:

  • unreachable: no snapshot can be recorded at all, because the location changed or the service denies access;
  • unextractable: no version can be extracted from the snapshot, because the selection of content or some filter fails;
  • noisy: both snapshots and versions are recorded but the changes contain noise that should have been filtered out.

Open Terms Archive needs to keep track of this changes in order to regenerate versions history from snapshots history.

Service history

To keep track of services declarations and filters changes, Open Terms Archive offers a versioning system. It is optional and should be added only when needed. It works by creating history files for terms declarations and filters, where each entry should be a previous valid declaration or filter function and should have an expiry date.

Both for terms and filters history, the expiration date is declared in a property validUntil. It should be the authored date and time of the last snapshot commit for which the declaration is still valid.

Terms declarations history files and filters history files can both evolve on their own. Having one does not imply to create the other.

The current (latest) valid declaration has no date and should not appear in the history object: it stays in its own file, just like if there was no history at all.

Terms declaration history

Declarations history are stored in a history JSON file with the following name declarations/$service_id.history.json.

The terms history contains an object with terms types as properties. Each terms type property is an array of history entries. Each entry has the same format as a normal terms declaration, except there is the mandatory extra property validUntil.

{
-  
-  "<terms type>": [
-    {
-      "fetch": "The URL where the document can be found",
-      "executeClientScripts": "A boolean to execute client-side JavaScript loaded by the document before accessing the content, in case the DOM modifications are needed to access the content; defaults to false (fetch HTML only)",
-      "filter": "An array of service specific filter function names",
-      "remove": "A CSS selector, a range selector or an array of selectors that target the insignificant parts of the document that has to be removed. Useful to remove parts that are inside the selected parts",
-      "select": "A CSS selector, a range selector or an array of selectors that target the meaningful parts of the document, excluding elements such as headers, footers and navigation",
-      "validUntil": "The inclusive expiration date in ISO format"
-    }
-  ]
-  
-}
-

For example, to add a history entry for the Terms of Service of the service ASKfm, create the file declarations/ASKfm.history.json with the following contents:

{
-  "Terms of Service": [
-    {
-      "fetch": "https://ask.fm/docs/terms_of_use/?lang=en",
-      "select": "body",
-      "filter": ["add"],
-      "validUntil": "2020-10-29T21:30:00.000Z"
-    }
-  ]
-}
-

Filters history

Filters history is declared in a filters history declaration JavaScript file with the following name: declarations/$service_id.filters.history.js.

For each filter, a variable named like the filter must be exported. This variable should contain an array of filter history entries. Each entry is an object with the expiration date, as validUntil property, and the valid function for this date, under the filter property. Both properties are mandatory.

export const <filterName> = [
-  {
-    validUntil: "The inclusive expiration date in ISO format",
-    filter: function() { /* body valid until the expiration of the `validUntil` date */ }
-  }
-];
-

For example, to add a history entry for the removeSharesButton filter of the service ASKfm, create the file declarations/ASKfm.filters.history.js with the following content:

export const removeSharesButton = [
-  {
-    validUntil: '2020-08-22T11:30:21.000Z',
-    filter: async (document) => {
-      document.querySelectorAll('.shares').forEach((element) => element.remove());
-    },
-  },
-];
-

Handling a terminated service

If the service provider stops offering a service, the associated terms will become unavailable. To mark that service termination in Open Terms Archive and ensure tracking tentatives are stopped, while maintaining the possibility to explore the history:

  1. Move the existing documents declaration to the service history file.
  2. Update the declaration to stop tracking all terms, by removing every <terms type> entries from the documents key in the declaration:
{
-  "name": "<service name>",
-  "documents": {}
-}
-

Renaming a service

The consensus is to consider that a service provider renaming a service (for example, Twitter to X) is akin to terminating the previous service and opening a new one. Therefore, to apply a service renaming, open a pull request that both terminates the previous service and adds a new service declaration with the new service name. You can reuse the documents part of the original declaration, but should double-check that the selectors and URLs still match, as a service rename is most often accompanied by a new page layout, a new domain name, and sometimes entirely new terms.

- - \ No newline at end of file +https://docs.opentermsarchive.org/terms/tracking-new-terms/ \ No newline at end of file diff --git a/css/loader.min.ca92c1a7804f2e7bd9ab5796a635b95c6ec04243851c23aa4845f82931dd4c0c.css b/css/loader.min.ec497ac5595176f384307b2f0b9419cc98391447c9c8f16cf306ed80d0b8af6f.css similarity index 90% rename from css/loader.min.ca92c1a7804f2e7bd9ab5796a635b95c6ec04243851c23aa4845f82931dd4c0c.css rename to css/loader.min.ec497ac5595176f384307b2f0b9419cc98391447c9c8f16cf306ed80d0b8af6f.css index c5f05936..482f6627 100644 --- a/css/loader.min.ca92c1a7804f2e7bd9ab5796a635b95c6ec04243851c23aa4845f82931dd4c0c.css +++ b/css/loader.min.ec497ac5595176f384307b2f0b9419cc98391447c9c8f16cf306ed80d0b8af6f.css @@ -1 +1 @@ -/*!minireset.css v0.0.7 | MIT License | github.com/jgthms/minireset.css*/html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}:root{--defaultFontSize:1.6rem;--defaultFontFamily:"Inter";--gridColsNumber:12;--gridColWidth:76px;--gridGuttersNumber:11;--gridGutterWidth:24px;--colorPrimary:#0496ff;--colorSecondary:#0b08a0;--colorTertiary:#f9dd3f;--colorDarkedSecondary:#b4656f;--colorError:#ec368d;--colorSuccess:#11ebc3;--colorBlack900:#010613;--colorBlack850:#171717;--colorBlack800:#333;--colorBlack600:#5e5e5e;--colorBlack400:#999;--colorBlack300:#d6d6d6;--colorBlack200:#f5f5f5;--colorWhite:#fefffd;--p3XS:2px;--p2XS:4px;--pXS:8px;--pS:12px;--pM:16px;--pL:24px;--pXL:36px;--p2XL:48px;--p3XL:64px;--p4XL:96px;--m3XS:2px;--m2XS:4px;--mXS:8px;--mS:12px;--mM:16px;--mL:24px;--mXL:36px;--m2XL:48px;--m3XL:64px;--m4XL:96px;--bpMobileSmall:320px;--bpMobileLarge:480px;--bpMobileExtraLarge:620px;--bpTabletSmall:768px;--bpTabletLarge:1024px;--bpGridPlus:1196px;--bpDesktopWide:1440px}*,::before,::after{box-sizing:border-box}html{font-size:62.5%;font-size:calc(1em * .625)}body{background-color:#fefffd;background-color:var(--colorWhite);font-family:inter;font-family:var(--defaultFontFamily);font-size:1.6rem;font-size:var(--defaultFontSize);color:#010613;color:var(--colorBlack900);line-height:1.5;letter-spacing:-.2px;font-weight:400}.float__right{float:right}.float__left{float:left}.text__center{text-align:center}.text__right{text-align:right}.text__left{text-align:left}.center{margin-left:auto;margin-right:auto}.pl__0{padding-left:0}.pl__2XS{padding-left:4px;padding-left:var(--p2XS)}.pl__XS{padding-left:8px;padding-left:var(--pXS)}.pl__S{padding-left:12px;padding-left:var(--pS)}.pl__M{padding-left:16px;padding-left:var(--pM)}.pl__L{padding-left:24px;padding-left:var(--pL)}.pl__XL{padding-left:36px;padding-left:var(--pXL)}.pl__2XL{padding-left:48px;padding-left:var(--p2XL)}.pl__3XL{padding-left:64px;padding-left:var(--p3XL)}.pl__4XL{padding-left:96px;padding-left:var(--p4XL)}.pr__0{padding-right:0}.pr__2XS{padding-right:4px;padding-right:var(--p2XS)}.pr__XS{padding-right:8px;padding-right:var(--pXS)}.pr__S{padding-right:12px;padding-right:var(--pS)}.pr__M{padding-right:16px;padding-right:var(--pM)}.pr__L{padding-right:24px;padding-right:var(--pL)}.pr__XL{padding-right:36px;padding-right:var(--pXL)}.pr__2XL{padding-right:48px;padding-right:var(--p2XL)}.pr__3XL{padding-right:64px;padding-right:var(--p3XL)}.pr__4XL{padding-right:96px;padding-right:var(--p4XL)}.pt__0{padding-top:0}.pt__2XS{padding-top:4px;padding-top:var(--p2XS)}.pt__XS{padding-top:8px;padding-top:var(--pXS)}.pt__S{padding-top:12px;padding-top:var(--pS)}.pt__M{padding-top:16px;padding-top:var(--pM)}.pt__L{padding-top:24px;padding-top:var(--pL)}.pt__XL{padding-top:36px;padding-top:var(--pXL)}.pt__2XL{padding-top:48px;padding-top:var(--p2XL)}.pt__3XL{padding-top:64px;padding-top:var(--p3XL)}.pt__4XL{padding-top:96px;padding-top:var(--p4XL)}.pb__0{padding-bottom:0}.pb__2XS{padding-bottom:4px;padding-bottom:var(--p2XS)}.pb__XS{padding-bottom:8px;padding-bottom:var(--pXS)}.pb__S{padding-bottom:12px;padding-bottom:var(--pS)}.pb__M{padding-bottom:16px;padding-bottom:var(--pM)}.pb__L{padding-bottom:24px;padding-bottom:var(--pL)}.pb__XL{padding-bottom:36px;padding-bottom:var(--pXL)}.pb__2XL{padding-bottom:48px;padding-bottom:var(--p2XL)}.pb__3XL{padding-bottom:64px;padding-bottom:var(--p3XL)}.pb__4XL{padding-bottom:96px;padding-bottom:var(--p4XL)}.ml__0{margin-left:0}.ml__2XS{margin-left:4px;margin-left:var(--m2XS)}.ml__XS{margin-left:8px;margin-left:var(--mXS)}.ml__S{margin-left:12px;margin-left:var(--mS)}.ml__M{margin-left:16px;margin-left:var(--mM)}.ml__L{margin-left:24px;margin-left:var(--mL)}.ml__XL{margin-left:36px;margin-left:var(--mXL)}.ml__2XL{margin-left:48px;margin-left:var(--m2XL)}.ml__3XL{margin-left:64px;margin-left:var(--m3XL)}.ml__4XL{margin-left:96px;margin-left:var(--m4XL)}.mr__0{margin-right:0}.mr__0{margin-right:0}.mr__2XS{margin-right:4px;margin-right:var(--m2XS)}.mr__XS{margin-right:8px;margin-right:var(--mXS)}.mr__S{margin-right:12px;margin-right:var(--mS)}.mr__M{margin-right:16px;margin-right:var(--mM)}.mr__L{margin-right:24px;margin-right:var(--mL)}.mr__XL{margin-right:36px;margin-right:var(--mXL)}.mr__2XL{margin-right:48px;margin-right:var(--m2XL)}.mr__3XL{margin-right:64px;margin-right:var(--m3XL)}.mr__4XL{margin-right:96px;margin-right:var(--m4XL)}.mt__0{margin-top:0}.mt__2XS{margin-top:4px;margin-top:var(--m2XS)}.mt__XS{margin-top:8px;margin-top:var(--mXS)}.mt__S{margin-top:12px;margin-top:var(--mS)}.mt__M{margin-top:16px;margin-top:var(--mM)}.mt__L{margin-top:24px;margin-top:var(--mL)}.mt__XL{margin-top:36px;margin-top:var(--mXL)}.mt__2XL{margin-top:48px;margin-top:var(--m2XL)}.mt__3XL{margin-top:64px;margin-top:var(--m3XL)}.mt__4XL{margin-top:96px;margin-top:var(--m4XL)}.mb__0{margin-bottom:0}.mb__2XS{margin-bottom:4px;margin-bottom:var(--m2XS)}.mb__XS{margin-bottom:8px;margin-bottom:var(--mXS)}.mb__S{margin-bottom:12px;margin-bottom:var(--mS)}.mb__M{margin-bottom:16px;margin-bottom:var(--mM)}.mb__L{margin-bottom:24px;margin-bottom:var(--mL)}.mb__XL{margin-bottom:36px;margin-bottom:var(--mXL)}.mb__2XL{margin-bottom:48px;margin-bottom:var(--m2XL)}.mb__3XL{margin-bottom:64px;margin-bottom:var(--m3XL)}.mb__4XL{margin-bottom:96px;margin-bottom:var(--m4XL)}#svgdefs{position:absolute;width:0;height:0;overflow:hidden}.button{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;display:inline-flex;align-items:center;background-color:#0496ff;background-color:var(--colorPrimary);padding:12px 24px;padding:var(--pS)var(--pL);color:#fefffd;color:var(--colorWhite);border-radius:4px;transition:all .3s easeOutExpo}.button:hover:not(:disabled){background-color:#0b08a0;background-color:var(--colorSecondary);color:#fefffd;color:var(--colorWhite);transition:all .25s easeOutCirc}.button a{color:#fefffd;color:var(--colorWhite);text-decoration:none}.button.button__secondary{background-color:#fefffd;background-color:var(--colorWhite);border:1px solid #0496ff;border:1px solid var(--colorPrimary);color:#0496ff;color:var(--colorPrimary)}.button.button__secondary:hover{background-color:#fefffd;background-color:var(--colorWhite);color:#0b08a0;color:var(--colorSecondary);border:1px solid #0b08a0;border:1px solid var(--colorSecondary)}.button.button__secondary a{color:#0496ff;color:var(--colorPrimary)}.button.button__hasOnlyIcon{padding-left:12px;padding-left:var(--pS);padding-right:12px;padding-right:var(--pS)}.button.sm{font-size:.8em;padding:8px 16px;padding:var(--pXS)var(--pM)}.button:disabled{opacity:.6;cursor:not-allowed}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Regular.eot);src:url(/fonts/inter/Inter-Regular.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Regular.woff2)format('woff2'),url(/fonts/inter/Inter-Regular.woff)format('woff'),url(/fonts/inter/Inter-Regular.ttf)format('truetype'),url(/fonts/inter/Inter-Regular.svg#Inter-Regular)format('svg');font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Bold.eot);src:url(/fonts/inter/Inter-Bold.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Bold.woff2)format('woff2'),url(/fonts/inter/Inter-Bold.woff)format('woff'),url(/fonts/inter/Inter-Bold.ttf)format('truetype'),url(/fonts/inter/Inter-Bold.svg#Inter-Bold)format('svg');font-weight:700;font-style:normal;font-display:swap}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Light.eot);src:url(/fonts/inter/Inter-Light.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Light.woff2)format('woff2'),url(/fonts/inter/Inter-Light.woff)format('woff'),url(/fonts/inter/Inter-Light.ttf)format('truetype'),url(/fonts/inter/Inter-Light.svg#Inter-Light)format('svg');font-weight:300;font-style:normal;font-display:swap}:root{--svgfill:none}.icon_circle{background-color:#999;background-color:var(--colorBlack400);border-radius:50%;height:28px;width:28px;display:inline-flex;align-items:center;justify-content:center}.icon_circle.icon_circle__medium{height:24px;width:24px}.icon_arrowDown{width:1em;height:1em}.icon_close{width:1em;height:1em}.icon_github{width:1em;height:1em}.icon_contact{width:1em;height:1em}.icon{width:1em;height:1em}.icon--fill-white{--svgfill:var(--colorWhite)}.text__light{font-size:1.4rem;letter-spacing:-.2px;color:#5e5e5e;color:var(--colorBlack600)}.text__smallcaps{font-size:1.2rem;text-transform:uppercase;letter-spacing:.5px;color:#999;color:var(--colorBlack400)}h1,.h1{font-family:inter;font-weight:700;font-size:4.2rem;letter-spacing:-1.5px;color:#010613;color:var(--colorBlack900);line-height:1.25}@media(max-width:1196px){h1,.h1{font-size:3.2rem;line-height:1.15}}@media(max-width:768px){h1,.h1{font-size:2.8rem}}h2,.h2{font-family:inter;font-style:normal;font-weight:700;font-size:3.2rem;letter-spacing:-.4px;color:#010613;color:var(--colorBlack900);line-height:1.4}h2.h2__thin,.h2.h2__thin{font-weight:300}@media(max-width:1196px){h2,.h2{font-size:2.8rem;line-height:1.3}}@media(max-width:768px){h2,.h2{line-height:1.25}}h3,.h3{font-family:inter;font-style:normal;font-weight:700;font-size:2.4rem;letter-spacing:-.4px;color:#171717;color:var(--colorBlack850);line-height:1.4}h3.h3__light,.h3.h3__light{font-weight:400}h3.h3__ultralight,.h3.h3__ultralight{font-weight:300}@media(max-width:1196px){h3,.h3{letter-spacing:-1px;line-height:1.3}}@media(max-width:768px){h3,.h3{font-size:2.2rem}}h4,.h4{font-family:inter;font-style:normal;font-weight:700;font-size:2rem;letter-spacing:-.4px;color:#333;color:var(--colorBlack800);line-height:1.3}h4.h4__white,.h4.h4__white{color:#fefffd;color:var(--colorWhite)}h4.h4__light,.h4.h4__light{font-weight:400}h4.h4__ultralight,.h4.h4__ultralight{font-weight:300}h5,.h5{font-family:inter;font-style:normal;font-weight:700;font-size:1.8rem;letter-spacing:-.2px;color:#333;color:var(--colorBlack800);line-height:1.3}h5.h5__light,.h5.h5__light{font-weight:400}h5.h5__ultralight,.h5.h5__ultralight{font-weight:300}h6,.h6{font-family:inter;font-style:normal;font-weight:700;font-size:1.6rem;letter-spacing:0;color:#333;color:var(--colorBlack800);line-height:1.25}a{color:#0496ff;color:var(--colorPrimary);text-decoration:none;transition:all .3s easeOutExpo}a:hover{color:#0b08a0;color:var(--colorSecondary);transition:all .25s easeOutCirc}.a__small{font-size:1.4rem}.a__darked:hover{color:#b4656f;color:var(--colorDarkedSecondary)}.a_icontext{display:flex;align-items:center}@media(max-width:620px){.a_icontext{justify-content:center}}input,select,textarea{font-size:1.6rem;border-radius:4px;background-color:#fefffd;background-color:var(--colorWhite);padding:12px 16px;padding:var(--pS)var(--pM);border:1px solid #999;border:1px solid var(--colorBlack400);width:100%;color:#333;color:var(--colorBlack800)}input::-moz-placeholder,select::-moz-placeholder,textarea::-moz-placeholder{color:#999;color:var(--colorBlack400)}input::placeholder,select::placeholder,textarea::placeholder{color:#999;color:var(--colorBlack400)}input[disabled]:not([type=submit]) textarea:disabled{background-color:#999;background-color:var(--colorBlack400)}select:disabled{background-color:#999;background-color:var(--colorBlack400)}input[type=checkbox]{width:2rem;height:2rem;margin-right:8px;margin-right:var(--mXS)}label{color:var(--color1-600);font-weight:700;display:block;width:100%;margin-bottom:8px;margin-bottom:var(--mXS)}.label__inline{display:inline-flex;width:auto}.formfield{width:100%}.formfield+.formfield{margin-top:24px;margin-top:var(--mL)}.formfield.formfield__alignRight{text-align:right}.formfield.formfield__flex{display:flex}.select{position:relative}.select select{position:relative;-webkit-appearance:none;-moz-appearance:none;appearance:none}.select svg{top:16px;top:var(--mM);right:12px;right:var(--mS);position:absolute;pointer-events:none}blockquote{padding-left:12px;padding-left:var(--pS);border-left:4px solid #f5f5f5;border-left:4px solid var(--colorBlack200);color:#5e5e5e;color:var(--colorBlack600)}table{border-collapse:collapse;width:100%}table thead tr th{padding:8px 16px;padding:var(--pXS)var(--pM);border-bottom:1px solid #d6d6d6;border-bottom:1px solid var(--colorBlack300);border-right:1px solid #d6d6d6;border-right:1px solid var(--colorBlack300);background-color:#f5f5f5;background-color:var(--colorBlack200)}table thead tr th:last-child{border-right:1px solid #f5f5f5;border-right:1px solid var(--colorBlack200)}table thead tr th:first-child{border-left:1px solid #f5f5f5;border-left:1px solid var(--colorBlack200)}table tbody tr td{padding:8px 16px;padding:var(--pXS)var(--pM);border:1px solid #f5f5f5;border:1px solid var(--colorBlack200)}.bg{background-color:#f5f5f5;background-color:var(--colorBlack200)}.chroma{background-color:#f5f5f5;background-color:var(--colorBlack200);font-size:1.4rem}.chroma .x{}.chroma .err{color:#ec368d;color:var(--colorError)}.chroma .cl{}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#f9dd3f;background-color:var(--colorTertiary)}.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f}.chroma .ln{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f}.chroma .line{display:flex}.chroma .k{color:#0b08a0;color:var(--colorSecondary)}.chroma .kc{color:#0b08a0;color:var(--colorSecondary)}.chroma .kd{color:#0b08a0;color:var(--colorSecondary)}.chroma .kn{color:#0b08a0;color:var(--colorSecondary)}.chroma .kp{color:#0b08a0;color:var(--colorSecondary)}.chroma .kr{color:#0b08a0;color:var(--colorSecondary)}.chroma .kt{color:#0b08a0;color:var(--colorSecondary)}.chroma .n{color:#333;color:var(--colorBlack800)}.chroma .na{color:#333;color:var(--colorBlack800)}.chroma .nb{color:#333;color:var(--colorBlack800)}.chroma .bp{color:#333;color:var(--colorBlack800)}.chroma .nc{color:#333;color:var(--colorBlack800)}.chroma .no{color:#333;color:var(--colorBlack800)}.chroma .nd{color:#333;color:var(--colorBlack800)}.chroma .ni{color:#333;color:var(--colorBlack800)}.chroma .ne{color:#333;color:var(--colorBlack800)}.chroma .nf{color:#333;color:var(--colorBlack800)}.chroma .fm{color:#333;color:var(--colorBlack800)}.chroma .nl{color:#333;color:var(--colorBlack800)}.chroma .nn{color:#333;color:var(--colorBlack800)}.chroma .nx{color:#333;color:var(--colorBlack800)}.chroma .py{color:#333;color:var(--colorBlack800)}.chroma .nt{color:#0a2e64}.chroma .nv{color:#333;color:var(--colorBlack800)}.chroma .vc{color:#333;color:var(--colorBlack800)}.chroma .vg{color:#333;color:var(--colorBlack800)}.chroma .vi{color:#333;color:var(--colorBlack800)}.chroma .vm{color:#333;color:var(--colorBlack800)}.chroma .l{}.chroma .ld{}.chroma .s{color:#0ec040}.chroma .sa{color:#0ec040}.chroma .sb{color:#0ec040}.chroma .sc{color:#0ec040}.chroma .dl{color:#0ec040}.chroma .sd{color:#0ec040}.chroma .s2{color:#0a2e64}.chroma .se{color:#0ec040}.chroma .sh{color:#0ec040}.chroma .si{color:#0ec040}.chroma .sx{color:#0ec040}.chroma .sr{color:#0ec040}.chroma .s1{color:#0ec040}.chroma .ss{color:#0ec040}.chroma .m{color:#3af}.chroma .mb{color:#3af}.chroma .mf{color:#3af}.chroma .mh{color:#3af}.chroma .mi{color:#3af}.chroma .il{color:#3af}.chroma .mo{color:#3af}.chroma .o{}.chroma .ow{color:#0b08a0;color:var(--colorSecondary)}.chroma .p{}.chroma .c{color:#67707b;font-style:italic}.chroma .ch{color:#67707b;font-style:italic}.chroma .cm{color:#67707b;font-style:italic}.chroma .c1{color:#67707b;font-style:italic}.chroma .cs{color:#67707b;font-style:italic}.chroma .cp{color:#67707b;font-style:italic}.chroma .cpf{color:#67707b;font-style:italic}.chroma .g{}.chroma .gd{}.chroma .ge{}.chroma .gr{}.chroma .gh{}.chroma .gi{}.chroma .go{}.chroma .gp{}.chroma .gs{}.chroma .gu{}.chroma .gt{}.chroma .gl{}.chroma .w{}.logo svg{height:40px;width:312px}.logo.logo__alternative svg{height:76px}.logo__small{}.logo__medium{}.logo__large{}.logo__full{width:100%}.logo__full svg{height:auto;width:100%}@media(max-width:480px){.logo{margin-top:8px}.logo svg{height:32px}}.headerMenu{display:flex;align-items:center}.headerMenu ul{display:flex}.headerMenu.headerMenu__primary ul li{margin:0 12px;margin:0 var(--mS)}.headerMenu.headerMenu__secondary ul li:not(:last-child){margin:0 4px;margin:0 var(--m2XS)}@media(max-width:1024px){.headerMenu ul{width:100%}.headerMenu ul li{width:100%;margin:12px auto;margin:var(--mS)auto}.headerMenu ul li a{color:#fefffd;color:var(--colorWhite);display:inline-flex}.headerMenu.headerMenu__primary ul li{margin:12px auto;margin:var(--mS)auto}.headerMenu.headerMenu__secondary ul li:not(:last-child){margin:12px auto;margin:var(--mS)auto}}.languageSwitcher{text-align:right;margin-right:8px;margin-right:var(--mXS);font-size:1.4rem;position:relative}.languageSwitcher.languageSwitcher__isOpen .languageSwitcher_items{display:block}.languageSwitcher_current{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;display:flex;padding:8px;padding:var(--pXS);border-radius:4px;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);align-items:center;background-color:#fefffd;background-color:var(--colorWhite)}.languageSwitcher_current>svg{margin-left:4px;margin-left:var(--m2XS)}@media(max-width:1024px){.languageSwitcher_current{}}.languageSwitcher_items{position:absolute;right:0;display:flex;flex-direction:column;text-align:right;overflow:visible;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);border-radius:4px;margin-top:-1px;display:none;background-color:#fefffd;background-color:var(--colorWhite)}.languageSwitcher_item{width:100%;white-space:nowrap;padding:8px;padding:var(--pXS)}.languageSwitcher_item.languageSwitcher_item__isActive{border:1px solid red}.container{margin:0 auto;padding-top:96px;padding-top:var(--p4XL);padding-bottom:64px;padding-bottom:var(--p3XL)}.container.container__1211{max-width:calc( (76px * 12) + (24px * 11) );max-width:calc( (var(--gridColWidth) * 12) + (var(--gridGutterWidth) * 11) );width:100%}.container.container__1110{max-width:calc( (76px * 11) + (24px * 10) );max-width:calc( (var(--gridColWidth) * 11) + (var(--gridGutterWidth) * 10) );width:100%}.container.container__1011{max-width:calc( (76px * 10) + (24px * 11) );max-width:calc( (var(--gridColWidth) * 10) + (var(--gridGutterWidth) * 11) );width:100%}.container.container__109{max-width:calc( (76px * 10) + (24px * 9) );max-width:calc( (var(--gridColWidth) * 10) + (var(--gridGutterWidth) * 9) );width:100%}.container.container__98{max-width:calc( (76px * 9) + (24px * 8) );max-width:calc( (var(--gridColWidth) * 9) + (var(--gridGutterWidth) * 8) );width:100%}.container.container__87{max-width:calc( (76px * 8) + (24px * 7) );max-width:calc( (var(--gridColWidth) * 8) + (var(--gridGutterWidth) * 7) );width:100%}.container.container__76{max-width:calc( (76px * 7) + (24px * 6) );max-width:calc( (var(--gridColWidth) * 7) + (var(--gridGutterWidth) * 6) );width:100%}.container.container__65{max-width:calc( (76px * 6) + (24px * 5) );max-width:calc( (var(--gridColWidth) * 6) + (var(--gridGutterWidth) * 5) );width:100%}.container.container__54{max-width:calc( (76px * 5) + (24px * 4) );max-width:calc( (var(--gridColWidth) * 5) + (var(--gridGutterWidth) * 4) );width:100%}.container.container__43{max-width:calc( (76px * 4) + (24px * 3) );max-width:calc( (var(--gridColWidth) * 4) + (var(--gridGutterWidth) * 3) );width:100%}.container.container__32{max-width:calc( (76px * 3) + (24px * 2) );max-width:calc( (var(--gridColWidth) * 3) + (var(--gridGutterWidth) * 2) );width:100%}.container.container__21{max-width:calc( (76px * 2) + (24px * 1) );max-width:calc( (var(--gridColWidth) * 2) + (var(--gridGutterWidth) * 1) );width:100%}.container.container__flex{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:flex-start}@media(max-width:768px){.container.container__flex{flex-direction:column}}.container.container__fluid{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL);max-width:100%}.container.container__wide{max-width:var(--desktopWide);margin:0 auto}.container.container__hasBgImage{background-position:top;background-repeat:no-repeat;background-size:cover}.container.container__isDark{background-color:#010613;background-color:var(--colorBlack900);color:#fefffd;color:var(--colorWhite)}.container.container__isDark h1,.container.container__isDark h2,.container.container__isDark h3,.container.container__isDark .text__subtitle{color:#fefffd;color:var(--colorWhite)}.container.container__isGray{background-color:#f5f5f5;background-color:var(--colorBlack200)}.container.container__isGray blockquote:before{color:#fefffd;color:var(--colorWhite)}.container.container__hasNoPaddingX{padding-left:0;padding-right:0}.container.container__hasNoPaddingLeft{padding-left:0}.container.container__hasNoPaddingRight{padding-right:0}.container.container__hasNoPaddingY{padding-top:0;padding-bottom:0}.container.container__hasNoPaddingTop{padding-top:0}.container.container__hasNoPaddingBottom{padding-bottom:0}.container.container__hasPaddingYSmall{padding-top:24px;padding-top:var(--pL);padding-bottom:24px;padding-bottom:var(--pL)}.container.container__alignXleft{margin-left:0}@media(max-width:1196px){.container{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}@media(max-width:768px){.container{padding-top:64px;padding-top:var(--p3XL);padding-bottom:48px;padding-bottom:var(--p2XL)}.container.container__hasPaddingYSmall{padding-top:36px;padding-top:var(--pXL);padding-bottom:16px;padding-bottom:var(--pM)}}.header{width:100%;display:flex;align-items:center;padding-top:24px;padding-top:var(--pL);padding-bottom:24px;padding-bottom:var(--pL);position:relative}.header.header__isOpen .header_menus{transition:.5s all easeOutCirc;transform:translateX(0)}.header.header__isOpen .header_openLink{display:none}.header.header__isOpen .header_closeLink{display:inline-flex}.header{}@media(max-width:1196px){.header{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}.header_logo{line-height:0}.header_menus{flex-grow:1;display:flex}.header_menus nav:first-child{flex-grow:1;justify-content:center;align-items:center}.header_menus nav:last-child{margin-left:auto}@media(max-width:1024px){.header_menus{transition:.3s all easeOutExpo;transform:translateX(100%);background-color:#0b08a0;background-color:var(--colorSecondary);position:fixed;z-index:1;left:0;right:0;top:0;bottom:0;flex-wrap:wrap;flex-direction:column}.header_menus nav{width:100%}.header_menus nav:first-child{align-items:flex-end}.header_menus nav:first-child,.header_menus nav:last-child{flex-grow:1;justify-content:center}.header_menus nav:first-child ul,.header_menus nav:last-child ul{flex-direction:column;text-align:center}.header_menus nav:last-child{margin-top:auto;margin-bottom:36px;margin-bottom:var(--mXL);flex-direction:column}.header_menus nav:last-child div{margin-bottom:24px;margin-bottom:var(--mL)}}.header_openLink{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;color:#0496ff;color:var(--colorPrimary);display:none;font-size:1.4rem;position:absolute;padding:12px;padding:var(--pS);top:24px;top:var(--mL);right:24px;right:var(--mL)}@media(max-width:1024px){.header_openLink{display:inline-flex}}.header_closeLink{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;position:fixed;display:none;color:#fefffd;color:var(--colorWhite);font-size:1.4rem;padding:12px;padding:var(--pS);top:24px;top:var(--mL);right:24px;right:var(--mL);align-items:center;z-index:1}.header_closeLink svg{margin-left:4px;margin-left:var(--m2XS)}.footer{width:100%;padding:0 0 24px;padding:0 0 var(--pL)}.version{color:#999;color:var(--colorBlack400);font-size:.8em;text-align:right;font-style:italic}@media(max-width:1024px){.footer{text-align:center}}.footer_menus{width:100%;display:flex;justify-content:space-between;margin-top:4px;margin-top:var(--m2XS)}.footer_menus div:first-child{margin-right:24px;margin-right:var(--gridGutterWidth)}.footer_menus div ul{display:flex;flex-direction:row}.footer_menus div ul li{margin:0 8px;margin:0 var(--mXS)}.footer_menus div ul li:first-child{margin-left:0}.footer_menus div ul li:last-child{margin-right:0}.footer_menus div ul li a{color:#5e5e5e;color:var(--colorBlack600)}.footer_menus div ul+ul{margin-top:1rem}@media(max-width:1196px){.footer{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}@media(max-width:1024px){.footer_menus{justify-content:center;align-items:flex-start}.footer_menus div{margin:24px 76px 0;margin:var(--gridGutterWidth)var(--gridColWidth)0}.footer_menus div:first-child{margin-right:0}.footer_menus div ul{flex-direction:column}.footer_menus div ul li{text-align:left;margin:8px;margin:var(--mXS)}.footer_menus div ul li:first-child{margin-top:0}.footer_menus div ul li:first-child{margin-left:8px;margin-left:var(--mXS)}.footer_menus div ul li:last-child{margin-right:8px;margin-right:var(--mXS)}.footer_menus div ul+ul{flex-direction:column}}@media(max-width:620px){.footer_menus{justify-content:flex-start;flex-wrap:wrap}.footer_menus div{width:100%;margin:24px 0 0;margin:var(--gridGutterWidth)0 0}.footer_menus div ul li{text-align:center}}.footerMenu.footerMenu__isSmall{font-size:1.4rem}.footerMenu.footerMenu__alignRight ul{justify-content:flex-end}.divider>hr{border:1px solid #999;border:1px solid var(--colorBlack400)}.textContent{border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);padding:24px;padding:var(--mL);overflow-x:hidden;max-width:100%}.textContent hr{clear:both;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);margin-bottom:24px;margin-bottom:var(--mL)}.textContent details[open] summary{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent p,.textContent .highlight,.textContent details{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent p:last-child,.textContent .highlight:last-child,.textContent details:last-child{margin-bottom:0}.textContent p:global(.mb__0),.textContent .highlight:global(.mb__0),.textContent details:global(.mb__0){margin-bottom:0}.textContent p:global(.mb__3XL),.textContent .highlight:global(.mb__3XL),.textContent details:global(.mb__3XL){margin-bottom:64px;margin-bottom:var(--m3XL)}.textContent p+hr,.textContent blockquote+hr,.textContent pre+hr,.textContent ul+hr{margin-top:48px;margin-top:var(--m2XL)}.textContent h1{margin-bottom:36px;margin-bottom:var(--mXL)}@media(max-width:768px){.textContent h1{margin-bottom:36px;margin-bottom:var(--mXL)}}.textContent h1:global(.mb__0){margin-bottom:0}.textContent h1:global(.mb__S){margin-bottom:12px;margin-bottom:var(--mS)}.textContent h1:global(.mb__M){margin-bottom:16px;margin-bottom:var(--mM)}.textContent h2{margin-bottom:24px;margin-bottom:var(--mL)}.textContent h2:global(.mb__0){margin-bottom:0}.textContent h3{margin-bottom:16px;margin-bottom:var(--mM)}.textContent h3:global(.mb__0){margin-bottom:0}.textContent h4{margin-bottom:16px;margin-bottom:var(--mM)}.textContent h4:global(.mb__0){margin-bottom:0}.textContent h4:global(.mb__XL){margin-bottom:36px;margin-bottom:var(--mXL)}.textContent h4:global(.mb__3XL){margin-bottom:64px;margin-bottom:var(--m3XL)}.textContent h5{margin-bottom:12px;margin-bottom:var(--mS)}.textContent h5:global(.mb__0){margin-bottom:0}.textContent h6{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent h6:global(.mb__0){margin-bottom:0}.textContent p+h2,.textContent ul+h2,.textContent ol+h2,.textContent blockquote+h2,.textContent .highlight+h2,.textContent details+h2{margin-top:48px;margin-top:var(--m2XL)}.textContent p+h3,.textContent ul+h3,.textContent ol+h3,.textContent blockquote+h3,.textContent .highlight+h3,.textContent details+h3{margin-top:36px;margin-top:var(--mXL)}.textContent p+h4,.textContent ul+h4,.textContent ol+h4,.textContent blockquote+h4,.textContent .highlight+h4,.textContent details+h4{margin-top:24px;margin-top:var(--mL)}.textContent p+h5,.textContent ul+h5,.textContent ol+h5,.textContent blockquote+h5,.textContent .highlight+h5,.textContent details+h5{margin-top:24px;margin-top:var(--mL)}.textContent iframe{margin-bottom:24px;margin-bottom:var(--mL)}.textContent ul{list-style-type:disc}.textContent ol{list-style-type:numbers}.textContent nav:not(:last-child){margin-bottom:24px;margin-bottom:var(--mL)}.textContent ul,.textContent ol{margin-left:24px;margin-left:var(--mL)}.textContent ul:not(:last-child),.textContent ol:not(:last-child){margin-bottom:24px;margin-bottom:var(--mL)}.textContent li{position:relative;margin-bottom:4px;margin-bottom:var(--m2XS)}.textContent li svg{left:calc(24px * -1);left:calc(var(--mL) * -1);top:4px;top:var(--m2XS);position:absolute}.textContent li:last-child{margin-bottom:0}.textContent li>ul{margin-top:4px;margin-top:var(--m2XS)}.textContent .textContent__noListStyle{list-style-type:none}.textContent blockquote{margin-bottom:16px;margin-bottom:var(--mM)}.textContent pre{padding:.8rem;overflow-x:scroll}.textContent code{background-color:#f5f5f5;background-color:var(--colorBlack200);font-size:.95em}.textContent button{margin-bottom:36px;margin-bottom:var(--mXL)}@media(max-width:768px){.textContent button{margin-bottom:24px;margin-bottom:var(--mL)}}.textContent button:global(.mb__0){margin-bottom:0}.textContent__marginTopLarge{margin-top:48px;margin-top:var(--m2XL)}.textContent__hasNoMarginTop{margin-top:0}summary{cursor:pointer}.aside{flex-shrink:0;margin-right:36px;margin-right:var(--mXL);max-width:calc( (76px * 3) + (24px * 2) );max-width:calc( (var(--gridColWidth) * 3) + (var(--gridGutterWidth) * 2) );width:100%;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);border-radius:4px}.aside_items{}.aside_item{padding:8px 12px;padding:var(--mXS)var(--mS);border-bottom:1px solid #f5f5f5;border-bottom:1px solid var(--colorBlack200)}.aside_item:last-child{border:none}.aside_item #TableOfContents{padding-left:8px;padding-left:var(--mXS)}.aside_item #TableOfContents>ul>li>ul{padding-left:8px;padding-left:var(--mXS)}.aside_subitems{padding-left:8px;padding-left:var(--mXS)}.aside_item-current{background-color:#f5f5f5;background-color:var(--colorBlack200)}.aside_item-current>a,.aside_item-current>span{font-weight:700}.aside_item_section{color:#5e5e5e;color:var(--colorBlack600);width:100%;display:inline-block}@media(max-width:768px){.aside{max-width:100%;margin-bottom:48px;margin-bottom:var(--m2XL)}} \ No newline at end of file +/*!minireset.css v0.0.7 | MIT License | github.com/jgthms/minireset.css*/html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:400}ul{list-style:none}button,input,select{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}:root{--defaultFontSize:1.6rem;--defaultFontFamily:"Inter";--gridColsNumber:12;--gridColWidth:76px;--gridGuttersNumber:11;--gridGutterWidth:24px;--colorPrimary:#0496ff;--colorSecondary:#0b08a0;--colorTertiary:#f9dd3f;--colorDarkedSecondary:#b4656f;--colorError:#ec368d;--colorSuccess:#11ebc3;--colorBlack900:#010613;--colorBlack850:#171717;--colorBlack800:#333;--colorBlack600:#5e5e5e;--colorBlack400:#999;--colorBlack300:#d6d6d6;--colorBlack200:#f5f5f5;--colorWhite:#fefffd;--p3XS:2px;--p2XS:4px;--pXS:8px;--pS:12px;--pM:16px;--pL:24px;--pXL:36px;--p2XL:48px;--p3XL:64px;--p4XL:96px;--m3XS:2px;--m2XS:4px;--mXS:8px;--mS:12px;--mM:16px;--mL:24px;--mXL:36px;--m2XL:48px;--m3XL:64px;--m4XL:96px;--bpMobileSmall:320px;--bpMobileLarge:480px;--bpMobileExtraLarge:620px;--bpTabletSmall:768px;--bpTabletLarge:1024px;--bpGridPlus:1196px;--bpDesktopWide:1440px}*,::before,::after{box-sizing:border-box}html{font-size:62.5%;font-size:calc(1em * .625)}body{background-color:#fefffd;background-color:var(--colorWhite);font-family:inter;font-family:var(--defaultFontFamily);font-size:1.6rem;font-size:var(--defaultFontSize);color:#010613;color:var(--colorBlack900);line-height:1.5;letter-spacing:-.2px;font-weight:400}.float__right{float:right}.float__left{float:left}.text__center{text-align:center}.text__right{text-align:right}.text__left{text-align:left}.center{margin-left:auto;margin-right:auto}.pl__0{padding-left:0}.pl__2XS{padding-left:4px;padding-left:var(--p2XS)}.pl__XS{padding-left:8px;padding-left:var(--pXS)}.pl__S{padding-left:12px;padding-left:var(--pS)}.pl__M{padding-left:16px;padding-left:var(--pM)}.pl__L{padding-left:24px;padding-left:var(--pL)}.pl__XL{padding-left:36px;padding-left:var(--pXL)}.pl__2XL{padding-left:48px;padding-left:var(--p2XL)}.pl__3XL{padding-left:64px;padding-left:var(--p3XL)}.pl__4XL{padding-left:96px;padding-left:var(--p4XL)}.pr__0{padding-right:0}.pr__2XS{padding-right:4px;padding-right:var(--p2XS)}.pr__XS{padding-right:8px;padding-right:var(--pXS)}.pr__S{padding-right:12px;padding-right:var(--pS)}.pr__M{padding-right:16px;padding-right:var(--pM)}.pr__L{padding-right:24px;padding-right:var(--pL)}.pr__XL{padding-right:36px;padding-right:var(--pXL)}.pr__2XL{padding-right:48px;padding-right:var(--p2XL)}.pr__3XL{padding-right:64px;padding-right:var(--p3XL)}.pr__4XL{padding-right:96px;padding-right:var(--p4XL)}.pt__0{padding-top:0}.pt__2XS{padding-top:4px;padding-top:var(--p2XS)}.pt__XS{padding-top:8px;padding-top:var(--pXS)}.pt__S{padding-top:12px;padding-top:var(--pS)}.pt__M{padding-top:16px;padding-top:var(--pM)}.pt__L{padding-top:24px;padding-top:var(--pL)}.pt__XL{padding-top:36px;padding-top:var(--pXL)}.pt__2XL{padding-top:48px;padding-top:var(--p2XL)}.pt__3XL{padding-top:64px;padding-top:var(--p3XL)}.pt__4XL{padding-top:96px;padding-top:var(--p4XL)}.pb__0{padding-bottom:0}.pb__2XS{padding-bottom:4px;padding-bottom:var(--p2XS)}.pb__XS{padding-bottom:8px;padding-bottom:var(--pXS)}.pb__S{padding-bottom:12px;padding-bottom:var(--pS)}.pb__M{padding-bottom:16px;padding-bottom:var(--pM)}.pb__L{padding-bottom:24px;padding-bottom:var(--pL)}.pb__XL{padding-bottom:36px;padding-bottom:var(--pXL)}.pb__2XL{padding-bottom:48px;padding-bottom:var(--p2XL)}.pb__3XL{padding-bottom:64px;padding-bottom:var(--p3XL)}.pb__4XL{padding-bottom:96px;padding-bottom:var(--p4XL)}.ml__0{margin-left:0}.ml__2XS{margin-left:4px;margin-left:var(--m2XS)}.ml__XS{margin-left:8px;margin-left:var(--mXS)}.ml__S{margin-left:12px;margin-left:var(--mS)}.ml__M{margin-left:16px;margin-left:var(--mM)}.ml__L{margin-left:24px;margin-left:var(--mL)}.ml__XL{margin-left:36px;margin-left:var(--mXL)}.ml__2XL{margin-left:48px;margin-left:var(--m2XL)}.ml__3XL{margin-left:64px;margin-left:var(--m3XL)}.ml__4XL{margin-left:96px;margin-left:var(--m4XL)}.mr__0{margin-right:0}.mr__0{margin-right:0}.mr__2XS{margin-right:4px;margin-right:var(--m2XS)}.mr__XS{margin-right:8px;margin-right:var(--mXS)}.mr__S{margin-right:12px;margin-right:var(--mS)}.mr__M{margin-right:16px;margin-right:var(--mM)}.mr__L{margin-right:24px;margin-right:var(--mL)}.mr__XL{margin-right:36px;margin-right:var(--mXL)}.mr__2XL{margin-right:48px;margin-right:var(--m2XL)}.mr__3XL{margin-right:64px;margin-right:var(--m3XL)}.mr__4XL{margin-right:96px;margin-right:var(--m4XL)}.mt__0{margin-top:0}.mt__2XS{margin-top:4px;margin-top:var(--m2XS)}.mt__XS{margin-top:8px;margin-top:var(--mXS)}.mt__S{margin-top:12px;margin-top:var(--mS)}.mt__M{margin-top:16px;margin-top:var(--mM)}.mt__L{margin-top:24px;margin-top:var(--mL)}.mt__XL{margin-top:36px;margin-top:var(--mXL)}.mt__2XL{margin-top:48px;margin-top:var(--m2XL)}.mt__3XL{margin-top:64px;margin-top:var(--m3XL)}.mt__4XL{margin-top:96px;margin-top:var(--m4XL)}.mb__0{margin-bottom:0}.mb__2XS{margin-bottom:4px;margin-bottom:var(--m2XS)}.mb__XS{margin-bottom:8px;margin-bottom:var(--mXS)}.mb__S{margin-bottom:12px;margin-bottom:var(--mS)}.mb__M{margin-bottom:16px;margin-bottom:var(--mM)}.mb__L{margin-bottom:24px;margin-bottom:var(--mL)}.mb__XL{margin-bottom:36px;margin-bottom:var(--mXL)}.mb__2XL{margin-bottom:48px;margin-bottom:var(--m2XL)}.mb__3XL{margin-bottom:64px;margin-bottom:var(--m3XL)}.mb__4XL{margin-bottom:96px;margin-bottom:var(--m4XL)}#svgdefs{position:absolute;width:0;height:0;overflow:hidden}.button{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;display:inline-flex;align-items:center;background-color:#0496ff;background-color:var(--colorPrimary);padding:12px 24px;padding:var(--pS)var(--pL);color:#fefffd;color:var(--colorWhite);border-radius:4px;transition:all .3s easeOutExpo}.button:hover:not(:disabled){background-color:#0b08a0;background-color:var(--colorSecondary);color:#fefffd;color:var(--colorWhite);transition:all .25s easeOutCirc}.button a{color:#fefffd;color:var(--colorWhite);text-decoration:none}.button.button__secondary{background-color:#fefffd;background-color:var(--colorWhite);border:1px solid #0496ff;border:1px solid var(--colorPrimary);color:#0496ff;color:var(--colorPrimary)}.button.button__secondary:hover{background-color:#fefffd;background-color:var(--colorWhite);color:#0b08a0;color:var(--colorSecondary);border:1px solid #0b08a0;border:1px solid var(--colorSecondary)}.button.button__secondary a{color:#0496ff;color:var(--colorPrimary)}.button.button__hasOnlyIcon{padding-left:12px;padding-left:var(--pS);padding-right:12px;padding-right:var(--pS)}.button.sm{font-size:.8em;padding:8px 16px;padding:var(--pXS)var(--pM)}.button:disabled{opacity:.6;cursor:not-allowed}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Regular.eot);src:url(/fonts/inter/Inter-Regular.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Regular.woff2)format('woff2'),url(/fonts/inter/Inter-Regular.woff)format('woff'),url(/fonts/inter/Inter-Regular.ttf)format('truetype'),url(/fonts/inter/Inter-Regular.svg#Inter-Regular)format('svg');font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Bold.eot);src:url(/fonts/inter/Inter-Bold.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Bold.woff2)format('woff2'),url(/fonts/inter/Inter-Bold.woff)format('woff'),url(/fonts/inter/Inter-Bold.ttf)format('truetype'),url(/fonts/inter/Inter-Bold.svg#Inter-Bold)format('svg');font-weight:700;font-style:normal;font-display:swap}@font-face{font-family:inter;src:url(/fonts/inter/Inter-Light.eot);src:url(/fonts/inter/Inter-Light.eot?#iefix)format('embedded-opentype'),url(/fonts/inter/Inter-Light.woff2)format('woff2'),url(/fonts/inter/Inter-Light.woff)format('woff'),url(/fonts/inter/Inter-Light.ttf)format('truetype'),url(/fonts/inter/Inter-Light.svg#Inter-Light)format('svg');font-weight:300;font-style:normal;font-display:swap}:root{--svgfill:none}.icon_circle{background-color:#999;background-color:var(--colorBlack400);border-radius:50%;height:28px;width:28px;display:inline-flex;align-items:center;justify-content:center}.icon_circle.icon_circle__medium{height:24px;width:24px}.icon_arrowDown{width:1em;height:1em}.icon_close{width:1em;height:1em}.icon_github{width:1em;height:1em}.icon_contact{width:1em;height:1em}.icon{width:1em;height:1em}.icon--fill-white{--svgfill:var(--colorWhite)}.text__light{font-size:1.4rem;letter-spacing:-.2px;color:#5e5e5e;color:var(--colorBlack600)}.text__smallcaps{font-size:1.2rem;text-transform:uppercase;letter-spacing:.5px;color:#999;color:var(--colorBlack400)}h1,.h1{font-family:inter;font-weight:700;font-size:4.2rem;letter-spacing:-1.5px;color:#010613;color:var(--colorBlack900);line-height:1.25}@media(max-width:1196px){h1,.h1{font-size:3.2rem;line-height:1.15}}@media(max-width:768px){h1,.h1{font-size:2.8rem}}h2,.h2{font-family:inter;font-style:normal;font-weight:700;font-size:3.2rem;letter-spacing:-.4px;color:#010613;color:var(--colorBlack900);line-height:1.4}h2.h2__thin,.h2.h2__thin{font-weight:300}@media(max-width:1196px){h2,.h2{font-size:2.8rem;line-height:1.3}}@media(max-width:768px){h2,.h2{line-height:1.25}}h3,.h3{font-family:inter;font-style:normal;font-weight:700;font-size:2.4rem;letter-spacing:-.4px;color:#171717;color:var(--colorBlack850);line-height:1.4}h3.h3__light,.h3.h3__light{font-weight:400}h3.h3__ultralight,.h3.h3__ultralight{font-weight:300}@media(max-width:1196px){h3,.h3{letter-spacing:-1px;line-height:1.3}}@media(max-width:768px){h3,.h3{font-size:2.2rem}}h4,.h4{font-family:inter;font-style:normal;font-weight:700;font-size:2rem;letter-spacing:-.4px;color:#333;color:var(--colorBlack800);line-height:1.3}h4.h4__white,.h4.h4__white{color:#fefffd;color:var(--colorWhite)}h4.h4__light,.h4.h4__light{font-weight:400}h4.h4__ultralight,.h4.h4__ultralight{font-weight:300}h5,.h5{font-family:inter;font-style:normal;font-weight:700;font-size:1.8rem;letter-spacing:-.2px;color:#333;color:var(--colorBlack800);line-height:1.3}h5.h5__light,.h5.h5__light{font-weight:400}h5.h5__ultralight,.h5.h5__ultralight{font-weight:300}h6,.h6{font-family:inter;font-style:normal;font-weight:700;font-size:1.6rem;letter-spacing:0;color:#333;color:var(--colorBlack800);line-height:1.25}a{color:#0496ff;color:var(--colorPrimary);text-decoration:none;transition:all .3s easeOutExpo}a:hover{color:#0b08a0;color:var(--colorSecondary);transition:all .25s easeOutCirc}.a__small{font-size:1.4rem}.a__darked:hover{color:#b4656f;color:var(--colorDarkedSecondary)}.a_icontext{display:flex;align-items:center}@media(max-width:620px){.a_icontext{justify-content:center}}input,select,textarea{font-size:1.6rem;border-radius:4px;background-color:#fefffd;background-color:var(--colorWhite);padding:12px 16px;padding:var(--pS)var(--pM);border:1px solid #999;border:1px solid var(--colorBlack400);width:100%;color:#333;color:var(--colorBlack800)}input::-moz-placeholder,select::-moz-placeholder,textarea::-moz-placeholder{color:#999;color:var(--colorBlack400)}input::placeholder,select::placeholder,textarea::placeholder{color:#999;color:var(--colorBlack400)}input[disabled]:not([type=submit]) textarea:disabled{background-color:#999;background-color:var(--colorBlack400)}select:disabled{background-color:#999;background-color:var(--colorBlack400)}input[type=checkbox]{width:2rem;height:2rem;margin-right:8px;margin-right:var(--mXS)}label{color:var(--color1-600);font-weight:700;display:block;width:100%;margin-bottom:8px;margin-bottom:var(--mXS)}.label__inline{display:inline-flex;width:auto}.formfield{width:100%}.formfield+.formfield{margin-top:24px;margin-top:var(--mL)}.formfield.formfield__alignRight{text-align:right}.formfield.formfield__flex{display:flex}.select{position:relative}.select select{position:relative;-webkit-appearance:none;-moz-appearance:none;appearance:none}.select svg{top:16px;top:var(--mM);right:12px;right:var(--mS);position:absolute;pointer-events:none}blockquote{padding-left:12px;padding-left:var(--pS);border-left:4px solid #f5f5f5;border-left:4px solid var(--colorBlack200);color:#5e5e5e;color:var(--colorBlack600)}table{border-collapse:collapse;width:100%}table thead tr th{padding:8px 16px;padding:var(--pXS)var(--pM);border-bottom:1px solid #d6d6d6;border-bottom:1px solid var(--colorBlack300);border-right:1px solid #d6d6d6;border-right:1px solid var(--colorBlack300);background-color:#f5f5f5;background-color:var(--colorBlack200)}table thead tr th:last-child{border-right:1px solid #f5f5f5;border-right:1px solid var(--colorBlack200)}table thead tr th:first-child{border-left:1px solid #f5f5f5;border-left:1px solid var(--colorBlack200)}table tbody tr td{padding:8px 16px;padding:var(--pXS)var(--pM);border:1px solid #f5f5f5;border:1px solid var(--colorBlack200)}.bg{background-color:#f5f5f5;background-color:var(--colorBlack200)}.chroma{background-color:#f5f5f5;background-color:var(--colorBlack200);font-size:1.4rem}.chroma .x{}.chroma .err{color:#ec368d;color:var(--colorError)}.chroma .cl{}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#f9dd3f;background-color:var(--colorTertiary)}.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f}.chroma .ln{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f7f7f}.chroma .line{display:flex}.chroma .k{color:#0b08a0;color:var(--colorSecondary)}.chroma .kc{color:#0b08a0;color:var(--colorSecondary)}.chroma .kd{color:#0b08a0;color:var(--colorSecondary)}.chroma .kn{color:#0b08a0;color:var(--colorSecondary)}.chroma .kp{color:#0b08a0;color:var(--colorSecondary)}.chroma .kr{color:#0b08a0;color:var(--colorSecondary)}.chroma .kt{color:#0b08a0;color:var(--colorSecondary)}.chroma .n{color:#333;color:var(--colorBlack800)}.chroma .na{color:#333;color:var(--colorBlack800)}.chroma .nb{color:#333;color:var(--colorBlack800)}.chroma .bp{color:#333;color:var(--colorBlack800)}.chroma .nc{color:#333;color:var(--colorBlack800)}.chroma .no{color:#333;color:var(--colorBlack800)}.chroma .nd{color:#333;color:var(--colorBlack800)}.chroma .ni{color:#333;color:var(--colorBlack800)}.chroma .ne{color:#333;color:var(--colorBlack800)}.chroma .nf{color:#333;color:var(--colorBlack800)}.chroma .fm{color:#333;color:var(--colorBlack800)}.chroma .nl{color:#333;color:var(--colorBlack800)}.chroma .nn{color:#333;color:var(--colorBlack800)}.chroma .nx{color:#333;color:var(--colorBlack800)}.chroma .py{color:#333;color:var(--colorBlack800)}.chroma .nt{color:#0a2e64}.chroma .nv{color:#333;color:var(--colorBlack800)}.chroma .vc{color:#333;color:var(--colorBlack800)}.chroma .vg{color:#333;color:var(--colorBlack800)}.chroma .vi{color:#333;color:var(--colorBlack800)}.chroma .vm{color:#333;color:var(--colorBlack800)}.chroma .l{}.chroma .ld{}.chroma .s{color:#0ec040}.chroma .sa{color:#0ec040}.chroma .sb{color:#0ec040}.chroma .sc{color:#0ec040}.chroma .dl{color:#0ec040}.chroma .sd{color:#0ec040}.chroma .s2{color:#0a2e64}.chroma .se{color:#0ec040}.chroma .sh{color:#0ec040}.chroma .si{color:#0ec040}.chroma .sx{color:#0ec040}.chroma .sr{color:#0ec040}.chroma .s1{color:#0ec040}.chroma .ss{color:#0ec040}.chroma .m{color:#3af}.chroma .mb{color:#3af}.chroma .mf{color:#3af}.chroma .mh{color:#3af}.chroma .mi{color:#3af}.chroma .il{color:#3af}.chroma .mo{color:#3af}.chroma .o{}.chroma .ow{color:#0b08a0;color:var(--colorSecondary)}.chroma .p{}.chroma .c{color:#67707b;font-style:italic}.chroma .ch{color:#67707b;font-style:italic}.chroma .cm{color:#67707b;font-style:italic}.chroma .c1{color:#67707b;font-style:italic}.chroma .cs{color:#67707b;font-style:italic}.chroma .cp{color:#67707b;font-style:italic}.chroma .cpf{color:#67707b;font-style:italic}.chroma .g{}.chroma .gd{}.chroma .ge{}.chroma .gr{}.chroma .gh{}.chroma .gi{}.chroma .go{}.chroma .gp{}.chroma .gs{}.chroma .gu{}.chroma .gt{}.chroma .gl{}.chroma .w{}.logo svg{height:40px;width:312px}.logo.logo__alternative svg{height:76px}.logo__small{}.logo__medium{}.logo__large{}.logo__full{width:100%}.logo__full svg{height:auto;width:100%}@media(max-width:480px){.logo{margin-top:8px}.logo svg{height:32px}}.headerMenu{display:flex;align-items:center}.headerMenu ul{display:flex}.headerMenu.headerMenu__primary ul li{margin:0 12px;margin:0 var(--mS)}.headerMenu.headerMenu__secondary ul li:not(:last-child){margin:0 4px;margin:0 var(--m2XS)}@media(max-width:1024px){.headerMenu ul{width:100%}.headerMenu ul li{width:100%;margin:12px auto;margin:var(--mS)auto}.headerMenu ul li a{color:#fefffd;color:var(--colorWhite);display:inline-flex}.headerMenu.headerMenu__primary ul li{margin:12px auto;margin:var(--mS)auto}.headerMenu.headerMenu__secondary ul li:not(:last-child){margin:12px auto;margin:var(--mS)auto}}.languageSwitcher{text-align:right;margin-right:8px;margin-right:var(--mXS);font-size:1.4rem;position:relative}.languageSwitcher.languageSwitcher__isOpen .languageSwitcher_items{display:block}.languageSwitcher_current{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;display:flex;padding:8px;padding:var(--pXS);border-radius:4px;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);align-items:center;background-color:#fefffd;background-color:var(--colorWhite)}.languageSwitcher_current>svg{margin-left:4px;margin-left:var(--m2XS)}@media(max-width:1024px){.languageSwitcher_current{}}.languageSwitcher_items{position:absolute;right:0;display:flex;flex-direction:column;text-align:right;overflow:visible;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);border-radius:4px;margin-top:-1px;display:none;background-color:#fefffd;background-color:var(--colorWhite)}.languageSwitcher_item{width:100%;white-space:nowrap;padding:8px;padding:var(--pXS)}.languageSwitcher_item.languageSwitcher_item__isActive{border:1px solid red}.container{margin:0 auto;padding-top:96px;padding-top:var(--p4XL);padding-bottom:64px;padding-bottom:var(--p3XL)}.container.container__1211{max-width:calc( (76px * 12) + (24px * 11) );max-width:calc( (var(--gridColWidth) * 12) + (var(--gridGutterWidth) * 11) );width:100%}.container.container__1110{max-width:calc( (76px * 11) + (24px * 10) );max-width:calc( (var(--gridColWidth) * 11) + (var(--gridGutterWidth) * 10) );width:100%}.container.container__1011{max-width:calc( (76px * 10) + (24px * 11) );max-width:calc( (var(--gridColWidth) * 10) + (var(--gridGutterWidth) * 11) );width:100%}.container.container__109{max-width:calc( (76px * 10) + (24px * 9) );max-width:calc( (var(--gridColWidth) * 10) + (var(--gridGutterWidth) * 9) );width:100%}.container.container__98{max-width:calc( (76px * 9) + (24px * 8) );max-width:calc( (var(--gridColWidth) * 9) + (var(--gridGutterWidth) * 8) );width:100%}.container.container__87{max-width:calc( (76px * 8) + (24px * 7) );max-width:calc( (var(--gridColWidth) * 8) + (var(--gridGutterWidth) * 7) );width:100%}.container.container__76{max-width:calc( (76px * 7) + (24px * 6) );max-width:calc( (var(--gridColWidth) * 7) + (var(--gridGutterWidth) * 6) );width:100%}.container.container__65{max-width:calc( (76px * 6) + (24px * 5) );max-width:calc( (var(--gridColWidth) * 6) + (var(--gridGutterWidth) * 5) );width:100%}.container.container__54{max-width:calc( (76px * 5) + (24px * 4) );max-width:calc( (var(--gridColWidth) * 5) + (var(--gridGutterWidth) * 4) );width:100%}.container.container__43{max-width:calc( (76px * 4) + (24px * 3) );max-width:calc( (var(--gridColWidth) * 4) + (var(--gridGutterWidth) * 3) );width:100%}.container.container__32{max-width:calc( (76px * 3) + (24px * 2) );max-width:calc( (var(--gridColWidth) * 3) + (var(--gridGutterWidth) * 2) );width:100%}.container.container__21{max-width:calc( (76px * 2) + (24px * 1) );max-width:calc( (var(--gridColWidth) * 2) + (var(--gridGutterWidth) * 1) );width:100%}.container.container__flex{display:flex;flex-direction:row;flex-wrap:nowrap;align-items:flex-start}@media(max-width:768px){.container.container__flex{flex-direction:column}}.container.container__fluid{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL);max-width:100%}.container.container__wide{max-width:var(--desktopWide);margin:0 auto}.container.container__hasBgImage{background-position:top;background-repeat:no-repeat;background-size:cover}.container.container__isDark{background-color:#010613;background-color:var(--colorBlack900);color:#fefffd;color:var(--colorWhite)}.container.container__isDark h1,.container.container__isDark h2,.container.container__isDark h3,.container.container__isDark .text__subtitle{color:#fefffd;color:var(--colorWhite)}.container.container__isGray{background-color:#f5f5f5;background-color:var(--colorBlack200)}.container.container__isGray blockquote:before{color:#fefffd;color:var(--colorWhite)}.container.container__hasNoPaddingX{padding-left:0;padding-right:0}.container.container__hasNoPaddingLeft{padding-left:0}.container.container__hasNoPaddingRight{padding-right:0}.container.container__hasNoPaddingY{padding-top:0;padding-bottom:0}.container.container__hasNoPaddingTop{padding-top:0}.container.container__hasNoPaddingBottom{padding-bottom:0}.container.container__hasPaddingYSmall{padding-top:24px;padding-top:var(--pL);padding-bottom:24px;padding-bottom:var(--pL)}.container.container__alignXleft{margin-left:0}@media(max-width:1196px){.container{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}@media(max-width:768px){.container{padding-top:64px;padding-top:var(--p3XL);padding-bottom:48px;padding-bottom:var(--p2XL)}.container.container__hasPaddingYSmall{padding-top:36px;padding-top:var(--pXL);padding-bottom:16px;padding-bottom:var(--pM)}}.header{width:100%;display:flex;align-items:center;padding-top:24px;padding-top:var(--pL);padding-bottom:24px;padding-bottom:var(--pL);position:relative}.header.header__isOpen .header_menus{transition:.5s all easeOutCirc;transform:translateX(0)}.header.header__isOpen .header_openLink{display:none}.header.header__isOpen .header_closeLink{display:inline-flex}.header{}@media(max-width:1196px){.header{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}.header_logo{line-height:0}.header_menus{flex-grow:1;display:flex}.header_menus nav:first-child{flex-grow:1;justify-content:center;align-items:center}.header_menus nav:last-child{margin-left:auto}@media(max-width:1024px){.header_menus{transition:.3s all easeOutExpo;transform:translateX(100%);background-color:#0b08a0;background-color:var(--colorSecondary);position:fixed;z-index:1;left:0;right:0;top:0;bottom:0;flex-wrap:wrap;flex-direction:column}.header_menus nav{width:100%}.header_menus nav:first-child{align-items:flex-end}.header_menus nav:first-child,.header_menus nav:last-child{flex-grow:1;justify-content:center}.header_menus nav:first-child ul,.header_menus nav:last-child ul{flex-direction:column;text-align:center}.header_menus nav:last-child{margin-top:auto;margin-bottom:36px;margin-bottom:var(--mXL);flex-direction:column}.header_menus nav:last-child div{margin-bottom:24px;margin-bottom:var(--mL)}}.header_openLink{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;color:#0496ff;color:var(--colorPrimary);display:none;font-size:1.4rem;position:absolute;padding:12px;padding:var(--pS);top:24px;top:var(--mL);right:24px;right:var(--mL)}@media(max-width:1024px){.header_openLink{display:inline-flex}}.header_closeLink{border:none;margin:0;padding:0;width:auto;overflow:visible;background:0 0;color:inherit;font:inherit;line-height:normal;-webkit-font-smoothing:inherit;-moz-osx-font-smoothing:inherit;-webkit-appearance:none;cursor:pointer;position:fixed;display:none;color:#fefffd;color:var(--colorWhite);font-size:1.4rem;padding:12px;padding:var(--pS);top:24px;top:var(--mL);right:24px;right:var(--mL);align-items:center;z-index:1}.header_closeLink svg{margin-left:4px;margin-left:var(--m2XS)}.footer{width:100%;padding:0 0 24px;padding:0 0 var(--pL)}.version{color:#999;color:var(--colorBlack400);font-size:.8em;text-align:right;font-style:italic}@media(max-width:1024px){.footer{text-align:center}}.footer_menus{width:100%;display:flex;justify-content:space-between;margin-top:4px;margin-top:var(--m2XS)}.footer_menus div:first-child{margin-right:24px;margin-right:var(--gridGutterWidth)}.footer_menus div ul{display:flex;flex-direction:row}.footer_menus div ul li{margin:0 8px;margin:0 var(--mXS)}.footer_menus div ul li:first-child{margin-left:0}.footer_menus div ul li:last-child{margin-right:0}.footer_menus div ul li a{color:#5e5e5e;color:var(--colorBlack600)}.footer_menus div ul+ul{margin-top:1rem}@media(max-width:1196px){.footer{padding-left:24px;padding-left:var(--pL);padding-right:24px;padding-right:var(--pL)}}@media(max-width:1024px){.footer_menus{justify-content:center;align-items:flex-start}.footer_menus div{margin:24px 76px 0;margin:var(--gridGutterWidth)var(--gridColWidth)0}.footer_menus div:first-child{margin-right:0}.footer_menus div ul{flex-direction:column}.footer_menus div ul li{text-align:left;margin:8px;margin:var(--mXS)}.footer_menus div ul li:first-child{margin-top:0}.footer_menus div ul li:first-child{margin-left:8px;margin-left:var(--mXS)}.footer_menus div ul li:last-child{margin-right:8px;margin-right:var(--mXS)}.footer_menus div ul+ul{flex-direction:column}}@media(max-width:620px){.footer_menus{justify-content:flex-start;flex-wrap:wrap}.footer_menus div{width:100%;margin:24px 0 0;margin:var(--gridGutterWidth)0 0}.footer_menus div ul li{text-align:center}}.footerMenu.footerMenu__isSmall{font-size:1.4rem}.footerMenu.footerMenu__alignRight ul{justify-content:flex-end}.divider>hr{border:1px solid #999;border:1px solid var(--colorBlack400)}.textContent{border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);padding:24px;padding:var(--mL);overflow-x:hidden;max-width:100%}.textContent hr{clear:both;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);margin-bottom:24px;margin-bottom:var(--mL)}.textContent details[open] summary{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent p,.textContent .highlight,.textContent details{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent p:last-child,.textContent .highlight:last-child,.textContent details:last-child{margin-bottom:0}.textContent p:global(.mb__0),.textContent .highlight:global(.mb__0),.textContent details:global(.mb__0){margin-bottom:0}.textContent p:global(.mb__3XL),.textContent .highlight:global(.mb__3XL),.textContent details:global(.mb__3XL){margin-bottom:64px;margin-bottom:var(--m3XL)}.textContent p+hr,.textContent blockquote+hr,.textContent pre+hr,.textContent ul+hr{margin-top:48px;margin-top:var(--m2XL)}.textContent h1{margin-bottom:36px;margin-bottom:var(--mXL)}@media(max-width:768px){.textContent h1{margin-bottom:36px;margin-bottom:var(--mXL)}}.textContent h1:global(.mb__0){margin-bottom:0}.textContent h1:global(.mb__S){margin-bottom:12px;margin-bottom:var(--mS)}.textContent h1:global(.mb__M){margin-bottom:16px;margin-bottom:var(--mM)}.textContent h2{margin-bottom:24px;margin-bottom:var(--mL)}.textContent h2:global(.mb__0){margin-bottom:0}.textContent h3{margin-bottom:16px;margin-bottom:var(--mM)}.textContent h3:global(.mb__0){margin-bottom:0}.textContent h4{margin-bottom:16px;margin-bottom:var(--mM)}.textContent h4:global(.mb__0){margin-bottom:0}.textContent h4:global(.mb__XL){margin-bottom:36px;margin-bottom:var(--mXL)}.textContent h4:global(.mb__3XL){margin-bottom:64px;margin-bottom:var(--m3XL)}.textContent h5{margin-bottom:12px;margin-bottom:var(--mS)}.textContent h5:global(.mb__0){margin-bottom:0}.textContent h6{margin-bottom:8px;margin-bottom:var(--mXS)}.textContent h6:global(.mb__0){margin-bottom:0}.textContent p+h2,.textContent ul+h2,.textContent ol+h2,.textContent blockquote+h2,.textContent .highlight+h2,.textContent details+h2,.textContent video+h2{margin-top:48px;margin-top:var(--m2XL)}.textContent p+h3,.textContent ul+h3,.textContent ol+h3,.textContent blockquote+h3,.textContent .highlight+h3,.textContent details+h3,.textContent video+h3{margin-top:36px;margin-top:var(--mXL)}.textContent p+h4,.textContent ul+h4,.textContent ol+h4,.textContent blockquote+h4,.textContent .highlight+h4,.textContent details+h4,.textContent video+h4{margin-top:24px;margin-top:var(--mL)}.textContent p+h5,.textContent ul+h5,.textContent ol+h5,.textContent blockquote+h5,.textContent .highlight+h5,.textContent details+h5,.textContent video+h5{margin-top:24px;margin-top:var(--mL)}.textContent{& iframe, video { margin-bottom: 24px; margin-bottom: var(--mL); }}.textContent ul{list-style-type:disc}.textContent ol{list-style-type:numbers}.textContent nav:not(:last-child){margin-bottom:24px;margin-bottom:var(--mL)}.textContent ul,.textContent ol{margin-left:24px;margin-left:var(--mL)}.textContent ul:not(:last-child),.textContent ol:not(:last-child){margin-bottom:24px;margin-bottom:var(--mL)}.textContent li{position:relative;margin-bottom:4px;margin-bottom:var(--m2XS)}.textContent li svg{left:calc(24px * -1);left:calc(var(--mL) * -1);top:4px;top:var(--m2XS);position:absolute}.textContent li:last-child{margin-bottom:0}.textContent li>ul{margin-top:4px;margin-top:var(--m2XS)}.textContent .textContent__noListStyle{list-style-type:none}.textContent blockquote{margin-bottom:16px;margin-bottom:var(--mM)}.textContent pre{padding:.8rem;overflow-x:scroll}.textContent code{background-color:#f5f5f5;background-color:var(--colorBlack200);font-size:.95em}.textContent button{margin-bottom:36px;margin-bottom:var(--mXL)}@media(max-width:768px){.textContent button{margin-bottom:24px;margin-bottom:var(--mL)}}.textContent button:global(.mb__0){margin-bottom:0}.textContent__marginTopLarge{margin-top:48px;margin-top:var(--m2XL)}.textContent__hasNoMarginTop{margin-top:0}summary{cursor:pointer}.aside{flex-shrink:0;margin-right:36px;margin-right:var(--mXL);max-width:calc( (76px * 3) + (24px * 2) );max-width:calc( (var(--gridColWidth) * 3) + (var(--gridGutterWidth) * 2) );width:100%;border:1px solid #f5f5f5;border:1px solid var(--colorBlack200);border-radius:4px}.aside_items{}.aside_item{padding:8px 12px;padding:var(--mXS)var(--mS);border-bottom:1px solid #f5f5f5;border-bottom:1px solid var(--colorBlack200)}.aside_item:last-child{border:none}.aside_item #TableOfContents{padding-left:8px;padding-left:var(--mXS)}.aside_item #TableOfContents>ul>li>ul{padding-left:8px;padding-left:var(--mXS)}.aside_subitems{padding-left:8px;padding-left:var(--mXS)}.aside_item-current{background-color:#f5f5f5;background-color:var(--colorBlack200)}.aside_item-current>a,.aside_item-current>span{font-weight:700}.aside_item_section{color:#5e5e5e;color:var(--colorBlack600);width:100%;display:inline-block}@media(max-width:768px){.aside{max-width:100%;margin-bottom:48px;margin-bottom:var(--m2XL)}} \ No newline at end of file diff --git a/design-principles/index.html b/design-principles/index.html index d8f5bdd7..5859ef0c 100644 --- a/design-principles/index.html +++ b/design-principles/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Design principles

Design principles

These overarching principles guide technical and governance decisions. They are fundamental and can only be changed through community consensus, based on a thorough impact assessment.

Each principle has a name, a rationale, and potential implementation examples or guidelines.

1. Never trust the services

A major goal of Open Terms Archive is to enable assessing the loyalty of services towards their end users. Since loyalty is not assumed, trust can not be warranted.

Cases

Several services have been observed:

  • blocking an IP or a user agent randomly;
  • pretending to encounter technical errors (500, 502…) instead of being explicit about their intention (robots.txt, 403…);
  • to not reflect actual updates in the “last update” date of their contractual documents;
  • changing the content of the same page based on user agent properties or source IP geolocation. When one accesses a supposedly already regionalized policy according to the URL, but gets a different content based on geolocation without any information nor ability to access other regional policies, we consider it misleading and disloyal.

Examples of consequential choices

  • Do not use “last update” date in documents or headers for metadata.

2. Do not require trust in maintainers

Open Terms Archive maintainers should not need to be trusted by users more than the services it enables assessing.

Cases

  • Collections can be unmaintained.
  • Maintainers can filter out content that could be relevant from the perspective of other maintainers.
  • A server can encounter technical problems and miss updates.

Examples of consequential choices

  • Always keep an untouched snapshot of the source documents.
  • Use cryptographic signatures to ensure the database can be authenticated.
  • Enable terms collection to be replicated by anyone.
  • Support duplication across collections as this increases the resilience of the network. It will be up to reusers to decide which source they prefer in case of divergence.

3. Obtain documents like a user would

In order to guarantee legal relevance, source documents should only be ones that end users of the service are themselves receiving. Following principle 1, technical workarounds to obtain some version of the source documents that are more easily handled by machines cannot be trusted to have the same content as the ones intended for end users.

Cases

  • Accessing the same URL from a differently geolocated IP address will change the contents in some services.

Examples of consequential choices

  • Scrape HTML even if one could obtain the contractual content from an API.
+Close

Design principles

These overarching principles guide technical and governance decisions. They are fundamental and can only be changed through community consensus, based on a thorough impact assessment.

Each principle has a name, a rationale, and potential implementation examples or guidelines.

1. Never trust the services

A major goal of Open Terms Archive is to enable assessing the loyalty of services towards their end users. Since loyalty is not assumed, trust can not be warranted.

Cases

Several services have been observed:

  • blocking an IP or a user agent randomly;
  • pretending to encounter technical errors (500, 502…) instead of being explicit about their intention (robots.txt, 403…);
  • to not reflect actual updates in the “last update” date of their contractual documents;
  • changing the content of the same page based on user agent properties or source IP geolocation. When one accesses a supposedly already regionalized policy according to the URL, but gets a different content based on geolocation without any information nor ability to access other regional policies, we consider it misleading and disloyal.

Examples of consequential choices

  • Do not use “last update” date in documents or headers for metadata.

2. Do not require trust in maintainers

Open Terms Archive maintainers should not need to be trusted by users more than the services it enables assessing.

Cases

  • Collections can be unmaintained.
  • Maintainers can filter out content that could be relevant from the perspective of other maintainers.
  • A server can encounter technical problems and miss updates.

Examples of consequential choices

  • Always keep an untouched snapshot of the source documents.
  • Use cryptographic signatures to ensure the database can be authenticated.
  • Enable terms collection to be replicated by anyone.
  • Support duplication across collections as this increases the resilience of the network. It will be up to reusers to decide which source they prefer in case of divergence.

3. Obtain documents like a user would

In order to guarantee legal relevance, source documents should only be ones that end users of the service are themselves receiving. Following principle 1, technical workarounds to obtain some version of the source documents that are more easily handled by machines cannot be trusted to have the same content as the ones intended for end users.

Cases

  • Accessing the same URL from a differently geolocated IP address will change the contents in some services.

Examples of consequential choices

  • Scrape HTML even if one could obtain the contractual content from an API.
\ No newline at end of file diff --git a/en/sitemap.xml b/en/sitemap.xml index 224da082..ac557eeb 100644 --- a/en/sitemap.xml +++ b/en/sitemap.xml @@ -1 +1 @@ -https://docs.opentermsarchive.org/https://docs.opentermsarchive.org/collections/metadata/https://docs.opentermsarchive.org/api/node/https://docs.opentermsarchive.org/navigate-history/https://docs.opentermsarchive.org/api/collection/https://docs.opentermsarchive.org/collections/governance/https://docs.opentermsarchive.org/collections/create/https://docs.opentermsarchive.org/api/federation/https://docs.opentermsarchive.org/subscribe-rss/https://docs.opentermsarchive.org/contributing-terms/https://docs.opentermsarchive.org/collections/federation/https://docs.opentermsarchive.org/collections/https://docs.opentermsarchive.org/api/https://docs.opentermsarchive.org/guidelines/https://docs.opentermsarchive.org/design-principles/https://docs.opentermsarchive.org/guidelines/choosing-selectors/https://docs.opentermsarchive.org/memos/copywriting-reference/https://docs.opentermsarchive.org/guidelines/declaring/https://docs.opentermsarchive.org/memos/how-to-publish/https://docs.opentermsarchive.org/memos/https://docs.opentermsarchive.org/guidelines/reviewing/https://docs.opentermsarchive.org/guidelines/targeting/ \ No newline at end of file +https://docs.opentermsarchive.org/https://docs.opentermsarchive.org/terms/how-to-navigate-history/https://docs.opentermsarchive.org/collections/metadata/https://docs.opentermsarchive.org/api/node/https://docs.opentermsarchive.org/api/collection/https://docs.opentermsarchive.org/collections/governance/https://docs.opentermsarchive.org/terms/https://docs.opentermsarchive.org/terms/tracking-new-terms/https://docs.opentermsarchive.org/collections/create/https://docs.opentermsarchive.org/terms/declarations-maintenance/https://docs.opentermsarchive.org/api/federation/https://docs.opentermsarchive.org/collections/federation/https://docs.opentermsarchive.org/terms/reference/https://docs.opentermsarchive.org/collections/https://docs.opentermsarchive.org/api/https://docs.opentermsarchive.org/guidelines/https://docs.opentermsarchive.org/design-principles/https://docs.opentermsarchive.org/guidelines/choosing-selectors/https://docs.opentermsarchive.org/memos/copywriting-reference/https://docs.opentermsarchive.org/guidelines/declaring/https://docs.opentermsarchive.org/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/https://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/https://docs.opentermsarchive.org/memos/how-to-publish/https://docs.opentermsarchive.org/memos/https://docs.opentermsarchive.org/guidelines/reviewing/https://docs.opentermsarchive.org/guidelines/targeting/ \ No newline at end of file diff --git a/fr/index.html b/fr/index.html index 9eb4b4d5..770b2a9d 100644 --- a/fr/index.html +++ b/fr/index.html @@ -1,4 +1,4 @@ -Open Terms Archive - Pour commencer

Choosing selectors

Selectors are used in Open Terms Archive declarations to specify the parts of documents that should be recorded.

What are selectors

Selectors are used in the select and remove keys of an Open Terms Archive declaration.

The “selectors” referred to are defined by the W3C Selectors standard, more commonly known as “CSS Selectors”.

An easy-to-read introduction to CSS Selectors can be found on mdn web docs.

Choosing durable selectors eases maintenance

The design of web pages containing terms can evolve over time, leading to changes in their HTML (more precisely, to their DOM) which may render ineffective the selectors that were initially chosen. That means they may no longer target the significant parts, breaking the ability to continuously record terms changes. When this happens, selectors must be updated to specify the meaningful parts of the terms.

It is possible to reduce the frequency of human intervention on the selectors by choosing some that are least likely to become obsolete even when changes occur on the document structure. Decreasing the cost of this maintenance increases the likelihood that terms are continuously tracked.

Guidelines

While there is no single right way to choose durable selectors, as it remains intrinsically subjective and dependent on the document itself, following the guidelines below is likely to yield durable selectors.

Simple

Prefer simple selectors over compound ones, and compound ones over combinator ones, as they are more readable and make less assumptions on future changes.

In particular, avoid deep nesting of elements and pseudo-classes. Such selectors rely not only on the targeted content structure but also on the content around it. The likelihood that at least one block in the tree changes on a page update increases, making the selector brittle.

Examples

  • #content or [role="main"] are better than #content .inner or [role="main"] > .content-block.
  • main > div > #article > .tos is a bad selector because of deep nesting.
  • div:nth-child(2) is a bad selector because of the usage of a pseudo-class.

Named

Prefer selectors whose names are representative of the parts they select, as they are evidence of an intention by the service provider, and thus more likely to stay valid through design changes.

Conversely, avoid class names being or containing series of alphanumeric characters. Those are most likely to be generated and to change on the next page update.

Examples

  • .tos or #legal-notice are better than main or .content.
  • .dez68h or .tos-cpoxw27 are bad selectors because they are likely automatically generated.
Example with HTML

For the following HTML code:

...
+Close

Choosing selectors

Selectors are used in Open Terms Archive declarations to specify the parts of documents that should be recorded.

What are selectors

Selectors are used in the select and remove keys of an Open Terms Archive declaration.

The “selectors” referred to are defined by the W3C Selectors standard, more commonly known as “CSS Selectors”.

An easy-to-read introduction to CSS Selectors can be found on mdn web docs.

Choosing durable selectors eases maintenance

The design of web pages containing terms can evolve over time, leading to changes in their HTML (more precisely, to their DOM) which may render ineffective the selectors that were initially chosen. That means they may no longer target the significant parts, breaking the ability to continuously record terms changes. When this happens, selectors must be updated to specify the meaningful parts of the terms.

It is possible to reduce the frequency of human intervention on the selectors by choosing some that are least likely to become obsolete even when changes occur on the document structure. Decreasing the cost of this maintenance increases the likelihood that terms are continuously tracked.

Guidelines

While there is no single right way to choose durable selectors, as it remains intrinsically subjective and dependent on the document itself, following the guidelines below is likely to yield durable selectors.

Simple

Prefer simple selectors over compound ones, and compound ones over combinator ones, as they are more readable and make less assumptions on future changes.

In particular, avoid deep nesting of elements and pseudo-classes. Such selectors rely not only on the targeted content structure but also on the content around it. The likelihood that at least one block in the tree changes on a page update increases, making the selector brittle.

Examples

  • #content or [role="main"] are better than #content .inner or [role="main"] > .content-block.
  • main > div > #article > .tos is a bad selector because of deep nesting.
  • div:nth-child(2) is a bad selector because of the usage of a pseudo-class.

Named

Prefer selectors whose names are representative of the parts they select, as they are evidence of an intention by the service provider, and thus more likely to stay valid through design changes.

Conversely, avoid class names being or containing series of alphanumeric characters. Those are most likely to be generated and to change on the next page update.

Examples

  • .tos or #legal-notice are better than main or .content.
  • .dez68h or .tos-cpoxw27 are bad selectors because they are likely automatically generated.
Example with HTML

For the following HTML code:

...
   <div id="globalContainer" role="main">
     <div class="tos_title clearfix">Privacy Policy</div>
     <div class="article_content" id="tos_content">
@@ -46,7 +46,7 @@
   ".af23jf45",
   ".xlms051"
 ]
-

Strategies

Start wide, narrow down over time

If in doubt about a selector, prefer making a wide selection and then removing the non-significant parts within this selection: obsolete selectors that include too much are more likely to be spotted than too specific ones that will not include new content, as anyone reading the versions changes will spot irrelevant content being added, but will not see content that is not tracked.

Use range selectors

Range selectors enable to select content that starts in one block and ends in another block that are not in the same tree. While they are more complex than element selectors, it is preferable to use a range selector whose start and end abide by the guidelines above than to use a bad plain selector.

Example

Example with HTML

For the following HTML code:

...
+

Strategies

Start wide, narrow down over time

If in doubt about a selector, prefer making a wide selection and then removing the non-significant parts within this selection: obsolete selectors that include too much are more likely to be spotted than too specific ones that will not include new content, as anyone reading the versions changes will spot irrelevant content being added, but will not see content that is not tracked.

Use range selectors

Range selectors enable to select content that starts in one block and ends in another block that are not in the same tree. While they are more complex than element selectors, it is preferable to use a range selector whose start and end abide by the guidelines above than to use a bad plain selector.

Example

Example with HTML

For the following HTML code:

...
   <div class="container">
     <div id="nav-menu">
       <ul>
diff --git a/guidelines/declaring/index.html b/guidelines/declaring/index.html
index 423e1bea..42008577 100644
--- a/guidelines/declaring/index.html
+++ b/guidelines/declaring/index.html
@@ -1,8 +1,8 @@
-Open Terms Archive - Declaring documents

This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in Contributing Terms.

Declaring documents

Service name

Casing

  • In order to find the service name casing, rely first on the page title (easily found in search results). Do not rely on the logo as it can be stylized differently. Example with Facebook: +Close

This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in the Terms reference.

Declaring documents

Service name

Casing

  • In order to find the service name casing, rely first on the page title (easily found in search results). Do not rely on the logo as it can be stylized differently. Example with Facebook: facebook search
  • If it is still ambiguous, rely on Wikipedia as a source. However, make sure to differentiate the service from the provider company’s name. Example with “DeviantArt”, a service (which used to be stylized deviantArt until 2014) by the limited liability company “deviantArt”: deviantArt search

Terms used by several services

  • If you want to add terms which happen to be shared with another service from the same parent company, be specific in naming the exact service you want to track. For instance, you may find that a company like Github uses the same terms for its code hosting and its AI assistant. While this does not mean that the terms for GitHub (code hosting) are the only terms of GitHub Copilot (assistant), it does mean that these two services have terms that are represented in the same document. In tracking terms for one of these services, say Github Copilot, be specific in naming it as the service you want to track. This way, if GitHub was to introduce dedicated terms for each of these services in the future, their locations can be updated without having to create new terms since the service already existed before.

Service ID

Normalisation

  1. For non-roman alphabets (Cyrillic, ideograms…), use the service-provided transliteration.
  2. For diacritics: normalise the string to its NFD normal UTF form, then remove the entire combining character class. Details.
  3. As a last resort, use the domain name.

Provider prefixing

  • If you encounter a document you want to add to a service, yet find that it would override an already-declared document for this service such as Terms of Service or Privacy Policy, and that the only solution you see would be to create a new terms type that would contain the name of the feature, then it is likely you should declare a new service, potentially duplicating existing documents.

Example: the Facebook Community Payments terms are Terms of Service. The only way to declare them in the Facebook service would be to add a “Community Payments Terms” terms type as they would otherwise conflict with Facebook’s Terms of Service. It is better to declare a new service called “Facebook Payments” with its own Terms of Service. It turns out that this service also has a developer agreement, independent from the main Facebook service.

Facebook Community Payments

  • As a last resort, rely on the trademark.

Example: Apple’s App Store uses only generic terms (“app” and “store”). However, it is of common use to mention “the App Store” as Apple’s. To help us decide whether it should be prefixed or not, we can check that Apple has trademarked “App Store”. The service can thus be named “App Store”, without prefixing.


Usual noise

Noise is unwanted content in versions.

Irrelevant content

The first type of noise we try to remove is content that is not relevant legally speaking, and that harms document readability.

CSS selectors are a first step as they permit to select an area instead of the whole page, but they let pass through content such as headers, footers, buttons, drop-down lists…

Filtering permits to get rid of the remaining irrelevant content.

A drop-down list let user select which document he would like to see but this list doesn’t interest us in the final document.

HTML file :

<div class="filter-holder">
   <select class="filter-options">
@@ -54,6 +54,6 @@
 We found that those contents are usually hypertext links, since two links can point to the same website yet they can be written differently. A case in point are links passing parameters : a change in parameters will not change where the link point at.

A link has a parameter ‘h=’ changing too frequently and irrelevant to the adress the link point to.

HTML file :

You can only use our copyrights or <a href="https://l.facebook.com/l.php?u=https%3A%2F%2Fen.facebookbrand.com%2Ftrademarks%2F&amp;h=AT0_izDHO3yJuXJuJJeWQyJFVilQqIDOA3oMwr51t6gEq1q4UbyH2VtU7UhNzhg1LH0YzUHAjw0TADuoufWgb_YEuzoFpvyIR8_4rkUfjDXxUw3q1KmpsYL_H3C4OIm3xHzrUZRatmWQ6PAk">trademarks (or any similar marks)</a>
 

Markdown file :

You can only use our copyrights or [trademarks (or any similar marks)](https://l.facebook.com/l.php?u=https%3A%2F%2Fen.facebookbrand.com%2Ftrademarks%2F&h=AT1XEFWtw25SbFSSD7W2MOS1LQIsUwaUrq4qh5dNmI21qm42JE5lUiv9g8MsTSnvi3DjYfJxOPoBxEKyBQjo7qkxfcUkDzedQzBLWgGJYWC6CwDBI0S5pefB4oiuh8Jo63phreoUKQ3BF4O5)
 

Wished Markdown file :

You can only use our copyrights or [trademarks (or any similar marks)](https://l.facebook.com/l.php?u=https%3A%2F%2Fen.facebookbrand.com%2Ftrademarks%2F)
-

Solution

Write a filter in the declaration.


Using the graphical contribution interface

Blank page when contacting support

While using the graphical user interface for contribution, you may come across a blank page when trying to contact the team.

This may be caused by the lack of a mail program being set up in your browser.

Solution

If you use Gmail, for example, these instructions explain how to add Gmail as the default mailto handler in Chrome. Try following them and trying again.

+

Solution

Write a filter in the declaration.

\ No newline at end of file diff --git a/guidelines/index.xml b/guidelines/index.xml index 4b3f71d6..decb8df0 100644 --- a/guidelines/index.xml +++ b/guidelines/index.xml @@ -2,7 +2,7 @@ What are selectors Selectors are used in the select and remove keys of an Open Terms Archive declaration. The “selectors” referred to are defined by the W3C Selectors standard, more commonly known as “CSS Selectors”. An easy-to-read introduction to CSS Selectors can be found on mdn web docs. -Choosing durable selectors eases maintenance The design of web pages containing terms can evolve over time, leading to changes in their HTML (more precisely, to their DOM) which may render ineffective the selectors that were initially chosen.Declaring documentshttps://docs.opentermsarchive.org/guidelines/declaring/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/declaring/This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in Contributing Terms. +Choosing durable selectors eases maintenance The design of web pages containing terms can evolve over time, leading to changes in their HTML (more precisely, to their DOM) which may render ineffective the selectors that were initially chosen.Declaring documentshttps://docs.opentermsarchive.org/guidelines/declaring/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/declaring/This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in the Terms reference. Declaring documents Service name Casing In order to find the service name casing, rely first on the page title (easily found in search results). Do not rely on the logo as it can be stylized differently. Example with Facebook: If it is still ambiguous, rely on Wikipedia as a source. However, make sure to differentiate the service from the provider company&rsquo;s name.Reviewing contributionshttps://docs.opentermsarchive.org/guidelines/reviewing/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/reviewing/Reviewing contributions Thank you for showing interest in reviewing contributions made to Open Terms Archive. This document is intended to help you get started and provide some guidelines for reviewing contributions. Why is this important? We want to make sure that the contributions made to the project are of high quality and that they are in line with the vision of the project. We also want to make sure that the contributions are reviewed in a timely manner so that the contributors can get feedback and continue to contribute to the project.Targetinghttps://docs.opentermsarchive.org/guidelines/targeting/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/targeting/What to track? Can I track terms that are not applicable yet? Yes. For example, documents that would start applying at date in the future are legitimate candidates for tracking. You can this way track if their terms change even before they are applied. \ No newline at end of file diff --git a/guidelines/reviewing/index.html b/guidelines/reviewing/index.html index 6a7bad33..3b2c8ea2 100644 --- a/guidelines/reviewing/index.html +++ b/guidelines/reviewing/index.html @@ -1,14 +1,14 @@ -Open Terms Archive - Reviewing contributions

Reviewing contributions

Thank you for showing interest in reviewing contributions made to Open Terms Archive. This document is intended to help you get started and provide some guidelines for reviewing contributions.

Why is this important?

We want to make sure that the contributions made to the project are of high quality and that they are in line with the vision of the project. We also want to make sure that the contributions are reviewed in a timely manner so that the contributors can get feedback and continue to contribute to the project. +Close

Reviewing contributions

Thank you for showing interest in reviewing contributions made to Open Terms Archive. This document is intended to help you get started and provide some guidelines for reviewing contributions.

Why is this important?

We want to make sure that the contributions made to the project are of high quality and that they are in line with the vision of the project. We also want to make sure that the contributions are reviewed in a timely manner so that the contributors can get feedback and continue to contribute to the project. This is where volunteer reviewers come in to help. Reviewers are people who have volunteered to review contributions made to the project. They are not paid for their work, but they are given credit for their work.

Who can do it?

Anyone can review contributions. As hinted before, most of the contributions made to Open Terms Archive are contractual documents that are to be tracked. Therefore, you don’t need to be a programmer or have any technical knowledge. You just need to be able to read and understand the contribution and provide feedback where necessary.

How long and complex will it be?

It depends on the contribution. Some contributions may be spot on and can be reviewed in a few minutes. Other contributions may require a more detailed review and changes to be made and can take longer. We estimate it to take 3 to 15 mins for one to review a document. The first reviews might be a bit longer as reviewers get familiar with the process, and will speed up with time.

Where to start

To get started, we will need to understand a few things. The nature of the contributions you will be reviewing, where to get the contributions to review and the tools that will help you in reviewing the contributions.

The nature of the contributions

The contributions you will be reviewing are contractual documents of digital services. These are documents that govern the relationship between two or more parties. -They are not the original documents, but rather the terms extracted from these documents. If the terms are represented accurately, it will be easier to follow on with any subsequent changes in the document. Contributors track these documents (sometimes, anonymously) by submitting a pull request either using a tool that helps contributors add documents to the project, the GUI contributing tool, or by creating a JSON file and adding it via a pull request. You can find more information about pull requests here.

There are three types of contributions you’ll come across:

  • adding declarations to a collection;
  • updating declarations in a collection;
  • removing declarations from a collection.

The method used to review each of these types of contribution varies, and you’ll find a detailed explanation below.

Where to find the contributions

The contributions can be found in the form of pull requests in the repository of the collection you want to work on. For example, for the Contrib collection, they are visible under the pull requests tab of the contrib-declarations repository..

How To Review Pull Requests that Add Declarations

Your focus should be on two aspects: accuracy and quality.

  • Accuracy is about making sure that the contributed declaration is accurate and tracks significant sections of the terms that actually make a legal impact when updated.
  • Durability is about making sure that the contributed declaration is durable over time, with CSS selectors that will make sure the document will need little maintenance over time.

Step-by-step Review Guide

  1. Click on the Inspect the declaration link to view the declaration in a graphical user interface.
  2. Use the link provided in the URL section of the contribution tool to check out the original document.
  3. Verify that the name of the service matches the JSON file and complies with the guidelines.
  4. Quickly scan the document to ensure that the correct term type has been selected. To determine the term type, consider who the intended audience is and what the document is discussing. You can also refer to the terms types list to find the best term type for the document.
  5. Confirm that the selected area of the document contains only one term type and does not include any other types.
  6. Check both the significant and insignificant parts of the document. Ensure that the suggested selectors abide by the selectors guidelines.
    • Ensure that the significant parts do not include navigation items, contact links, or other insignificant details that may cause confusion by triggering a change detection when the legal terms have actually not been updated.
  7. Verify the version of the document in the contribution tool by clicking on the Verify version button.
  8. Ensure that all checks generated by the OTA-bot are manually checked.
  9. When you confirm that the term contribution has been made to the correct collection, proceed to add a review.
  10. Merge the contribution.

How To Review Pull Requests that Update Declarations

When some terms can no longer be tracked by the Open Terms Archive engine, an issue is created in the collection repository. This issue contains the details on why the document cannot be tracked and the date the challenge was encountered. +They are not the original documents, but rather the terms extracted from these documents. If the terms are represented accurately, it will be easier to follow on with any subsequent changes in the document. Contributors track these documents (sometimes, anonymously) by submitting a pull request either using a tool that helps contributors add documents to the project, the GUI contributing tool, or by creating a JSON file and adding it via a pull request. You can find more information about pull requests here.

There are three types of contributions you’ll come across:

  • adding declarations to a collection;
  • updating declarations in a collection;
  • removing declarations from a collection.

The method used to review each of these types of contribution varies, and you’ll find a detailed explanation below.

Where to find the contributions

The contributions can be found in the form of pull requests in the repository of the collection you want to work on. For example, for the Contrib collection, they are visible under the pull requests tab of the contrib-declarations repository..

How To Review Pull Requests that Add Declarations

Your focus should be on two aspects: accuracy and quality.

  • Accuracy is about making sure that the contributed declaration is accurate and tracks significant sections of the terms that actually make a legal impact when updated.
  • Durability is about making sure that the contributed declaration is durable over time, with CSS selectors that will make sure the document will need little maintenance over time.

Step-by-step Review Guide

  1. Click on the Inspect the declaration link to view the declaration in a graphical user interface.
  2. Use the link provided in the URL section of the contribution tool to check out the original document.
  3. Verify that the name of the service matches the JSON file and complies with the guidelines.
  4. Quickly scan the document to ensure that the correct term type has been selected. To determine the term type, consider who the intended audience is and what the document is discussing. You can also refer to the terms types list to find the best term type for the document.
  5. Confirm that the selected area of the document contains only one term type and does not include any other types.
  6. Check both the significant and insignificant parts of the document. Ensure that the suggested selectors abide by the selectors guidelines.
    • Ensure that the significant parts do not include navigation items, contact links, or other insignificant details that may cause confusion by triggering a change detection when the legal terms have actually not been updated.
  7. Verify the version of the document in the contribution tool by clicking on the Verify version button.
  8. Ensure that all checks generated by the OTA-bot are manually checked.
  9. When you confirm that the term contribution has been made to the correct collection, proceed to add a review.
  10. Merge the contribution.

How To Review Pull Requests that Update Declarations

When some terms can no longer be tracked by the Open Terms Archive engine, an issue is created in the collection repository. This issue contains the details on why the document cannot be tracked and the date the challenge was encountered. Contributors are then required to update the declaration in order to bring back the tracking of the terms. The updates can be made using the contribution tool and it’s effects will be similar to the one seen when adding declaration but with a slight change. -The pull request created will consist of fewer checks than those that add declarations, as some aspects have already been previously checked, such as the name of the service and its ID. The checks will guide the reviewer on the key things to look out for during the review process, and a link to inspect the declaration.

For pull requests that update declarations, you should focus should be on two things: history file and declaration.

  • History file: The history file is a JSON file that keeps track of a service declaration changes. It contains a validUntil property that specifies the date a specific version of a service declaration was last effective. You have to confirm that this date is the same as the date in the issue opened for the declaration when the bot couldn’t track it for the first time. This issue is usually included in the pull request message. The history file is updated with every update pull request. You can find more information about the history file here.
  • Declaration: for update pull requests, you only look at the selectors to make sure they are simple and also verify the generated version is ok.

Step-by-step Review Guide

  1. Click on the inspect the declaration suggestion link to view contribution using the contribution tool.
  2. Check both the significant and insignificant parts of the document. Ensure that the suggested selectors abide by the selectors guidelines.
  3. Verify the version of the document in the contribution tool by clicking on the verify version button.
  4. Open the issue linked with the pull request. Confirm the date when the declaration was last tracked from the bot’s comment.
  5. Compare it with the validUntil property in the history file under the Files changes section of the pull request. If the dates are the same, proceed to approve the pull request.
  6. Merge the contribution.

You can read more about maintaining declarations from the official documentation.

When to Make Changes to a Contribution

When you spot an error in a contribution, instead of asking the author to implement these changes, we usually recommend you fix it, especially for first time contributors, in order to speed up the process. You can make your corrections directly through the graphical user interface and send the document. This will create an update in the already existing pull request and a new comment will be generated by the OTA-bot.

In some special cases, the correction may have to do with the service name. Such changes modify the branch name, hence, creating a new pull request instead of updating the initial pull request as their names are now different. In any case, it’s always important to let the contributor know about any changes or corrections you make to their contribution.

Editing a Service ID

When contributing to the project, reviewers may need to modify the Service ID of a service that is being added for tracking. This is often necessary when the service being tracked is in a language other than English, such as Chinese or French. In these cases, the Service ID usually reflects the transliteration of the service name (written in the native language). The documentation provides more information on this. It is important to note that the contributor can be very crucial in providing an accurate transliteration of the service name especially if the reviewer does not know the service’s native language.

Since the Service ID is used as the file name of the JSON file associated with the service, it is necessary to change the file name to reflect the transliteration. Here are the steps to follow:

  1. Open the pull request associated with the contribution and service.
  2. Navigate to the “Files changed” tab of the pull request. Here, you will see the files being changed by the contribution, including the JSON file of the service.
  3. To edit the file, click on the three dots button on the right side of the file name and select “Edit file”. This will open the file in the Github editor.
  4. From here, you can change the file name from the current Service ID to the new Service ID, which represents the transliteration of the service name.
  5. Once you have made the changes, commit them and review the pull request as usual. If everything checks out, you can merge the pull request.

Running Tests

Status checks are required to pass before merging can take place. This ensures that automated tests (through “Continuous Integration”, or CI) confirm the contribution will be readable by the Open Terms Archive engine.

These tests should run automatically. However, under some circumstances, the tests might need to be triggered manually. To that end, navigate to the “Actions” tab of the collections repository, and look for the name of the contribution where tests are not run. Once located in the list, click on the entry name, and click on “Re-run all jobs” at the top right.

Running Tests From a Fork

If the contribution comes from a fork rather than from the bot, the checks will not appear in the Actions tab, as they cannot be run from a different repository. In order to run checks from a fork, you need to create a new branch in the collection repository, with the contents of the branch in the fork. This operation can only be done through the command-line. Assuming you already have cloned the collection repository:

  1. Ensure you have the latest version of the code with git checkout main && git pull.
  2. Create a new branch, preferably with the name of the service to be added: git checkout -b add_<service_name>_<terms_type>.
  3. Pull the contribution from the fork: git pull https://github.com/<contributor_name>/<collection_name> <branch_name_in_the_fork>:add_<service_name>_<terms_type>. The branch name used in the fork can be found in the pull request page, right under the title.
  4. Push your branch to the original collection repository: git push origin add_<service_name>_<terms_type>.

As you did not push to the source branch but instead created a copy of that branch in the collection repository, the pull request itself will not mention a new push, and GitHub will suggest that you create a new pull request. In order to keep pull request authorship clear for contributors, please keep the original pull request instead: since the checked-in code is now pushed by a trusted author, the CI should run. And since the commit IDs are the same in the fork and in the original branch, the status checks will update in the original pull request when you refresh the page, without the need to create a new pull request.

Once the pull request has been merged, delete the copy you made of the branch with git push origin -d add_<service_name>_<terms_type>.

Debugging Failing Tests

When tests fail, you can follow these steps to diagnose and address the issue:

  1. Begin by analyzing any error messages or warnings provided by the test output. These messages can often provide meaningful information to identify the source of the problem. Pay attention to specific issues such as schema validation errors, inaccessible web locations or inaccessible content selection.

  2. For a deeper investigation, you can access the snapshots and versions generated during the test run. Navigate to the summary page of the failing workflow. Scroll down to the “Artifacts” section located at the bottom of the page. Click on snapshots_and_versions to download them.

  3. Inside the downloaded archive you will be able to inspect the snapshot file related to the terms that failed. Ensure the document downloaded by the engine is the correct one and that the terms content is present. Sometimes a login wall or a cookies wall can block access to the content.

  4. If the snapshot is the proper one, you can examine the generated version to check the accuracy of content selection.

If tests keep on failing

If the tests fail systematically in CI but there is at least one environment in which all tests pass, it is allowed to use admin powers to force the merge.

For example, tests may fail in CI because of a 403 Access Denied error, but succeed when run on a development machine.

Bypassing protection is allowed because:

  • if the engine is updated, the problem could correct itself;
  • if it’s an anti-bot protection, it can stop from one day to the next;
  • adding the terms prevents duplicate suggestions for additions;
  • a service can encounter this type of error after being merged, so there is no reason to prevent it from being added with this error.

Merging the Pull Request

Beyond status checks, additional restriction requires branches to be up to date before merging. This ensures that the contribution has been tested with the latest version of the collection. This appears as a “This branch is out-of-date with the base branch” warning on a pull request. +The pull request created will consist of fewer checks than those that add declarations, as some aspects have already been previously checked, such as the name of the service and its ID. The checks will guide the reviewer on the key things to look out for during the review process, and a link to inspect the declaration.

For pull requests that update declarations, you should focus should be on two things: history file and declaration.

  • History file: The history file is a JSON file that keeps track of a service declaration changes. It contains a validUntil property that specifies the date a specific version of a service declaration was last effective. You have to confirm that this date is the same as the date in the issue opened for the declaration when the bot couldn’t track it for the first time. This issue is usually included in the pull request message. The history file is updated with every update pull request. You can find more information about the history file here.
  • Declaration: for update pull requests, you only look at the selectors to make sure they are simple and also verify the generated version is ok.

Step-by-step Review Guide

  1. Click on the inspect the declaration suggestion link to view contribution using the contribution tool.
  2. Check both the significant and insignificant parts of the document. Ensure that the suggested selectors abide by the selectors guidelines.
  3. Verify the version of the document in the contribution tool by clicking on the verify version button.
  4. Open the issue linked with the pull request. Confirm the date when the declaration was last tracked from the bot’s comment.
  5. Compare it with the validUntil property in the history file under the Files changes section of the pull request. If the dates are the same, proceed to approve the pull request.
  6. Merge the contribution.

You can read more about maintaining declarations from the official documentation.

When to Make Changes to a Contribution

When you spot an error in a contribution, instead of asking the author to implement these changes, we usually recommend you fix it, especially for first time contributors, in order to speed up the process. You can make your corrections directly through the graphical user interface and send the document. This will create an update in the already existing pull request and a new comment will be generated by the OTA-bot.

In some special cases, the correction may have to do with the service name. Such changes modify the branch name, hence, creating a new pull request instead of updating the initial pull request as their names are now different. In any case, it’s always important to let the contributor know about any changes or corrections you make to their contribution.

Editing a Service ID

When contributing to the project, reviewers may need to modify the Service ID of a service that is being added for tracking. This is often necessary when the service being tracked is in a language other than English, such as Chinese or French. In these cases, the Service ID usually reflects the transliteration of the service name (written in the native language). The documentation provides more information on this. It is important to note that the contributor can be very crucial in providing an accurate transliteration of the service name especially if the reviewer does not know the service’s native language.

Since the Service ID is used as the file name of the JSON file associated with the service, it is necessary to change the file name to reflect the transliteration. Here are the steps to follow:

  1. Open the pull request associated with the contribution and service.
  2. Navigate to the “Files changed” tab of the pull request. Here, you will see the files being changed by the contribution, including the JSON file of the service.
  3. To edit the file, click on the three dots button on the right side of the file name and select “Edit file”. This will open the file in the Github editor.
  4. From here, you can change the file name from the current Service ID to the new Service ID, which represents the transliteration of the service name.
  5. Once you have made the changes, commit them and review the pull request as usual. If everything checks out, you can merge the pull request.

Running Tests

Status checks are required to pass before merging can take place. This ensures that automated tests (through “Continuous Integration”, or CI) confirm the contribution will be readable by the Open Terms Archive engine.

These tests should run automatically. However, under some circumstances, the tests might need to be triggered manually. To that end, navigate to the “Actions” tab of the collections repository, and look for the name of the contribution where tests are not run. Once located in the list, click on the entry name, and click on “Re-run all jobs” at the top right.

Running Tests From a Fork

If the contribution comes from a fork rather than from the bot, the checks will not appear in the Actions tab, as they cannot be run from a different repository. In order to run checks from a fork, you need to create a new branch in the collection repository, with the contents of the branch in the fork. This operation can only be done through the command-line. Assuming you already have cloned the collection repository:

  1. Ensure you have the latest version of the code with git checkout main && git pull.
  2. Create a new branch, preferably with the name of the service to be added: git checkout -b add_<service_name>_<terms_type>.
  3. Pull the contribution from the fork: git pull https://github.com/<contributor_name>/<collection_name> <branch_name_in_the_fork>:add_<service_name>_<terms_type>. The branch name used in the fork can be found in the pull request page, right under the title.
  4. Push your branch to the original collection repository: git push origin add_<service_name>_<terms_type>.

As you did not push to the source branch but instead created a copy of that branch in the collection repository, the pull request itself will not mention a new push, and GitHub will suggest that you create a new pull request. In order to keep pull request authorship clear for contributors, please keep the original pull request instead: since the checked-in code is now pushed by a trusted author, the CI should run. And since the commit IDs are the same in the fork and in the original branch, the status checks will update in the original pull request when you refresh the page, without the need to create a new pull request.

Once the pull request has been merged, delete the copy you made of the branch with git push origin -d add_<service_name>_<terms_type>.

Debugging Failing Tests

When tests fail, you can follow these steps to diagnose and address the issue:

  1. Begin by analyzing any error messages or warnings provided by the test output. These messages can often provide meaningful information to identify the source of the problem. Pay attention to specific issues such as schema validation errors, inaccessible web locations or inaccessible content selection.

  2. For a deeper investigation, you can access the snapshots and versions generated during the test run. Navigate to the summary page of the failing workflow. Scroll down to the “Artifacts” section located at the bottom of the page. Click on snapshots_and_versions to download them.

  3. Inside the downloaded archive you will be able to inspect the snapshot file related to the terms that failed. Ensure the document downloaded by the engine is the correct one and that the terms content is present. Sometimes a login wall or a cookies wall can block access to the content.

  4. If the snapshot is the proper one, you can examine the generated version to check the accuracy of content selection.

If tests keep on failing

If the tests fail systematically in CI but there is at least one environment in which all tests pass, it is allowed to use admin powers to force the merge.

For example, tests may fail in CI because of a 403 Access Denied error, but succeed when run on a development machine.

Bypassing protection is allowed because:

  • if the engine is updated, the problem could correct itself;
  • if it’s an anti-bot protection, it can stop from one day to the next;
  • adding the terms prevents duplicate suggestions for additions;
  • a service can encounter this type of error after being merged, so there is no reason to prevent it from being added with this error.

Merging the Pull Request

Beyond status checks, additional restriction requires branches to be up to date before merging. This ensures that the contribution has been tested with the latest version of the collection. This appears as a “This branch is out-of-date with the base branch” warning on a pull request. You can fix this using the Github interface, by clicking on the arrow button next to the “Update Branch” button, and select “Update with Rebase”.

Contributions FAQ

  1. How can we tell if a section is insignificant in the contractual document? The best way to judge if a section doesn’t not fit into the contractual document is by asking yourself if a change made on that section has any legal impact. If not it can be viewed as insignificant.
  2. How do we give feedback when reviewing a pull request? Even though there will be contributors who are technically skilled and those who aren’t, you are encouraged to provide comments line by line in the pull request for more context and to provide suggestions.
  3. How do we suggest changes to a contributor? It is encouraged to empower contributors to make required changes themselves, however for first time contributors, you can make the changes and explain why they are necessary as they progressively learn. In due time they get better at it and can make changes on their own.
\ No newline at end of file diff --git a/guidelines/targeting/index.html b/guidelines/targeting/index.html index e1c02ced..c49ae4ba 100644 --- a/guidelines/targeting/index.html +++ b/guidelines/targeting/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Targeting

What to track?

Can I track terms that are not applicable yet?

Yes.

For example, documents that would start applying at date in the future are legitimate candidates for tracking. You can this way track if their terms change even before they are applied.

+Close
\ No newline at end of file diff --git a/index.html b/index.html index cde9987c..8bb8e5cf 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,8 @@ -Open Terms Archive - Getting started

The document you are reading now is targeted at developers wanting to use or contribute to the engine of Open Terms Archive. For a high-level overview of Open Terms Archive’s wider goals and processes, please read its public homepage.

Open Terms Archive Engine

This codebase is a Node.js module enabling downloading, archiving and publishing versions of documents obtained online. It can be used independently from the Open Terms Archive ecosystem.


Motivation

Words in bold are business domain names.

Services have terms written in documents, contractual (Terms of Services, Privacy Policy…) or not (Community Guidelines, Deceased User Policy…), that can change over time. Open Terms Archive enables users rights advocates, regulatory bodies and interested citizens to follow the changes to these terms, to be notified whenever a new version is published, to explore their entire history and to collaborate in analysing them. This free and open-source engine is developed to support these goals.


Main concepts

Collection

Open Terms Archive is a decentralised system. It aims at enabling any entity to track terms on its own. To that end, the Open Terms Archive engine can be run on any server, thus making it a dedicated instance. An instance tracks terms within a single collection.

A collection is characterised by a scope across dimensions that describe the terms it tracks, such as language, jurisdiction and industry.

Example scope

The terms tracked in this collection are:

  • Of dating services used in Europe.
  • In the European Union and Switzerland jurisdictions.
  • In English, unless no English version exists, in which case the primary official language of the jurisdiction of incorporation of the service operator will be used.

Federation

In order to maximise discoverability, collaboration and political power, public collections are federated within a single ecosystem. This makes their data mutually discoverable and enables mutualising effort.

Terms types

To distinguish between the different terms of a service, each has a type, such as “Terms of Service”, “Privacy Policy”, “Developer Agreement”…

This type matches the topic, but not necessarily the title the service gives to it. Unifying the types enables comparing terms across services.

More information on terms types can be found in the dedicated repository. They are published on NPM under @opentermsarchive/terms-types, enabling standardisation and interoperability beyond the Open Terms Archive engine.

Declarations

The terms that constitute a collection are defined in simple JSON files called declarations.

A declaration also contains some metadata on the service on which the terms apply.

Here is an example declaration tracking the Privacy Policy of Open Terms Archive:

{
+Close

The document you are reading now is targeted at developers wanting to use or contribute to the engine of Open Terms Archive. For a high-level overview of Open Terms Archive’s wider goals and processes, please read its public homepage.

Open Terms Archive Engine

This codebase is a Node.js module enabling downloading, archiving and publishing versions of documents obtained online. It can be used independently from the Open Terms Archive ecosystem.


Motivation

Words in bold are business domain names.

Services have terms written in documents, contractual (Terms of Services, Privacy Policy…) or not (Community Guidelines, Deceased User Policy…), that can change over time. Open Terms Archive enables users rights advocates, regulatory bodies and interested citizens to follow the changes to these terms, to be notified whenever a new version is published, to explore their entire history and to collaborate in analysing them. This free and open-source engine is developed to support these goals.


Main concepts

Collection

Open Terms Archive is a decentralised system. It aims at enabling any entity to track terms on its own. To that end, the Open Terms Archive engine can be run on any server, thus making it a dedicated instance. An instance tracks terms within a single collection.

A collection is characterised by a scope across dimensions that describe the terms it tracks, such as language, jurisdiction and industry.

Example scope

The terms tracked in this collection are:

  • Of dating services used in Europe.
  • In the European Union and Switzerland jurisdictions.
  • In English, unless no English version exists, in which case the primary official language of the jurisdiction of incorporation of the service operator will be used.

Federation

In order to maximise discoverability, collaboration and political power, public collections are federated within a single ecosystem. This makes their data mutually discoverable and enables mutualising effort.

Terms types

To distinguish between the different terms of a service, each has a type, such as “Terms of Service”, “Privacy Policy”, “Developer Agreement”…

This type matches the topic, but not necessarily the title the service gives to it. Unifying the types enables comparing terms across services.

More information on terms types can be found in the dedicated repository. They are published on NPM under @opentermsarchive/terms-types, enabling standardisation and interoperability beyond the Open Terms Archive engine.

Declarations

The terms that constitute a collection are defined in simple JSON files called declarations.

A declaration also contains some metadata on the service on which the terms apply.

Here is an example declaration tracking the Privacy Policy of Open Terms Archive:

{
   "name": "Open Terms Archive",
   "documents": {
     "Privacy Policy": {
@@ -12,7 +12,7 @@
   }
 }
 

Add terms to a collection

Open Terms Archive acquires terms to deliver an explorable history of changes. This can be done in two ways:

  1. For the present and future, by tracking.
  2. For the past, by importing from an existing fonds such as ToSBack, the Internet Archive, Common Crawl or any other in-house format.

Tracking terms

In order to track the changes of terms, the engine records a snapshot of documents that contain them by fetching their web location several times a day. The engine then extracts a version from this snapshot by:

  1. Selecting the subset of the document (or documents) that contains the terms (instead of, e.g., navigation menus, footers, cookies banners…).
  2. Removing insignificant content, that is residual content in this subset that is not part of the terms (e.g. ads, illustrative pictures, internal navigation links…).
  3. Filtering noise that can emerge in the terms by preventing parts that change frequently from triggering false positives for changes (e.g. tracker identifiers in links, relative dates…). The engine can execute custom filters written in JavaScript to that end.

After these steps, if changes are spotted in the resulting terms, a new version is recorded.

Preserving snapshots enables recovering after the fact information potentially lost in the extraction step: if declarations were wrong, they can be maintained and corrected versions can be extracted from the original snapshots.

Importing terms

Existing fonds can be prepared for easier analysis by unifying their format to the Open Terms Archive dataset format. This unique format enables building interoperable tools, fostering collaboration across reusers. -Such a dataset can be generated from versions alone. If snapshots and declarations can be retrieved from the fonds too, then a full-fledged collection can be created.


Use the engine

This documentation describes how to execute the engine independently from any specific instance. For other use cases, other parts of the documentation could be more relevant:

Requirements

This module is tested to work across operating systems (continuous testing on UNIX, macOS and Windows).

A Node.js runtime is required to execute this engine.

Supported Node.js version can be found in the package.json file

Getting started

This engine is published as a module on NPM. The recommended install is as a dependency in a package.json file, next to a folder containing declaration files.

npm install --save @opentermsarchive/engine
+Such a dataset can be generated from versions alone. If snapshots and declarations can be retrieved from the fonds too, then a full-fledged collection can be created.


Use the engine

This documentation describes how to execute the engine independently from any specific instance. For other use cases, other parts of the documentation could be more relevant:

Requirements

This module is tested to work across operating systems (continuous testing on UNIX, macOS and Windows).

A Node.js runtime is required to execute this engine.

Supported Node.js version can be found in the package.json file

Getting started

This engine is published as a module on NPM. The recommended install is as a dependency in a package.json file, next to a folder containing declaration files.

npm install --save @opentermsarchive/engine
 mkdir declarations
 

In an editor, create the following declaration file in declarations/Open Terms Archive.json to track the terms of the Open Terms Archive website:

{
   "name": "Open Terms Archive",
diff --git a/index.xml b/index.xml
index dfaff00a..2304fd03 100644
--- a/index.xml
+++ b/index.xml
@@ -1,32 +1,38 @@
-Getting started on Open Terms Archive documentationhttps://docs.opentermsarchive.org/Recent content in Getting started on Open Terms Archive documentationHugo -- gohugo.ioenMetadatahttps://docs.opentermsarchive.org/collections/metadata/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/metadata/Collection metadata A collection is defined by the following metadata.
+Getting started on Open Terms Archive documentationhttps://docs.opentermsarchive.org/Recent content in Getting started on Open Terms Archive documentationHugo -- gohugo.ioenHow to navigate historyhttps://docs.opentermsarchive.org/terms/how-to-navigate-history/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-navigate-history/How to navigate history Screencast Learn how to navigate through versions history in this 4 minutes video, or scroll below for the textual version.
+Manual Every collection offers a public database of versions they recorded.
+For this guide, we will use the example of the Demo collection. The terms of this collection are published on the OpenTermsArchive/demo-versions repository.
+From the repository page, open the folder of the service of your choice by clicking on it.Metadatahttps://docs.opentermsarchive.org/collections/metadata/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/metadata/Collection metadata A collection is defined by the following metadata.
 Description A concise description of the collection topic.
 Examples Largest global social media Most used social media in France Dating apps Platforms providing services to businesses Name Three words maximum.
 Examples Platform Governance Archive France Élections Dating P2B Compliance Assessment ID An identifier derived from the collection name that can more easily be referenced in code. Use acronyms and replace spaces with dashes.Nodehttps://docs.opentermsarchive.org/api/node/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/api/node/Node.js API [Beta] As a Node module dependency, the engine exposes a JavaScript API that can be called in your own code. The following modules are available.
 fetch The fetch module gets the MIME type and content of a document from its URL
 import fetch from &#39;@opentermsarchive/engine/fetch&#39;; Documentation on how to use fetch is provided as JSDoc.
-Headless browser management If you pass the executeClientScripts option to fetch, a headless browser will be used to download and execute the page before serialising its DOM.Browsing through termshttps://docs.opentermsarchive.org/navigate-history/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/navigate-history/Browsing through terms Every collection offers a public database of versions they recorded.
-For this guide, we will use the example of the Demo collection. The terms of this collection are published on the OpenTermsArchive/demo-versions repository.
-From the repository page, open the folder of the service of your choice by clicking on it. For example, GitHub:
-You will see the set of terms tracked for that service, now click on the terms of your choice.Collectionhttps://docs.opentermsarchive.org/api/collection/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/api/collection/Collection Web API [Beta] As Open Terms Archive is decentralised, each instance embarks its own API. The documentation relevant to the specific version of the engine on that instance is provided on that instance itself.
+Headless browser management If you pass the executeClientScripts option to fetch, a headless browser will be used to download and execute the page before serialising its DOM.Collectionhttps://docs.opentermsarchive.org/api/collection/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/api/collection/Collection Web API [Beta] As Open Terms Archive is decentralised, each instance embarks its own API. The documentation relevant to the specific version of the engine on that instance is provided on that instance itself.
 The Collection API exposes JSON data over HTTP. Its OpenAPI specification can be found at http://localhost:&lt;port&gt;/&lt;basePath&gt;/&lt;API version&gt;/docs.
 That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.Governancehttps://docs.opentermsarchive.org/collections/governance/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/governance/Collection governance Setting up and maintaining a collection needs fulfilling certain tasks. These tasks are handled through roles. Each of these roles can be volunteer or paid, and can be handled by one single or several different entities. The Open Terms Archive core team provides processes and tools to support all of these roles.
-Host This role ensures that a server and internet access is available to run the engine on and fetch the terms, either by using its own infrastructure or renting a server on a hosting provider.Creating a collectionhttps://docs.opentermsarchive.org/collections/create/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/create/Creating a collection You are considering creating a new collection to track terms with Open Terms Archive? Amazing!
+Host This role ensures that a server and internet access is available to run the engine on and fetch the terms, either by using its own infrastructure or renting a server on a hosting provider.Tracking new termshttps://docs.opentermsarchive.org/terms/tracking-new-terms/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/tracking-new-terms/Tracking new terms Tracking terms is done by declaring them and the service they are associated with. Such a declaration is achieved by editing JSON files in the declarations folder.
+Before adding new terms, open the declarations folder and check if the service you want to track terms for is already declared. If a JSON file with the name of the service is already present, you can jump straight to the Terms reference.Creating a collectionhttps://docs.opentermsarchive.org/collections/create/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/create/Creating a collection You are considering creating a new collection to track terms with Open Terms Archive? Amazing!
 Define metadata First of all, define the metadata of the collection you would like to create.
-Check existing collections Now that you have a clear idea what you would like to track, double-check that there are no existing federated collections that you could contribute to. If you have a doubt about whether some terms you want to track would fit a collection, reach out to the collection maintainers.Federationhttps://docs.opentermsarchive.org/api/federation/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/api/federation/Federation API Open Terms Archive is a decentralised system that tracks collections of services&rsquo; terms across multiple servers. Each collection operates its own API, and the Federation API unifies search and discovery across collections, fostering collaboration with external applications.
+Check existing collections Now that you have a clear idea what you would like to track, double-check that there are no existing federated collections that you could contribute to. If you have a doubt about whether some terms you want to track would fit a collection, reach out to the collection maintainers.Declarations maintenancehttps://docs.opentermsarchive.org/terms/declarations-maintenance/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/declarations-maintenance/Declarations maintenance All parts of a terms declaration (web location, selection, noise removal, distribution across multiple documents…) can change over time. The process of updating these elements to enable continued tracking is called maintenance. Without it, terms can become:
+unreachable: no snapshot can be recorded at all, because the location changed or the service denies access; unextractable: no version can be extracted from the snapshot, because the selection of content or some filter fails; noisy: both snapshots and versions are recorded but the changes contain noise that should have been filtered out.Federationhttps://docs.opentermsarchive.org/api/federation/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/api/federation/Federation API Open Terms Archive is a decentralised system that tracks collections of services&rsquo; terms across multiple servers. Each collection operates its own API, and the Federation API unifies search and discovery across collections, fostering collaboration with external applications.
 The Federation API exposes JSON data over HTTP. Its documentation is provided in a dedicated, interactive interface.
-That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.Subscribing to terms changeshttps://docs.opentermsarchive.org/subscribe-rss/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/subscribe-rss/Subscribing to terms changes An RSS feed is a type of web page that contains information about the latest content published by a website, such as the date of publication and the address where you can view it. When this resource is updated, a feed reader app automatically notifies you and you can see the update. You can receive notification for a specific service or document by subscribing to RSS feeds.Contributing termshttps://docs.opentermsarchive.org/contributing-terms/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/contributing-terms/Contributing terms Tracking new terms Tracking terms is done by declaring them and the service they are associated with. Such a declaration is achieved by editing JSON files in the declarations folder.
-Before adding new terms, open the declarations folder and check if the service you want to track terms for is already declared. If a JSON file with the name of the service is already present, you can jump straight to declaring terms.Federationhttps://docs.opentermsarchive.org/collections/federation/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/federation/Federation Open Terms Archive is a decentralised system. It aims at enabling any entity set up their own collections and track terms on their own.
+That endpoint exposes both the OpenAPI specification if the requested Content-Type is JSON, and a Swagger UI for visual and interactive documentation otherwise.Federationhttps://docs.opentermsarchive.org/collections/federation/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/collections/federation/Federation Open Terms Archive is a decentralised system. It aims at enabling any entity set up their own collections and track terms on their own.
 In order to maximise discoverability, collaboration and political power, public collections are federated within a single ecosystem. This makes their data mutually discoverable and enables mutualising effort.
 Benefits A collection that joins the federation enjoys the following benefits:
-Visibility on the Open Terms Archive website lists of collections and datasets.Design principleshttps://docs.opentermsarchive.org/design-principles/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/design-principles/Design principles These overarching principles guide technical and governance decisions. They are fundamental and can only be changed through community consensus, based on a thorough impact assessment.
+Visibility on the Open Terms Archive website lists of collections and datasets.Referencehttps://docs.opentermsarchive.org/terms/reference/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/reference/Terms reference Terms are declared in a service declaration file, under the documents property.
+Most of the time, terms are written in only one source document (for example Facebook Terms of Service) but sometimes terms can be spread across multiple online source documents, and their combination constitutes the terms (for example Facebook Community Guidelines).
+Source document The way in which a source document is obtained is defined in a JSON object:Design principleshttps://docs.opentermsarchive.org/design-principles/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/design-principles/Design principles These overarching principles guide technical and governance decisions. They are fundamental and can only be changed through community consensus, based on a thorough impact assessment.
 Each principle has a name, a rationale, and potential implementation examples or guidelines.
 1. Never trust the services A major goal of Open Terms Archive is to enable assessing the loyalty of services towards their end users. Since loyalty is not assumed, trust can not be warranted.Choosing selectorshttps://docs.opentermsarchive.org/guidelines/choosing-selectors/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/choosing-selectors/Choosing selectors Selectors are used in Open Terms Archive declarations to specify the parts of documents that should be recorded.
 What are selectors Selectors are used in the select and remove keys of an Open Terms Archive declaration.
 The “selectors” referred to are defined by the W3C Selectors standard, more commonly known as “CSS Selectors”.
 An easy-to-read introduction to CSS Selectors can be found on mdn web docs.
 Choosing durable selectors eases maintenance The design of web pages containing terms can evolve over time, leading to changes in their HTML (more precisely, to their DOM) which may render ineffective the selectors that were initially chosen.Copywriting referencehttps://docs.opentermsarchive.org/memos/copywriting-reference/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/memos/copywriting-reference/Copywriting reference Each memo must be composed of the elements detailed below. You must follow this structure when writing your memos.
-Title Write a short declarative sentence to highlight the key change. 140 characters maximum. Use the name of the service as the subject. Write in the present tense. Prefer active phrasings over passive (e.g., “Microsoft expands reach” rather than “Reach expanded by Microsoft“). Describe the policy change, not the name of the document.Declaring documentshttps://docs.opentermsarchive.org/guidelines/declaring/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/declaring/This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in Contributing Terms.
-Declaring documents Service name Casing In order to find the service name casing, rely first on the page title (easily found in search results). Do not rely on the logo as it can be stylized differently. Example with Facebook: If it is still ambiguous, rely on Wikipedia as a source. However, make sure to differentiate the service from the provider company&rsquo;s name.How to publish a memohttps://docs.opentermsarchive.org/memos/how-to-publish/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/memos/how-to-publish/How to publish a memo This guide will help you publish a memo on opentermsarchive.org/en/memos.
+Title Write a short declarative sentence to highlight the key change. 140 characters maximum. Use the name of the service as the subject. Write in the present tense. Prefer active phrasings over passive (e.g., “Microsoft expands reach” rather than “Reach expanded by Microsoft“). Describe the policy change, not the name of the document.Declaring documentshttps://docs.opentermsarchive.org/guidelines/declaring/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/declaring/This document presents practical guidelines, is edited collaboratively and is not normative. Normative constraints are exposed in the Terms reference.
+Declaring documents Service name Casing In order to find the service name casing, rely first on the page title (easily found in search results). Do not rely on the logo as it can be stylized differently. Example with Facebook: If it is still ambiguous, rely on Wikipedia as a source. However, make sure to differentiate the service from the provider company&rsquo;s name.How to add terms with the graphical contribution interfacehttps://docs.opentermsarchive.org/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/How to add terms with the graphical contribution interface Screencast Learn how add terms with the graphical contribution interface in this 6 minutes video.
+Manual Blank page when contacting support While using the graphical user interface for contribution, you may come across a blank page when trying to contact the team.
+This may be caused by the lack of a mail program being set up in your browser.
+Solution If you use Gmail, for example, these instructions explain how to add Gmail as the default mailto handler in Chrome.How to be notified of terms changeshttps://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/How to be notified of terms changes An RSS feed is a type of web page that contains information about the latest content published by a website, such as the date of publication and the address where you can view it. When this resource is updated, a feed reader app automatically notifies you and you can see the update. You can receive notification for a specific service or document by subscribing to RSS feeds.How to publish a memohttps://docs.opentermsarchive.org/memos/how-to-publish/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/memos/how-to-publish/How to publish a memo This guide will help you publish a memo on opentermsarchive.org/en/memos.
 No technical skills are required.
 Prerequisites A drafted memo compliant with the copywriting reference. 1. Send Send your memo to contact@opentermsarchive.org by writing it in the body of the email or as a file attachment. Feel free to add any comments or questions you may have about the content or format.
 2. Review The Open Terms Archive core team will review your memo as quickly as possible.Reviewing contributionshttps://docs.opentermsarchive.org/guidelines/reviewing/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/guidelines/reviewing/Reviewing contributions Thank you for showing interest in reviewing contributions made to Open Terms Archive. This document is intended to help you get started and provide some guidelines for reviewing contributions.
diff --git a/jsdoc/Record.html b/jsdoc/Record.html
index 0ae20d72..e1d4ddb8 100644
--- a/jsdoc/Record.html
+++ b/jsdoc/Record.html
@@ -161,7 +161,7 @@ 

Home

Classes

  • diff --git a/jsdoc/archivist_extract_index.js.html b/jsdoc/archivist_extract_index.js.html index 6cb1a8a9..a8bece29 100644 --- a/jsdoc/archivist_extract_index.js.html +++ b/jsdoc/archivist_extract_index.js.html @@ -236,7 +236,7 @@

    Home

    Classes

    • diff --git a/jsdoc/archivist_fetcher_index.js.html b/jsdoc/archivist_fetcher_index.js.html index c0509c88..f33c987a 100644 --- a/jsdoc/archivist_fetcher_index.js.html +++ b/jsdoc/archivist_fetcher_index.js.html @@ -83,7 +83,7 @@

      Home

      Classes

      • diff --git a/jsdoc/archivist_recorder_record.js.html b/jsdoc/archivist_recorder_record.js.html index aa184d8a..38b22069 100644 --- a/jsdoc/archivist_recorder_record.js.html +++ b/jsdoc/archivist_recorder_record.js.html @@ -88,7 +88,7 @@

        Home

        Classes

        • diff --git a/jsdoc/archivist_recorder_repositories_interface.js.html b/jsdoc/archivist_recorder_repositories_interface.js.html index ec98d32a..ec7d3fc5 100644 --- a/jsdoc/archivist_recorder_repositories_interface.js.html +++ b/jsdoc/archivist_recorder_repositories_interface.js.html @@ -169,7 +169,7 @@

          Home

          Classes

          • diff --git a/jsdoc/collection-api_routes_services.js.html b/jsdoc/collection-api_routes_services.js.html index 4eb67a25..6a494633 100644 --- a/jsdoc/collection-api_routes_services.js.html +++ b/jsdoc/collection-api_routes_services.js.html @@ -201,7 +201,7 @@

            Home

            Classes

            • diff --git a/jsdoc/collection-api_routes_versions.js.html b/jsdoc/collection-api_routes_versions.js.html index 4d00c30e..4288393c 100644 --- a/jsdoc/collection-api_routes_versions.js.html +++ b/jsdoc/collection-api_routes_versions.js.html @@ -152,7 +152,7 @@

              Home

              Classes

              • diff --git a/jsdoc/global.html b/jsdoc/global.html index cdc7ed91..b2742f66 100644 --- a/jsdoc/global.html +++ b/jsdoc/global.html @@ -846,7 +846,7 @@

                Home

                Classes

                • diff --git a/jsdoc/index.html b/jsdoc/index.html index 7a0e90fe..16d23e64 100644 --- a/jsdoc/index.html +++ b/jsdoc/index.html @@ -56,7 +56,7 @@

                  Home

                  Classes

                  • diff --git a/memos/copywriting-reference/index.html b/memos/copywriting-reference/index.html index adcf6c90..b7d97cba 100644 --- a/memos/copywriting-reference/index.html +++ b/memos/copywriting-reference/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - Copywriting reference

                    Copywriting reference

                    Each memo must be composed of the elements detailed below. You must follow this structure when writing your memos.

                    Title

                    • Write a short declarative sentence to highlight the key change.
                    • 140 characters maximum.
                    • Use the name of the service as the subject.
                    • Write in the present tense.
                    • Prefer active phrasings over passive (e.g., “Microsoft expands reach” rather than “Reach expanded by Microsoft“).
                    • Describe the policy change, not the name of the document. This information will be given in the metadata below.
                    • Use no punctuation.
                    • Do not put a link in the title because in some reuse contexts the entire title is a link to the memo.

                    Example

                    • Facebook bans States from denying the use of violence in an invasion
                    • OpenAI specifies further plugin exports rules

                    Service name

                    • Write the service name (not the company name, e.g., “Facebook” rather than “Meta“)

                    Examples

                    LinkedIn

                    OpenAI

                    Terms types

                    • You must fill a valid terms type.
                    • Multiple terms types are allowed.

                    Examples

                    Terms of Service

                    Community Guidelines, Terms of Service, Privacy Policy

                    Date modified

                    • Use Month Day, Year format.
                    • Multiples dates are allowed.
                    • Avoid repeating months or years

                    Examples

                    March 4, 2024

                    November 3, 10 - December 16, 2023

                    Body text

                    • Describe changes in a neutral, objective, non-judgmental manner.
                      • Write in the past tense (e.g., “added”, “removed”…).
                      • Bolden the most important point.
                      • Do not repeat the date, it is already in the metadata.
                    • Systematically add a link to the diff on this action verb.
                      • Title of the link: “See the change”.
                      • Avoid verbs like “announce”, because most of the time the changes detected are not announced.
                    • Do not hesitate to quote the new text.
                      • Do not italicise citations, use quotes.
                      • Minimise the length of citations because legal text is often very wordy.
                      • Only quote the text before modification if it is strictly necessary to understand the change, to reduce the risk of confusion and length.
                    • If you write in a different language than the detected change, always look for citations in the version of the document that matches the language of writing if it exists instead of translating them yourself.

                    Example

                    OpenAI specified that, as far as European (EEA and Swiss) developers were concerned, their Agreement is with OpenAI Ireland Ltd. OpenAI stopped acting as a separate controller of personal data, and developers now have to present a privacy notice to their users prior to processing their data.

                    OpenAI also extended export restrictions to plugins “located” in countries embargoed or sanctioned by the US. This provision previously concerned only plugin owners.

                    OpenAI Ireland Ltd is a Dublin-based subsidiary of OpenAI set up in 2023.

                    Complete examples

                    Memo 1

                    Midjourney strengthens policies on intellectual property infringements

                    Midjourney ▪ Terms of Service ▪ December 23, 2023_

                    Midjourney introduced an explicit prohibition regarding the infringement of others’ intellectual property rights in its conditions for service availability and quality, mentioning the possibility of legal action and permanent ban from the service.

                    Previously, legal action was only mentioned where the violation of intellectual property rights resulted in financial detriment to Midjourney.

                    Memo 2

                    Instagram adds a posting ban to protect copyright

                    Instagram ▪ Community Guidelines ▪ March 28, 2022

                    On March 28, Instagram updated its intellectual property community rules, prohibiting the posting of content that “facilitates copyright infringement through unauthorized devices or services.” The text presents a list of cases in which users would risk infringing the copyright of a third party or even merely “facilitating” such infringement, even if they did not intend to do so. After the previously listed cases, which include “you purchased or downloaded the content” or “you saw others post the same content,” Instagram adds that users risk infringing copyright if they “use an unauthorized streaming device or service (examples: a ‘jailbroken’ or ‘loaded’ app or service).”

                    Contextualisation (optional)

                    • Body text in a new paragraph: contextualisation with external links to the most authoritative sources available.
                    • For example, explain which wider problems are tackled by this policy change, or give a historical perspective on the change.

                    Example

                    Meta expands reach against child exploitation

                    Facebook ▪ Community Guidelines ▪ June 13, 2022

                    The section on child exploitation for both Facebook and Instagram expanded to cover not only publications that exploit minors, but also “any activity” related to such acts.

                    This opens up the question of moderation of private discussions, as social platforms show difficulties in managing content related to child abuse —as recently as late March, the New York Times showed that moderation remains very light in this area, even though platforms are supposed to list this type of content and report it to authorities.

                    Source: June 23, 2022 Memo on French Elections.

                    +Close

Copywriting reference

Each memo must be composed of the elements detailed below. You must follow this structure when writing your memos.

Title

  • Write a short declarative sentence to highlight the key change.
  • 140 characters maximum.
  • Use the name of the service as the subject.
  • Write in the present tense.
  • Prefer active phrasings over passive (e.g., “Microsoft expands reach” rather than “Reach expanded by Microsoft“).
  • Describe the policy change, not the name of the document. This information will be given in the metadata below.
  • Use no punctuation.
  • Do not put a link in the title because in some reuse contexts the entire title is a link to the memo.

Example

  • Facebook bans States from denying the use of violence in an invasion
  • OpenAI specifies further plugin exports rules

Service name

  • Write the service name (not the company name, e.g., “Facebook” rather than “Meta“)

Examples

LinkedIn

OpenAI

Terms types

  • You must fill a valid terms type.
  • Multiple terms types are allowed.

Examples

Terms of Service

Community Guidelines, Terms of Service, Privacy Policy

Date modified

  • Use Month Day, Year format.
  • Multiples dates are allowed.
  • Avoid repeating months or years

Examples

March 4, 2024

November 3, 10 - December 16, 2023

Body text

  • Describe changes in a neutral, objective, non-judgmental manner.
    • Write in the past tense (e.g., “added”, “removed”…).
    • Bolden the most important point.
    • Do not repeat the date, it is already in the metadata.
  • Systematically add a link to the diff on this action verb.
    • Title of the link: “See the change”.
    • Avoid verbs like “announce”, because most of the time the changes detected are not announced.
  • Do not hesitate to quote the new text.
    • Do not italicise citations, use quotes.
    • Minimise the length of citations because legal text is often very wordy.
    • Only quote the text before modification if it is strictly necessary to understand the change, to reduce the risk of confusion and length.
  • If you write in a different language than the detected change, always look for citations in the version of the document that matches the language of writing if it exists instead of translating them yourself.

Example

OpenAI specified that, as far as European (EEA and Swiss) developers were concerned, their Agreement is with OpenAI Ireland Ltd. OpenAI stopped acting as a separate controller of personal data, and developers now have to present a privacy notice to their users prior to processing their data.

OpenAI also extended export restrictions to plugins “located” in countries embargoed or sanctioned by the US. This provision previously concerned only plugin owners.

OpenAI Ireland Ltd is a Dublin-based subsidiary of OpenAI set up in 2023.

Complete examples

Memo 1

Midjourney strengthens policies on intellectual property infringements

Midjourney ▪ Terms of Service ▪ December 23, 2023_

Midjourney introduced an explicit prohibition regarding the infringement of others’ intellectual property rights in its conditions for service availability and quality, mentioning the possibility of legal action and permanent ban from the service.

Previously, legal action was only mentioned where the violation of intellectual property rights resulted in financial detriment to Midjourney.

Memo 2

Instagram adds a posting ban to protect copyright

Instagram ▪ Community Guidelines ▪ March 28, 2022

On March 28, Instagram updated its intellectual property community rules, prohibiting the posting of content that “facilitates copyright infringement through unauthorized devices or services.” The text presents a list of cases in which users would risk infringing the copyright of a third party or even merely “facilitating” such infringement, even if they did not intend to do so. After the previously listed cases, which include “you purchased or downloaded the content” or “you saw others post the same content,” Instagram adds that users risk infringing copyright if they “use an unauthorized streaming device or service (examples: a ‘jailbroken’ or ‘loaded’ app or service).”

Contextualisation (optional)

  • Body text in a new paragraph: contextualisation with external links to the most authoritative sources available.
  • For example, explain which wider problems are tackled by this policy change, or give a historical perspective on the change.

Example

Meta expands reach against child exploitation

Facebook ▪ Community Guidelines ▪ June 13, 2022

The section on child exploitation for both Facebook and Instagram expanded to cover not only publications that exploit minors, but also “any activity” related to such acts.

This opens up the question of moderation of private discussions, as social platforms show difficulties in managing content related to child abuse —as recently as late March, the New York Times showed that moderation remains very light in this area, even though platforms are supposed to list this type of content and report it to authorities.

Source: June 23, 2022 Memo on French Elections.

\ No newline at end of file diff --git a/memos/how-to-publish/index.html b/memos/how-to-publish/index.html index 287b023d..a06307fe 100644 --- a/memos/how-to-publish/index.html +++ b/memos/how-to-publish/index.html @@ -1,7 +1,7 @@ -Open Terms Archive - How to publish a memo

How to publish a memo

This guide will help you publish a memo on opentermsarchive.org/en/memos.

No technical skills are required.

Prerequisites

1. Send

Send your memo to contact@opentermsarchive.org by writing it in the body of the email or as a file attachment. Feel free to add any comments or questions you may have about the content or format.

2. Review

The Open Terms Archive core team will review your memo as quickly as possible.

If necessary, we will suggest changes and discuss them with you. Note that review times may vary depending on the number of changes required, the speed of exchanges, and the availability of reviewers. If you do not hear from us within two weeks, please do not hesitate to contact us again by the means of your choice.

3. Promote

Once the core team has published your memo on opentermsarchive.org/en/memos, we will inform you and provide you with the URL address of your memo. You should then promote it through the media and to the people you consider appropriate. Whenever possible, please associate the hashtag #TermsSpotting with your memo promotion, in order to provide visibility to the overall Open Terms Archive project and analysis.

+Close

How to publish a memo

This guide will help you publish a memo on opentermsarchive.org/en/memos.

No technical skills are required.

Prerequisites

1. Send

Send your memo to contact@opentermsarchive.org by writing it in the body of the email or as a file attachment. Feel free to add any comments or questions you may have about the content or format.

2. Review

The Open Terms Archive core team will review your memo as quickly as possible.

If necessary, we will suggest changes and discuss them with you. Note that review times may vary depending on the number of changes required, the speed of exchanges, and the availability of reviewers. If you do not hear from us within two weeks, please do not hesitate to contact us again by the means of your choice.

3. Promote

Once the core team has published your memo on opentermsarchive.org/en/memos, we will inform you and provide you with the URL address of your memo. You should then promote it through the media and to the people you consider appropriate. Whenever possible, please associate the hashtag #TermsSpotting with your memo promotion, in order to provide visibility to the overall Open Terms Archive project and analysis.

\ No newline at end of file diff --git a/navigate-history/index.html b/navigate-history/index.html index ccf9b5a3..b19a1d86 100644 --- a/navigate-history/index.html +++ b/navigate-history/index.html @@ -1,7 +1 @@ -Open Terms Archive - Browsing through terms

Browsing through terms

Every collection offers a public database of versions they recorded.

For this guide, we will use the example of the Demo collection. The terms of this collection are published on the OpenTermsArchive/demo-versions repository.

  • From the repository page, open the folder of the service of your choice by clicking on it. For example, GitHub:

    Demo-versions repository services list

  • You will see the set of terms tracked for that service, now click on the terms of your choice. For example, GitHub’s Privacy Policy:

    GitHub terms list

  • The most recent version will be displayed. To view the history of changes made to these terms, click on History at the top right:

    GitHub Privacy Policy

  • The changes are presented in reverse chronological order. For example, GitHub Privacy Policy history. Click on a change title to see its contents:

    GitHub Privacy Policy history

  • The red colour shows deleted words and the green colour shows added words. For example, in this change of GitHub Privacy Policy, you can see in red the deletion of information about GitHub data protection officer.

    One GitHub Privacy Policy change with source diff view

  • You can choose from two types of display with the icons in the grey bar above the document. The first one (which is also the default one), named source diff displays the previous version and the next one either side by side or in a consolidated way (with one line under the other). The second one, named rich diff displays all the changes in a single document. In this view, beyond green and red, the yellow color shows modified paragraphs. Be careful, this display does not show some changes such as hyperlinks and text style’s changes:

    One GitHub Privacy Policy change with rich diff view


Notes

  • For long documents, unchanged paragraphs will not be displayed by default. You can manually make them appear by clicking on the small arrows just above or just below the displayed paragraphs:

    Expand unchanged paragraphs on source diff view

    or

    Expand unchanged paragraphs on rich diff view

  • You can use the History button anywhere in the repository to display the history of changes made to all terms in the current folder.

- - \ No newline at end of file +https://docs.opentermsarchive.org/terms/how-to-navigate-history/ \ No newline at end of file diff --git a/subscribe-rss/index.html b/subscribe-rss/index.html index ac5992ae..3a92d73b 100644 --- a/subscribe-rss/index.html +++ b/subscribe-rss/index.html @@ -1,7 +1 @@ -Open Terms Archive - Subscribing to terms changes

Subscribing to terms changes

An RSS feed is a type of web page that contains information about the latest content published by a website, such as the date of publication and the address where you can view it. When this resource is updated, a feed reader app automatically notifies you and you can see the update. You can receive notification for a specific service or document by subscribing to RSS feeds.


For a specific document

To find out the address of the RSS feed you want to subscribe to:

  1. Navigate to the page with the history of changes you are interested in.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would be this page.
  2. Copy the address of that page from your browser’s address bar.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would be https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub/Privacy%20Policy.md.
  3. Append .atom at the end of this address.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would become https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub/Privacy%20Policy.md.atom.
  4. Subscribe your RSS feed reader to the resulting address.

For all the documents of a service

Simply navigate to the history of changes for the service you are interested in and follow the same procedure as for a specific document.

For example, for all GitHub documents of the Demo instance, you would obtain https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub.atom.


For all the documents of an instance

Simply append commits.atom to the URL of the repository.

For example, for all documents of the Demo instance, you would use https://github.com/OpenTermsArchive/demo-versions/commits.atom.

- - \ No newline at end of file +https://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/ \ No newline at end of file diff --git a/terms/declarations-maintenance/index.html b/terms/declarations-maintenance/index.html new file mode 100644 index 00000000..1037bc6d --- /dev/null +++ b/terms/declarations-maintenance/index.html @@ -0,0 +1,49 @@ +Declarations maintenance

Declarations maintenance

All parts of a terms declaration (web location, selection, noise removal, distribution across multiple documents…) can change over time. The process of updating these elements to enable continued tracking is called maintenance. Without it, terms can become:

  • unreachable: no snapshot can be recorded at all, because the location changed or the service denies access;
  • unextractable: no version can be extracted from the snapshot, because the selection of content or some filter fails;
  • noisy: both snapshots and versions are recorded but the changes contain noise that should have been filtered out.

Open Terms Archive needs to keep track of this changes in order to regenerate versions history from snapshots history.

Service history reference

To keep track of services declarations and filters changes, Open Terms Archive offers a versioning system. It is optional and should be added only when needed. It works by creating history files for terms declarations and filters, where each entry should be a previous valid declaration or filter function and should have an expiry date.

Both for terms and filters history, the expiration date is declared in a property validUntil. It should be the authored date and time of the last snapshot commit for which the declaration is still valid.

Terms declarations history files and filters history files can both evolve on their own. Having one does not imply to create the other.

The current (latest) valid declaration has no date and should not appear in the history object: it stays in its own file, just like if there was no history at all.

Terms declaration history

Declarations history are stored in a history JSON file with the following name declarations/$service_id.history.json.

The terms history contains an object with terms types as properties. Each terms type property is an array of history entries. Each entry has the same format as a normal terms declaration, except there is the mandatory extra property validUntil.

{
+  
+  "<terms type>": [
+    {
+      "fetch": "The URL where the document can be found",
+      "executeClientScripts": "A boolean to execute client-side JavaScript loaded by the document before accessing the content, in case the DOM modifications are needed to access the content; defaults to false (fetch HTML only)",
+      "filter": "An array of service specific filter function names",
+      "remove": "A CSS selector, a range selector or an array of selectors that target the insignificant parts of the document that has to be removed. Useful to remove parts that are inside the selected parts",
+      "select": "A CSS selector, a range selector or an array of selectors that target the meaningful parts of the document, excluding elements such as headers, footers and navigation",
+      "validUntil": "The inclusive expiration date in ISO format"
+    }
+  ]
+  
+}
+

For example, to add a history entry for the Terms of Service of the service ASKfm, create the file declarations/ASKfm.history.json with the following contents:

{
+  "Terms of Service": [
+    {
+      "fetch": "https://ask.fm/docs/terms_of_use/?lang=en",
+      "select": "body",
+      "filter": ["add"],
+      "validUntil": "2020-10-29T21:30:00.000Z"
+    }
+  ]
+}
+

Filters history

Filters history is declared in a filters history declaration JavaScript file with the following name: declarations/$service_id.filters.history.js.

For each filter, a variable named like the filter must be exported. This variable should contain an array of filter history entries. Each entry is an object with the expiration date, as validUntil property, and the valid function for this date, under the filter property. Both properties are mandatory.

export const <filterName> = [
+  {
+    validUntil: "The inclusive expiration date in ISO format",
+    filter: function() { /* body valid until the expiration of the `validUntil` date */ }
+  }
+];
+

For example, to add a history entry for the removeSharesButton filter of the service ASKfm, create the file declarations/ASKfm.filters.history.js with the following content:

export const removeSharesButton = [
+  {
+    validUntil: '2020-08-22T11:30:21.000Z',
+    filter: async (document) => {
+      document.querySelectorAll('.shares').forEach((element) => element.remove());
+    },
+  },
+];
+

How to terminate a service

If the service provider stops offering a service, the associated terms will become unavailable. To mark that service termination in Open Terms Archive and ensure tracking tentatives are stopped, while maintaining the possibility to explore the history:

  1. Move the existing documents declaration to the service history file.
  2. Update the declaration to stop tracking all terms, by removing every <terms type> entries from the documents key in the declaration:
{
+  "name": "<service name>",
+  "documents": {}
+}
+

How to rename a service

The consensus is to consider that a service provider renaming a service (for example, Twitter to X) is akin to terminating the previous service and opening a new one. Therefore, to apply a service renaming, open a pull request that both terminates the previous service and adds a new service declaration with the new service name. You can reuse the documents part of the original declaration, but should double-check that the selectors and URLs still match, as a service rename is most often accompanied by a new page layout, a new domain name, and sometimes entirely new terms.

+ + \ No newline at end of file diff --git a/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/index.html b/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/index.html new file mode 100644 index 00000000..701ef813 --- /dev/null +++ b/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/index.html @@ -0,0 +1,8 @@ +How to add terms with the graphical contribution interface

How to add terms with the graphical contribution interface

Screencast

Learn how add terms with the graphical contribution interface in this 6 minutes video.

Manual

Blank page when contacting support

While using the graphical user interface for contribution, you may come across a blank page when trying to contact the team.

This may be caused by the lack of a mail program being set up in your browser.

Solution

If you use Gmail, for example, these instructions explain how to add Gmail as the default mailto handler in Chrome. Try following them and trying again.

+ + \ No newline at end of file diff --git a/terms/how-to-be-notified-of-terms-changes/index.html b/terms/how-to-be-notified-of-terms-changes/index.html new file mode 100644 index 00000000..204d8d43 --- /dev/null +++ b/terms/how-to-be-notified-of-terms-changes/index.html @@ -0,0 +1,7 @@ +How to be notified of terms changes

How to be notified of terms changes

An RSS feed is a type of web page that contains information about the latest content published by a website, such as the date of publication and the address where you can view it. When this resource is updated, a feed reader app automatically notifies you and you can see the update. You can receive notification for a specific service or document by subscribing to RSS feeds.


For a specific document

To find out the address of the RSS feed you want to subscribe to:

  1. Navigate to the page with the history of changes you are interested in.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would be this page.
  2. Copy the address of that page from your browser’s address bar.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would be https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub/Privacy%20Policy.md.
  3. Append .atom at the end of this address.
    • For example, for the GitHub Privacy Policy of the Demo instance, this would become https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub/Privacy%20Policy.md.atom.
  4. Subscribe your RSS feed reader to the resulting address.

For all the documents of a service

Simply navigate to the history of changes for the service you are interested in and follow the same procedure as for a specific document.

For example, for all GitHub documents of the Demo instance, you would obtain https://github.com/OpenTermsArchive/demo-versions/commits/main/GitHub.atom.


For all the documents of an instance

Simply append commits.atom to the URL of the repository.

For example, for all documents of the Demo instance, you would use https://github.com/OpenTermsArchive/demo-versions/commits.atom.

+ + \ No newline at end of file diff --git a/terms/how-to-navigate-history/index.html b/terms/how-to-navigate-history/index.html new file mode 100644 index 00000000..b9558ecb --- /dev/null +++ b/terms/how-to-navigate-history/index.html @@ -0,0 +1,8 @@ +How to navigate history

How to navigate history

Screencast

Learn how to navigate through versions history in this 4 minutes video, or scroll below for the textual version.

Manual

Every collection offers a public database of versions they recorded.

For this guide, we will use the example of the Demo collection. The terms of this collection are published on the OpenTermsArchive/demo-versions repository.

  • From the repository page, open the folder of the service of your choice by clicking on it. For example, GitHub:

    Demo-versions repository services list

  • You will see the set of terms tracked for that service, now click on the terms of your choice. For example, GitHub’s Privacy Policy:

    GitHub terms list

  • The most recent version will be displayed. To view the history of changes made to these terms, click on History at the top right:

    GitHub Privacy Policy

  • The changes are presented in reverse chronological order. For example, GitHub Privacy Policy history. Click on a change title to see its contents:

    GitHub Privacy Policy history

  • The red colour shows deleted words and the green colour shows added words. For example, in this change of GitHub Privacy Policy, you can see in red the deletion of information about GitHub data protection officer.

    One GitHub Privacy Policy change with source diff view

  • You can choose from two types of display with the icons in the grey bar above the document. The first one (which is also the default one), named source diff displays the previous version and the next one either side by side or in a consolidated way (with one line under the other). The second one, named rich diff displays all the changes in a single document. In this view, beyond green and red, the yellow color shows modified paragraphs. Be careful, this display does not show some changes such as hyperlinks and text style’s changes:

    One GitHub Privacy Policy change with rich diff view


Notes

  • For long documents, unchanged paragraphs will not be displayed by default. You can manually make them appear by clicking on the small arrows just above or just below the displayed paragraphs:

    Expand unchanged paragraphs on source diff view

    or

    Expand unchanged paragraphs on rich diff view

  • You can use the History button anywhere in the repository to display the history of changes made to all terms in the current folder.

+ + \ No newline at end of file diff --git a/terms/index.xml b/terms/index.xml new file mode 100644 index 00000000..de0370ca --- /dev/null +++ b/terms/index.xml @@ -0,0 +1,11 @@ +Terms on Open Terms Archive documentationhttps://docs.opentermsarchive.org/terms/Recent content in Terms on Open Terms Archive documentationHugo -- gohugo.ioenHow to navigate historyhttps://docs.opentermsarchive.org/terms/how-to-navigate-history/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-navigate-history/How to navigate history Screencast Learn how to navigate through versions history in this 4 minutes video, or scroll below for the textual version. +Manual Every collection offers a public database of versions they recorded. +For this guide, we will use the example of the Demo collection. The terms of this collection are published on the OpenTermsArchive/demo-versions repository. +From the repository page, open the folder of the service of your choice by clicking on it.Tracking new termshttps://docs.opentermsarchive.org/terms/tracking-new-terms/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/tracking-new-terms/Tracking new terms Tracking terms is done by declaring them and the service they are associated with. Such a declaration is achieved by editing JSON files in the declarations folder. +Before adding new terms, open the declarations folder and check if the service you want to track terms for is already declared. If a JSON file with the name of the service is already present, you can jump straight to the Terms reference.Declarations maintenancehttps://docs.opentermsarchive.org/terms/declarations-maintenance/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/declarations-maintenance/Declarations maintenance All parts of a terms declaration (web location, selection, noise removal, distribution across multiple documents…) can change over time. The process of updating these elements to enable continued tracking is called maintenance. Without it, terms can become: +unreachable: no snapshot can be recorded at all, because the location changed or the service denies access; unextractable: no version can be extracted from the snapshot, because the selection of content or some filter fails; noisy: both snapshots and versions are recorded but the changes contain noise that should have been filtered out.Referencehttps://docs.opentermsarchive.org/terms/reference/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/reference/Terms reference Terms are declared in a service declaration file, under the documents property. +Most of the time, terms are written in only one source document (for example Facebook Terms of Service) but sometimes terms can be spread across multiple online source documents, and their combination constitutes the terms (for example Facebook Community Guidelines). +Source document The way in which a source document is obtained is defined in a JSON object:How to add terms with the graphical contribution interfacehttps://docs.opentermsarchive.org/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-add-terms-using-with-the-graphical-contribution-interface/How to add terms with the graphical contribution interface Screencast Learn how add terms with the graphical contribution interface in this 6 minutes video. +Manual Blank page when contacting support While using the graphical user interface for contribution, you may come across a blank page when trying to contact the team. +This may be caused by the lack of a mail program being set up in your browser. +Solution If you use Gmail, for example, these instructions explain how to add Gmail as the default mailto handler in Chrome.How to be notified of terms changeshttps://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/Mon, 01 Jan 0001 00:00:00 +0000https://docs.opentermsarchive.org/terms/how-to-be-notified-of-terms-changes/How to be notified of terms changes An RSS feed is a type of web page that contains information about the latest content published by a website, such as the date of publication and the address where you can view it. When this resource is updated, a feed reader app automatically notifies you and you can see the update. You can receive notification for a specific service or document by subscribing to RSS feeds. \ No newline at end of file diff --git a/terms/reference/index.html b/terms/reference/index.html new file mode 100644 index 00000000..9d5dedc3 --- /dev/null +++ b/terms/reference/index.html @@ -0,0 +1,161 @@ +Terms reference

Terms reference

Terms are declared in a service declaration file, under the documents property.

Most of the time, terms are written in only one source document (for example Facebook Terms of Service) but sometimes terms can be spread across multiple online source documents, and their combination constitutes the terms (for example Facebook Community Guidelines).

Source document

The way in which a source document is obtained is defined in a JSON object:

{
+  "fetch": "The URL where the document can be found",
+  "executeClientScripts": "A boolean to execute client-side JavaScript loaded by the document before accessing the content, in case the DOM modifications are needed to access the content; defaults to false (fetch HTML only)",
+  "filter": "An array of service specific filter function names",
+  "remove": "A CSS selector, a range selector or an array of selectors that target the insignificant parts of the document that has to be removed. Useful to remove parts that are inside the selected parts",
+  "select": "A CSS selector, a range selector or an array of selectors that target the meaningful parts of the document, excluding elements such as headers, footers and navigation"
+}
+
  • For HTML files, fetch and select are mandatory.
  • For PDF files, only fetch is mandatory.

Let’s start by defining these keys!

fetch

This property should simply contain the URL at which the terms you want to track can be downloaded. HTML and PDF files are supported.

When terms coexist in different languages and jurisdictions, please refer to the scope of the collection to which you are contributing. This scope is usually defined in the README.

select

This property is not needed for PDF documents.

Most of the time, contractual documents are exposed as web pages, with a header, a footer, navigation menus, possibly ads… We aim at tracking only the significant parts of the document. In order to achieve that, the select property allows to extract only those parts in the process of converting from snapshot to version.

The select value can be either a CSS selector, a range selector or an array of those.

CSS selectors

CSS selectors should be provided as a string. See the specification for how to write CSS selectors.

For example, the following selector will select the content in the <main> tag of the HTML document:

"select": "main"
+

Range selectors

A range selector is defined with a start and an end CSS selector. It is also necessary to define if the range starts before or after the element targeted by the start CSS selector and to define if it ends before or after the element targeted by the end CSS selector.

To that end, a range selector is a JSON object containing two keys out of the four that are available: startBefore, startAfter, endBefore and endAfter.

{
+  "start[Before|After]": "<CSS selector>",
+  "end[Before|After]": "<CSS selector>"
+}
+

For example, the following selector will select the content between the element targeted by the CSS selector #privacy-eea, including it, and the element targeted by the CSS selector footer, excluding it:

{
+  "startBefore": "#privacy-eea",
+  "endBefore": "footer"
+}
+

remove

This property is optional.

Beyond selecting a subset of a web page, some documents will have non-significant parts in the middle of otherwise significant parts. For example, they can have “go to top” links or banner ads. These can be removed by listing CSS selectors, range selectors or an array of them under the remove property.

Example

Let’s assume a web page contains the following content:

<main>
+  <div class="filter-holder">
+    <select class="filter-options">
+        <option value="https://www.example.com/policies/user-agreement" selected>User Agreement</option>
+        <option value="https://www.example.com/policies/privacy-policy">Privacy Policy</option>
+        <option value="https://www.example.com/policies/content-policy">Content Policy</option>
+        <option value="https://www.example.com/policies/broadcasting-content-policy">Broadcasting Content Policy</option>
+    </select>
+  </div>
+  <h1>User Agreement</h1>
+  <div>…terms…</div>
+</main>
+

If only main is used in select, the following version will be extracted:

User Agreement Privacy Policy Content Policy Broadcasting Content Policy Moderator Guidelines Transparency Report 2017 Transparency Report 2018 Guidelines for Law Enforcement Transparency Report 2019
+
+User Agreement
+==============
+
+…terms…
+

Whereas we want instead:

User Agreement
+==============
+
+…terms…
+

This result can be obtained with the following declaration:

{
+  "fetch": "https://example.com/user-agreement",
+  "select": "main",
+  "remove": ".filter-holder"
+}
+

Complex selectors examples

{
+ "fetch": "https://support.google.com/adsense/answer/48182",
+ "select": ".article-container",
+ "remove": ".print-button, .go-to-top"
+}
+
{
+ "fetch": "https://www.wechat.com/en/service_terms.html",
+ "select": "#agreement",
+ "remove": {
+   "startBefore": "#wechat-terms-of-service-usa-specific-terms-",
+   "endBefore": "#wechat-terms-of-service-european-union-specific-terms-"
+ }
+}
+
{
+ "fetch": "https://fr-fr.facebook.com/legal/terms/plain_text_terms",
+ "select": "div[role=main]",
+ "remove": [
+   {
+     "startBefore": "[role=\"separator\"]",
+     "endAfter": "body"
+   },
+   "[style=\"display:none\"]"
+ ]
+}
+

executeClientScripts

This property is optional.

In some cases, the content of the document is only loaded (or is modified dynamically) by client scripts. +When set to true, this boolean property loads the page in a headless browser to load all assets and execute client scripts before trying to get the document contents.

Since the performance cost of this approach is high, it is set to false by default, relying on the HTML content only.

filter

This property is optional.

Finally, some documents will need more complex filtering beyond simple element selection and removal, for example to remove noise (changes in textual content that are not meaningful to the terms of services). Such filters are declared as JavaScript functions that modify the downloaded web page through the DOM API.

Filters take the document DOM and the terms declaration as parameters and are:

  • in-place: they modify the document structure and content directly;
  • idempotent: they should return the same document structure and content even if run repeatedly on their own result.

Filters are loaded automatically from files named after the service they operate on. For example, filters for the Meetup service, which is declared in declarations/Meetup.json, are loaded from declarations/Meetup.filters.js.

The generic function signature for a filter is:

export [async] function filterName(document, documentDeclaration)
+

Each filter is exposed as a named function export that takes a document parameter and behaves like the document object in a browser DOM. These functions can be async, but they will still run sequentially. The whole document declaration is passed as second parameter.

The document parameter is actually a JSDOM document instance.

You can learn more about usual noise and ways to handle it in the guidelines.

Example

Let’s assume a service adds a unique clickId parameter in the query string of all link destinations. These parameters change on each page load, leading to recording noise in versions. Since links should still be recorded, it is not appropriate to use remove to remove the links entirely. Instead, a filter will manipulate the links destinations to remove the always-changing parameter. Concretely, the goal is to apply the following filter:

- Read the <a href="https://example.com/example-page?clickId=349A2033B&lang=en">list of our affiliates</a>.
++ Read the <a href="https://example.com/example-page?lang=en">list of our affiliates</a>.
+

The code below implements this filter:

function removeTrackingIdsQueryParam(document) {
+  const QUERY_PARAM_TO_REMOVE = 'clickId';
+
+  document.querySelectorAll('a').forEach(link => {  // iterate over every link in the page
+    const url = new URL(link.getAttribute('href'), document.location);  // URL is part of the DOM API, see https://developer.mozilla.org/en-US/docs/Web/API/URL
+    const params = new URLSearchParams(url.search);  // URLSearchParams is part of the DOM API, see https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
+
+    params.delete(QUERY_PARAM_TO_REMOVE);  // we use the DOM API instead of RegExp because we can't know in advance in which order parameters will be written
+    url.search = params.toString();  // store the query string without the parameter
+    link.setAttribute('href', url.toString());  // write the destination URL without the parameter
+  });
+}
+

Example usage of declaration parameter

The second parameter can be used to access the defined document URL or selector inside the filter.

Let’s assume a service stores some of its legally-binding terms in images. To track these changes properly, images should be stored as part of the terms. By default, images are not stored since they significantly increase the document size. The filter below will store images inline in the terms, encoded in a data URL. In order to download the images for conversion, the base URL of the web page is needed to resolve relative links. This information is obtained from the declaration.

import fetch from 'isomorphic-fetch';
+
+export async function convertImagesToBase64(document, documentDeclaration) {
+  const { fetch: baseUrl, select: selector } = documentDeclaration;
+  
+  const images = Array.from(document.querySelectorAll(`${selector} img`));
+
+  return Promise.all(images.map(async ({ src }, index) => {
+    const imageAbsoluteUrl = new URL(src, baseUrl).href;
+    const response = await fetch(imageAbsoluteUrl);
+    const mimeType = response.headers.get('content-type');
+    const content = await response.arrayBuffer();
+
+    const base64Image = btoa(String.fromCharCode(...new Uint8Array(content)));
+
+    images[index].src = `data:${mimeType};base64,${base64Image}`;
+  }));
+}
+

Terms with a single source document

In the case where terms are extracted from one single source document, they are declared by simply declaring that source document:

  
+  "documents": {
+    "<terms type>": {
+      "fetch": "…",
+      "executeClientScripts": "…",
+      "filter": "…",
+      "remove": "…",
+      "select": "…"
+    }
+  }
+  
+

Terms with multiple source documents

When the terms are spread across multiple source documents, they should be declared by declaring their combination:

  
+  "documents": {
+    "<terms type>": {
+        "combine": [
+        {
+          "fetch": "…",
+          "executeClientScripts": "…",
+          "filter": "…",
+          "remove": "…",
+          "select": "…"
+        },
+        {
+          "fetch": "…",
+          "executeClientScripts": "…",
+          "filter": "…",
+          "remove": "…",
+          "select": "…"
+        }
+      ]
+    }
+  }
+  
+

If some parts of the source documents are repeated, they can be factorised. For example, it is common for the structure of HTML pages to be similar from page to page, so select, remove and filter would be the same. These elements can be shared instead of being duplicated:

  
+  "documents": {
+    "<terms type>": 
+      "executeClientScripts": "…",
+      "filter": "…",
+      "remove": "…",
+      "select": "…",
+      "combine": [
+        {
+          "fetch": "…",
+        },
+        {
+          "fetch": "…",
+        }
+      ]
+  }
+  
+

Terms type

Great, your terms declaration is now almost complete! You simply need to write it under the appropriate terms type in the documents JSON object within the service declaration.

In order to distinguish between the many terms that can be associated with a service and enable cross-services comparison of similar terms, we maintain a unique list of terms types in a dedicated repository.

Please note, the terms type may differ from the exact name provided by the service, but it should align with the underlying commitment. For example, some providers might call “Terms and Conditions” or “Terms of Use” what some others call “Terms of Service”.

If the terms you want to add don’t match an existing type, you can suggest a new one.

Testing your declaration

You can test the declarations you created or changed by running the following command:

npm test [$service_id [$another_service_id]]
+

Since this operation fetches documents and could be long, you can also validate the declaration structure only:

npm run test:schema [$service_id [$another_service_id]]
+

Linting

In order to ensure consistency across declarations, all declarations files have to be formatted homogeneously.

In order to achieve this, you can use the following command:

npm run lint [$service_id [$another_service_id]]
+
+ + \ No newline at end of file diff --git a/terms/tracking-new-terms/index.html b/terms/tracking-new-terms/index.html new file mode 100644 index 00000000..8c49c1e4 --- /dev/null +++ b/terms/tracking-new-terms/index.html @@ -0,0 +1,11 @@ +Tracking new terms

Tracking new terms

Tracking terms is done by declaring them and the service they are associated with. Such a declaration is achieved by editing JSON files in the declarations folder.

Before adding new terms, open the declarations folder and check if the service you want to track terms for is already declared. If a JSON file with the name of the service is already present, you can jump straight to the Terms reference. Otherwise, keep reading!

Declaring a new service

Before declaring a service, you will need to choose the service name and service ID. The service ID will be the name of the JSON file in which the service will be declared. It is a normalised version of the service name.

Service name

The service name is exposed to end users. It should reflect as closely as possible the official service name, as referenced in the terms or “about” pages, so that it can be recognised easily and unambiguously.

  • The service name should be the one used by the service itself, no matter the alphabet, UTF symbols, spaces, and casing.
    • Example: eBay.
    • Example: hi5.
    • Example: LINE.
    • Example: App Store.
    • Example: туту.ру (Cyrillic).
    • Example: 抖音短视频 (Simplified Chinese characters).
  • Domain name extensions (TLDs) are allowed when they are part of the official service name.
    • Example: Booking.com.
    • Example: historielærer.dk.
  • Service names can be prefixed by the provider name, separated by a space, when it would otherwise be too generic or ambiguous.
    • Example: Ads (by Facebook) → Facebook Ads.
    • Example: Analytics (by Google) → Google Analytics.
    • Example: Firebase (by Google) → Firebase.
    • Example: App Store (by Apple) → App Store.

If you have a hard time finding the service name, check out the practical guidelines to find the service name, and feel free to mention your uncertainties in the pull request! We will help you improve the service name if necessary 🙂

Service ID

The service ID is exposed to developers. It should be easy to handle with scripts and other tools.

  • Non-ASCII characters are not supported. Service IDs are derived from the service name by normalising it into ASCII.
    • Example: RTÉRTE.
    • Example: historielærer.dkhistorielaerer.dk.
    • Example: туту.руtutu.ru.
    • Example: 抖音短视频Douyin.
  • Punctuation is supported, except characters that have meaning at filesystem level (:, /, \). These are replaced with a dash (-). The dot (.) is supported, but the service ID cannot be solely . or .. as these have specific meanings in the filesystem.
    • Example: Booking.comBooking.com.
    • Example: Yahoo!Yahoo!.
    • Example: re:startre-start.
    • Example: we://we---.
  • Capitals and spaces are supported. Casing and spacing are expected to reflect the official service name casing and spacing.
    • Example: App StoreApp Store.
    • Example: DeviantArtDeviantArt.

If you have a hard time defining the service ID, check out the practical guidelines to derive the ID from the service name, and feel free to mention your uncertainties in the pull request! We will help you improve the service ID if necessary 🙂

More details on the ID and naming constraints and recommendations can be found in the relevant decision record.

Service declaration

Once you have the service name and the service ID, create a JSON file in the declarations folder named after the ID of the service you want to add, with the following structure:

{
+  "name": "<service name>",
+  "documents": {}
+}
+

Within the documents JSON object, you will now declare terms.

+ + \ No newline at end of file