Re: [Suit] On device resets during manifest processing

"Rønningstad, Øyvind" <Oyvind.Ronningstad@nordicsemi.no> Thu, 07 July 2022 12:48 UTC

Return-Path: <Oyvind.Ronningstad@nordicsemi.no>
X-Original-To: suit@ietfa.amsl.com
Delivered-To: suit@ietfa.amsl.com
Received: from localhost (localhost [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id AB3E2C15D461 for <suit@ietfa.amsl.com>; Thu, 7 Jul 2022 05:48:11 -0700 (PDT)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -1.806
X-Spam-Level:
X-Spam-Status: No, score=-1.806 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, HTTPS_HTTP_MISMATCH=0.1, RCVD_IN_DNSWL_BLOCKED=0.001, RCVD_IN_MSPIKE_H2=-0.001, RCVD_IN_ZEN_BLOCKED_OPENDNS=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01, URIBL_BLOCKED=0.001, URIBL_DBL_BLOCKED_OPENDNS=0.001, URIBL_ZEN_BLOCKED_OPENDNS=0.001] autolearn=ham autolearn_force=no
Authentication-Results: ietfa.amsl.com (amavisd-new); dkim=pass (1024-bit key) header.d=nordicsemi.onmicrosoft.com
Received: from mail.ietf.org ([50.223.129.194]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5yiBPTmjIiCv for <suit@ietfa.amsl.com>; Thu, 7 Jul 2022 05:48:07 -0700 (PDT)
Received: from EUR04-VI1-obe.outbound.protection.outlook.com (mail-eopbgr80082.outbound.protection.outlook.com [40.107.8.82]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 37A11C15D45E for <suit@ietf.org>; Thu, 7 Jul 2022 05:48:01 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=PwWKm1DLAP3TqTvGYqn8pB4MUUNMl7BDQFD7o7rtE1FrdDRl8eViA0pYwMLtuWqB7x5rpzcYMEMvCeSaaCI9SfsVkqElfcuiLbsQRM8OQjC/DQW9p/4CdwZF+/veUuPCjHiLEhicpXCdcVUMJDvE3SapV9BvqW6pftju1THWksNHEbsIjGHmLSRDtAaFJkVeAghGG2DWo7SX6fggnSRQ6dUeZGWN3l7mGJYsRIcac06SWcScKFsECjZQU/T6Nh7pVKokKmq9c6JIBKmVfv0dow2N1bSixBNIRySiDR2Al2IYSllni1RyLiofufXJwAnoi/ho0+RzJLPgv+Jh1R2NYg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=uW84EQVqBiG08txLvj67dynzfZhBM3HU/FG7VQgZD8U=; b=oWw9fcxjK2DgDDslpjfsgpCyrTv5Tz5LES4tY+qgeKCeceING29kVhgCqdkkZjAhMIw3mjEiemJk8BMxy7D5/94RnA3wK+/OjscaqrlwrUTZ8C5Nv5WsHdOGzO8K3AEsY8ekAKj8P9VdyOfJoWuOVMszsWLT0jSm/9ozVzh7NbOCFK35vGSSgQQeTh+oGdXxdNRhWxC+Yi/hmpCv4Me9kRKZd5ByFQ0KN3n/seYXiQZbWVNjohIrYZHk9BxkrDwA2txPs36+5z0+Frmcgq+UFb8qD+cFU0Oi6+/pKPh4LqP++9LunU2n2senSM0dhStDv8mezcrmN4J3tJVxkg3TIg==
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nordicsemi.no; dmarc=pass action=none header.from=nordicsemi.no; dkim=pass header.d=nordicsemi.no; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nordicsemi.onmicrosoft.com; s=selector2-nordicsemi-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=uW84EQVqBiG08txLvj67dynzfZhBM3HU/FG7VQgZD8U=; b=PrpBmAakKhOD3x4Do2rQXjQvOb9NaHf/iKQacL9eOvBq+89IUfzF1ahXZVJJj/hfyIxawwww149ThPS8qDfiyM7NhvsWRISD5ykdOSzBUBI2yUzUPiFSkKE1hCFXd4gQl+NCVfKxStcrBpgE+qQaF7FdKznp258BXIbJTLXd1HA=
Received: from AM9PR05MB7668.eurprd05.prod.outlook.com (2603:10a6:20b:2cc::13) by DB9PR05MB8704.eurprd05.prod.outlook.com (2603:10a6:10:2be::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5417.15; Thu, 7 Jul 2022 12:47:55 +0000
Received: from AM9PR05MB7668.eurprd05.prod.outlook.com ([fe80::dd1f:a176:9106:ff37]) by AM9PR05MB7668.eurprd05.prod.outlook.com ([fe80::dd1f:a176:9106:ff37%2]) with mapi id 15.20.5417.016; Thu, 7 Jul 2022 12:47:55 +0000
From: "Rønningstad, Øyvind" <Oyvind.Ronningstad@nordicsemi.no>
To: Brendan Moran <Brendan.Moran@arm.com>
CC: "suit@ietf.org" <suit@ietf.org>
Thread-Topic: [Suit] On device resets during manifest processing
Thread-Index: AdiPr99Tl0KFMg/lQV6mT+U8i/TDfgBgohtAABV+N4AAGe75UA==
Date: Thu, 07 Jul 2022 12:47:55 +0000
Message-ID: <AM9PR05MB766873AB6D56A4AB105308E388839@AM9PR05MB7668.eurprd05.prod.outlook.com>
References: <AM9PR05MB766851037AC1FA6D542713A588809@AM9PR05MB7668.eurprd05.prod.outlook.com> <AM9PR05MB766827642091BA812BAC891188809@AM9PR05MB7668.eurprd05.prod.outlook.com> <1EBCBBDE-3CED-476B-BE26-3A6D096A69BF@arm.com>
In-Reply-To: <1EBCBBDE-3CED-476B-BE26-3A6D096A69BF@arm.com>
Accept-Language: en-US
Content-Language: en-US
X-MS-Has-Attach:
X-MS-TNEF-Correlator:
authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nordicsemi.no;
x-ms-publictraffictype: Email
x-ms-office365-filtering-correlation-id: a9219aab-0842-4ae8-63df-08da6016e9cc
x-ms-traffictypediagnostic: DB9PR05MB8704:EE_
x-ms-exchange-senderadcheck: 1
x-ms-exchange-antispam-relay: 0
x-microsoft-antispam: BCL:0;
x-microsoft-antispam-message-info: r/m5gDOeIaQheI9oL3g9aHpp3nUm/bPAWGXZ3TAbjnI22wn7qlf4Vxdeun0rZY26Ad2aSP6Wt5ff1mi0fvo/Cr1zLGBS3mNFuNXEDrwyGs35J9Scg0Uc9FbPIKPeH5WTTJFDRX++W2N5fxK+mIpZTNRORufNwrvEaVqhbEwGjw0RJfyOa6oy2tUhAh8y/nmDqBxS2mJbcIw9NDs0zHsoNwDx8Pgd8X23Aw0uHHOF2PF3JQGO3npqq2jqal0tnWpzJYjgkmJUPPD/dbRDgnDATlHVCNE11X3CPCEh9vZLHrdlJRIFnUaDIUhoUihOyN7Om/eBTQPuPt4YQVIVZi0FkPOpE4ehmncQVdiTAsigup+nclzScsNNBJ6G++ntjw0UmhzqkLnj+u/4G9Zi9abzIGJnB1BrvZV37BAvd4t2ELMld+ZFzPDY24sGZY2RBNi8hzgKuHeFplRI3lRdCLo2khP9gZaJIY0r6wlLq5gQOxik2fnBhRflyAczPQAoqXD4dYoHzuqwAA0tQLtLMR9Dz+M7wE6VbmSKUJJ+svfa/F1r6GYWovfVBssCeRQjoJmtbevv6MJvlLeU9qLE7AXNU6Up9IFX0wqHkWIzquSGpT+tospdQ5Kgp1Mc3w5H7S8/wyrFWduUqCGcv+XyXKcorn0DlQIoDPTDi3/J4Jx8pGdN/HNr8rYjK0s5LAfnYTXgUk3prL0v1o5XN2fLgnMvg8CHMFNb/lmTPhbhufkpQr8KflRQn+nlClKAxznXpcHdu7kD5Nm4BLsRC/GqsTb7kxFqlAOPkOzZrSpk68aB+SV6ulxuYJgH2wbWtc/GPHEHSoOZxiW/2djx2X/xWLSESvB8KTYx8ay5Zbmd0Il9UQy9uMmxogQAxquH49+Jko+dAqBpenFDUPZscKItD7o0Qw==
x-forefront-antispam-report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:AM9PR05MB7668.eurprd05.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230016)(4636009)(366004)(136003)(396003)(39850400004)(376002)(346002)(316002)(83380400001)(122000001)(166002)(38070700005)(38100700002)(71200400001)(8936002)(8676002)(66946007)(66556008)(9686003)(64756008)(5660300002)(66446008)(66476007)(6506007)(76116006)(2906002)(966005)(4326008)(55016003)(478600001)(7696005)(52536014)(86362001)(6916009)(33656002)(186003)(41300700001); DIR:OUT; SFP:1101;
x-ms-exchange-antispam-messagedata-chunkcount: 1
x-ms-exchange-antispam-messagedata-0: ynqy2yRDvMq+Y/rYdEBKJhmlLjsnGtiMMKoNvnC1lm0w+JdlkDwNGBTjP0se88QKkSHn44IgxEU0np5SAVwsshBSacuOtk2QU9PmYBeMOZ/2BQVjNXZLf93XstYIGCBCBlrSPUYWjKnyImehH3dNYa2tZaHvN6E5HyBFzZt5bMSNpyk2BEDi3EXY5Kmb7l+hsNutp7pDLQlwpzQ1TUNY7Cb0kvUda+0fHZmp3mGA1HylaYM0YXEUV6n56zXXSsQeFgzrzgc9+2HTvsey3xZ4VhGFdGMoaXJcqwn+vnhrcGP5CZHAY+F4fyXDE3tYrruQ8h09DXDZZgCgNTCeBtPNKmxJB61l0+KEtXsMDH7wr8XHsq78GoArxODJdQP964QmGTOwo4arpsFKDcGX0WlWVPE1NaybfweAD688DnzjXgTUHM0isaWiWi611mRfNA5oD4joDLzKRHlN6NVvYEvR2gQrt56Tbsjp2lK7XdkNgyfFVpGI9RHq4ADfeMlXuNB4Q6e1KS3r6Mz8YHw9Fgrf4DRPWB192KoKPPpd25xCISylQgnzLVpwWllmrhzI55DJahLTJX3I1Dk4wpdkVnDxX2Re32MMa7c6fJdYZfeb51wVvoahAeFY+vhH2Zm79MkbuDQJXNGYJ5n1Z7HH4kvGqy8fYuKd2gaL6dFDYBFqS/UB07VgkLC5qlbF/+ZQUqAxD9rV3tfYviyJVzwaBB9sqQPxeG0MjSFqXKl8Ns0GldhkhIScatk6/8qg/jhA0k9vj4E5EXztjh+1VBpTxWQANkKb2myjBW4Xhd5k3TRgh8Ufh05AElHJ2qNIXHEcw+EDjcI+/aWnnGatETd7RCRBrJIqpoiveB2fuWBaoXG7Yj1t2ph7eQUZYYtf68Lok8kXkL2sy4AKlbvYcSX9j9ILJd7uD56OkwSxXgrClRAOK0/KsYQ5LBikPbCeFuGb8zJHEr71KfpzuF2+dhXC6wHFQTgbfSw2w7PjjH6hW8eA/se+BWKpWFtsGBvr58z2wnTO1B7P+G7a8lNobcCQI0907h5hv4LNqjqlR7hCgrBy/G0QlWvFbnjo8xxSURcgoB30VHmOlqf9ClRkiiDur2V8hpyTKEBq+hBKjeztjObnun5OH2yQZHE7ug4kR33qBCJEE+2NZualNk40TLHoYwlKuUr0AuAdBkTNcLw/UNNiny3BEiCzjCQTok5ie1eC8Ch0bpYfmz/0FqYwaIQOcsraFZr6VyjoTBroVRsLtCOMCYh00El4ht9SI2UR7Pti6ZP40PVzc6cE62HjYsKSfwF7HhaDGp9ufgqHwiGOTsMEkHwC49hf+9d9iNS4lS7jMKFmghjzglJGJkRSrYxtrguavqhx6qKfLG6AgKHIr/54ZWVu4NFEEVuluAQrF4is8JKJ1EU7Im627ENFHApXOWIxOQgJt3lritOliHYGgPpTQBI55OJ0u+nHcjtx4oesobRpresQb3OEizLA9cNRBCEqXzLq0M6FBNlhfQsC2/2fWZNw8Q/7LiMhHv4Rtg8KCNchQbDfhIb2klCOSbyOdTAvPIeM3/2KGdAK2xilDqUjsAmTqwfpigUiYyW+x+z8aU6XuM5Ga/LNMoNlebBhPapmSKCTsiHnEytzmdj4GzKCeUn6K2z0p/MB10jt0vDKsG9IJHscvz6k8Jv2ynWWoJHgEw==
Content-Type: multipart/alternative; boundary="_000_AM9PR05MB766873AB6D56A4AB105308E388839AM9PR05MB7668eurp_"
MIME-Version: 1.0
X-OriginatorOrg: nordicsemi.no
X-MS-Exchange-CrossTenant-AuthAs: Internal
X-MS-Exchange-CrossTenant-AuthSource: AM9PR05MB7668.eurprd05.prod.outlook.com
X-MS-Exchange-CrossTenant-Network-Message-Id: a9219aab-0842-4ae8-63df-08da6016e9cc
X-MS-Exchange-CrossTenant-originalarrivaltime: 07 Jul 2022 12:47:55.4223 (UTC)
X-MS-Exchange-CrossTenant-fromentityheader: Hosted
X-MS-Exchange-CrossTenant-id: 28e5afa2-bf6f-419a-8cf6-b31c6e9e5e8d
X-MS-Exchange-CrossTenant-mailboxtype: HOSTED
X-MS-Exchange-CrossTenant-userprincipalname: 6jQVVJZiZkBKnnvSRGfQ8zwiipNyMkkRX39ZNK/xQmHBTiPwFPndJVARp/0orA5LehE9y3fISMJEo1k1JpYXML5Vrs06tt9V/2FsMmdZ8zQXbduCK3uXPZ9phtfuwXi1
X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR05MB8704
Archived-At: <https://mailarchive.ietf.org/arch/msg/suit/HsCmMcjRwoT7M26FH-8HLkVXuoQ>
Subject: Re: [Suit] On device resets during manifest processing
X-BeenThere: suit@ietf.org
X-Mailman-Version: 2.1.39
Precedence: list
List-Id: Software Updates for Internet of Things <suit.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/suit>, <mailto:suit-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/suit/>
List-Post: <mailto:suit@ietf.org>
List-Help: <mailto:suit-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/suit>, <mailto:suit-request@ietf.org?subject=subscribe>
X-List-Received-Date: Thu, 07 Jul 2022 12:48:11 -0000

Hi Brendan, thanks for the detailed reply. Note that I finished this email before your second email with the proposed manifest text. I will reply to that separately.

I think this is actually moderately simple to do and it's my preferred alternative. The rules are:
1.       Condition Failures are recorded because they alter the flow of the manifest
2.       Nonvolatile state-altering commands (Copy, Fetch, Swap) are recorded because we need to know which failed if there is more than one between other records
These are stored in a journal, like the SUIT Report, and used to guide the manifest parser until it runs out of journal entries. Because a Copy/Fetch with a volatile target is a potential source of problems in this approach, we may need to perform those again. This might become a challenge. I think it might take some more consideration to work through this question.

I agree. Hopefully there is a simple ruleset that can be used.

Progress tracking in non-volatile memory
===============================

Essentially, this is a journal approach. The manifest parser uses the journal (a SUIT Report, for example) along with the manifest to recreate the parser state immediately before failure.

On startup, the manifest processor checks for a SUIT Report matching the manifest in its report storage area. If there is not one, it creates one and starts processing the manifest.

If there is already a SUIT Report matching the manifest, then it begins processing the manifest, using the SUIT Report to determine what state it should hold-since that is the purpose of the SUIT Report-effectively treating each command as a "dry run" if it has a corresponding entry in the SUIT Report.

When it comes to the end of the SUIT Report, it knows that all subsequent commands did not execute to completion. There's a small hiccup here: it's not currently mandatory for commands that modify non-volatile system state to append to the SUIT Report. We can fix that by ensuring that they have the correct reporting policy when constructing the manifest (https://datatracker.ietf.org/doc/html/draft-ietf-suit-manifest-17#section-8.4.7<https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdatatracker.ietf.org%2Fdoc%2Fhtml%2Fdraft-ietf-suit-manifest-17%23section-8.4.7&data=05%7C01%7COyvind.Ronningstad%40nordicsemi.no%7Cb88835e0fdcf4427f24808da5f9f9b7f%7C28e5afa2bf6f419a8cf6b31c6e9e5e8d%7C0%7C0%7C637927436364714700%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=GHrM%2FGl6qp2M%2FlMwGd55EmtLUkPyjWQ76knsGzS7BK8%3D&reserved=0>) or we can override the default behaviour of reporting policy for those commands in the Manifest Processor.

Since this is an application-specific mitigation for power loss/reset, I would prefer to have the Manifest Processor override the specified reporting policy for any commands that alter non-volatile system state.

I agree a SUIT Report should be a good way to perform the caching. I believe we should take a few steps to ensure that using reports for the sake of reset resilience doesn't interfere with other uses for the reporting machinery. Sometimes, a command needs to be reported for the sake of auditing (or something else), but needs to NOT be reported for the sake of reset resilience. And sometimes the opposite. If we were to add additional bits to suit-reporting-bits specifically for the purpose of reset resilience, that would be more or less analogous to the separate directive I proposed. I think that could be a good way to make this type of reporting independent of the other types.

QUESTION:
Should we add some language around using a SUIT Report for manifest resumption in scenarios where the manifests may have enough complexity that simply re-running the manifest will not result in a correct installation?

I think we should have language explaining the problem and proposing a solution. If using SUIT Reports becomes our proposed solution, then the proposed mechanism should be fully explained.

This doesn't have to be a SUIT Report, but it is a convenient way to express the idea.

I agree

Application-Specific Command-Resumption
=================================

We have discussed this in connection with MCUBoot support for image swap in the past. MCUBoot uses a resumable image swap algorithm that will continue even if it is interrupted. This could potentially be applied to other operations that modify non-volatile state, such as applying a differential update. I'm not sure how applicable it is to non-diff, non-swap operations.

This also applies to copy, if it supports overlapping source and destination (think memmove() vs memcpy()). I think this should not be in the scope of copy, since it will rarely be necessary, and when it is, it can usually be reproduced via multiple non-overlapping copy operations.

PROPOSED:
A command that alters system state in a way that prevents a repeated execution of the command from completing correctly MUST provide a journal that it can use to resume execution correctly.

I agree, just want to clarify that this is about atomicity: The command has to EITHER revert to its before-state (this is entirely possible with swapping at least), OR it must be completed. After that, other resumption logic can run. I.e. there's (at least) two levels of resumption logic, first complete or roll back the interrupted command (if needed), then complete or roll back the command sequence.

Partial Completion Detection in the Manifest
=================================

Using the Try-Each block we can build a number of constructs that allow us to resume in the correct state. For example, in the sequence you provided:
1.       Copy from Component ID 100 to 200
2.       Copy from Component ID 300 to 100

This can be replaced in a reasonably straight-forward way:
1.       If not Image Match Component ID 200
1.       Copy from Component ID 100 to 200
2.       If not Image Match Component ID 100
1.       Copy from Component ID 300 to 100

This uses the existing manifest structure to check for a partial completion in a repeatable way.

This does indeed solve the problem nicely. It makes me think that maybe there should be an alternative to copy, which merges the copy and the image match, essentially serving as:


  1.  Try-each:

     *   (sequence a)

                                                   i.      Image match

                                                 ii.      Copy

                                               iii.      Image match

     *   nil



This second example, however is more challenging.
1.       Copy from component Foo (non-volatile) to component Bar (volatile)
2.       Copy from somewhere to Foo
3.       Copy from Bar to Baz (non-volatile)
I understand this conceptually, however I'm having difficulty seeing whether we should consider it as a use case that dictates how we construct the specification. The actions themselves are inherently risky, regardless of whether or not SUIT is involved.

Yes, this was just to demonstrate that it is possible to construct these sequences "by mistake". I fully believe there's always better ways to construct these. There should be some text discouraging or prohibiting these sequences. One rule could be:

"If a component serves as a copy source for a volatile component, it cannot itself be modified before that volatile component has been unlinked."

Maybe we need a tool for correctly generating manifests under these conditions?

That would be very helpful, given we are able to formulate the ruleset. I feel that, depending on the complexity of the ruleset, it either works better as a tool during manifest generation, or as part of the manifest processor.

I think this is a great example of reconstruction using a SUIT Report (progress tracking in non-volatile memory). By replaying the manifest, but using the SUIT Report to guide the result of any conditions, and using the SUIT Report to skip any non-volatile state altering commands, we can perfectly reconstruct the state of the parser, prior to any resets or power failures, in-situ, which allows us to continue processing wherever the previous run left off.

I agree, but we do still need to figure out which commands should go into the report, and either explicitly choose them during manifest creation, or automatically infer them during manifest processing, or both.

Yes, I think this makes sense. Perhaps we should define the two overarching options: journaling and resilient manifest construction.

Sound good to me.
There's already a requirement in the Architecture document, but perhaps a Threat in the Threat Model would help.

Devices must not fail when

   a disruption, such as a power failure or network interruption, occurs

   during the update process.
https://datatracker.ietf.org/doc/html/rfc9019#section-3<https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdatatracker.ietf.org%2Fdoc%2Fhtml%2Frfc9019%23section-3&data=05%7C01%7COyvind.Ronningstad%40nordicsemi.no%7Cb88835e0fdcf4427f24808da5f9f9b7f%7C28e5afa2bf6f419a8cf6b31c6e9e5e8d%7C0%7C0%7C637927436364714700%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=H4u4iTFyFAKqwHTcJ7FV5D2OsYLRk2cwRHKro0K8Umc%3D&reserved=0>

Thanks, I had a feeling I'd missed something about it.

Best regards, Øyvind