Git Product home page Git Product logo

app-store-server-api's People

Contributors

agisboye avatar biancadanforth avatar depasqualeorg avatar fariassdev avatar fschindler avatar levi avatar mattcontinisio avatar mishkhan avatar mitty-company avatar ralle avatar vladimir-goldobin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

app-store-server-api's Issues

Get transaction history with wrong query parameter revision

Hello,

The query parameter revision name in the API getTransactionHistroy is wrong. It should be revision not query
See the API from apple doc.
image

In the current implementation, the query field is a typo.

 async getTransactionHistory(originalTransactionId: string, revision?: string): Promise<HistoryResponse> {
    const query = revision ? `?query=${revision}` : ""
    return this.makeRequest(`${this.baseUrl}/inApps/v1/history/${originalTransactionId}${query}`)
  }

Not an Issue but a Thank You

Just wanted to leave a comment thanking you for creating this library. I'm using it only for one function - verify Apple Server notifications. After a week of CrApples IAP docs I'm so glad I found this library!

Any chance to add 403 into error path of makeRequest?

I am currently developing subscription extension and some errors are from status code 403
4030004: Subscription Extension Ineligible
4030005: Subscription Max Extension
4030007: Family Shared Subscription Extension Ineligible
Right now all these errors are grouped to unknown error.
Thank you!

Sandbox Testing Not Working?

Thanks for the great framework!

I am able to successfully look up Order IDs in the Production environment. Production environment seems to generally be working perfectly for preexisting order IDs from my real users.

I now need to test the purchase workflow for new purchases, which requires testing in the Sandbox environment.

When I switch the environment to Environment.Sandbox, and try to lookup a sandbox orderId, I then receive the following error on my server:

Error: {"message":"invalid json response body at https://api.storekit-sandbox.itunes.apple.com/inApps/v1/lookup/2000000087140012 reason: Unexpected end of JSON input","code":141} {"error":{"code":141,"message":"invalid json response body at https://api.storekit-sandbox.itunes.apple.com/inApps/v1/lookup/2000000087140012 reason: Unexpected end of JSON input"} error: invalid json response body at https://api.storekit-sandbox.itunes.apple.com/inApps/v1/lookup/2000000087140012 reason: Unexpected end of JSON input {"code":141,"stack":"FetchError: invalid json response body at https://api.storekit-sandbox.itunes.apple.com/inApps/v1/lookup/2000000087140012 reason: Unexpected end of JSON input\n at /app/node_modules/app-store-server-api/node_modules/node-fetch/lib/index.js:27

Here is the code I am using to lookup the Order ID:

`

const api = new AppStoreServerAPI(
  KEY, KEY_ID, ISSUER_ID, APP_BUNDLE_ID, Environment.Sandbox
);

const response = await api.lookupOrder(orderId);

//console.log(response);

console.log(response.status);

if (response.status === OrderLookupStatus.Valid) {
    const transactions = await decodeTransactions(response.signedTransactions);`

Could something have changed on Apple's end for Sandbox testing? Is the Sandbox Environment confirmed to currently be working in the framework?

Any advice or fixes would be very much appreciated!

Thank you

General question on how your library was created

Sorry I know this question is not directly related to your project. Just you are one of the few people I have found that have created any code for this API. I need to do something similar in Java but I am not finding any official specification for the App Store Notifications v2. Is there an openAPI spec for this library?

Always getting 401 Unauthorized.

We are receiving the below error always, we changed the params, different keys, anything will return the same error.

Error: The request is unauthorized; the JSON Web Token (JWT) is invalid. at AppStoreServerAPI.<anonymous> (/node_modules/app-store-server-api/dist/cjs/AppStoreServerAPI.js:158:31) at step (/node_modules/app-store-server-api/dist/cjs/AppStoreServerAPI.js:52:23) at Object.next (/node_modules/app-store-server-api/dist/cjs/AppStoreServerAPI.js:33:53) at fulfilled (/node_modules/app-store-server-api/dist/cjs/AppStoreServerAPI.js:24:58) at processTicksAndRejections (internal/process/task_queues.js:97:5) transactions---- Error: The request is unauthorized; the JSON Web Token (JWT) is invalid. at processTicksAndRejections (internal/process/task_queues.js:97:5) { isHttpError: true, status: 500, code: 'UnknownError', data: undefined, source: undefined } []

our code here:

 const api = new AppStoreServerAPI(
            key, keyId, issuerId, iosBundleId, Environment.Production
        );

        const response = await api.lookupOrder(orderId);

        if (response.orderLookupStatus === OrderLookupStatus.Valid) {
            const transactions = await decodeTransactions(response.signedTransactions);
            return {
                error: null,
                transactions
            };
        }

Signing and Verifying payload

I want to simulate Apple notifications http call without using Apple device. I just want to trigger it on my own, using some http client, so I can be in ownership what payload of notification (decoded one) is, so it's easier to test.

In order to achieve that first of all I need to sign payload, how can I achieve that?
I assume I need private key and later on I can use some library (e.g jsonwebtoken) to sign payload.
I also need fingerprint and pass it to function that decodes payload (e.g to decodeTransaction). How I can get fingerprint that would match private key?

If you can help, or redirect me to some documentation that would be helpful.

Regards

Error on decodeNotificationPayload

Hi! I am so excited to see this library, thank you for creating it.

I set everything up and attempted to use const payload = await decodeNotificationPayload(signedPayload). However, I got an error:

(node:1) UnhandledPromiseRejectionWarning: TypeError: crypto_1.X509Certificate is not a constructor
[cookup-action-service] [2022-05-20 21:43:16]     at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:133:60
[cookup-action-service] [2022-05-20 21:43:16]     at Array.map (<anonymous>)
[cookup-action-service] [2022-05-20 21:43:16]     at validateCertificates (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:133:34)
[cookup-action-service] [2022-05-20 21:43:16]     at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:111:29
[cookup-action-service] [2022-05-20 21:43:16]     at step (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:52:23)
[cookup-action-service] [2022-05-20 21:43:16]     at Object.next (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:33:53)
[cookup-action-service] [2022-05-20 21:43:16]     at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:27:71
[cookup-action-service] [2022-05-20 21:43:16]     at new Promise (<anonymous>)
[cookup-action-service] [2022-05-20 21:43:16]     at __awaiter (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:23:12)
[cookup-action-service] [2022-05-20 21:43:16]     at getKey (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:106:74)
[cookup-action-service] [2022-05-20 21:43:16] (node:1) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)

Any ideas?

"Certificate validation failed" error when decoding transactions

I'm decoding transactions as follows, but I get the error "Certificate validation failed". I've verified that the environment variable is correct for the development environment. I haven't tried it in production yet. Any idea why this would be failing in the development environment?

import type { Action } from '@sveltejs/kit';
import { json } from '@sveltejs/kit';
import { decodeTransactions, APPLE_ROOT_CA_G3_FINGERPRINT } from 'app-store-server-api';
import { ENVIRONMENT } from '$env/static/private';

// https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode#Prepare-to-validate-receipts-in-the-test-environment
const LOCAL_ROOT_FINGERPRINT = 'FF:0B:A3:<redacted>';
const fingerprint = (ENVIRONMENT.toLowerCase() === 'production') ? APPLE_ROOT_CA_G3_FINGERPRINT : LOCAL_ROOT_FINGERPRINT;

export const POST: Action = async ({ request }) => {
  const requestData: { transactions: string[] } = await request.json();
  const decodedTransactions = await decodeTransactions(requestData.transactions, fingerprint);
  // Error: Certificate validation failed
  console.log(decodedTransactions);
  return json({});
};

Sample Payload to Test

Do you have sample payload to test the below decoding? Its because it is difficult to simulate a real request. Thanks for the help.

const transactionInfo = await decodeTransaction(item.signedTransactionInfo)
const renewalInfo = await decodeRenewalInfo(item.signedRenewalInfo)

API Key and Issuer ID

Do I need the API Key, the ID of the key and Issuer ID also if I only want to decode server notifications v2?

Thanks for the clarification.

TextEncoder is not defined

It works fine in the local environment, but when I turn on the server on AWS, it returns the following error.

AWS: Ubuntu 20.04
Node: 17.7.1
Express: 4.17.3

ReferenceError: TextEncoder is not defined
    at Object.<anonymous> (/home/ubuntu/mrheropurchaselogserver/node_modules/jose/dist/node/cjs/lib/buffer_utils.js:5:23)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (/home/ubuntu/mrheropurchaselogserver/node_modules/jose/dist/node/cjs/runtime/base64url.js:5:27)
    at Module._compile (internal/modules/cjs/loader.js:778:30)

The token always is invalid

Hello,

Happy to see there is a client lib to communicate with app store server API. Thanks for your contribution.

Today, I have tried with this library, but I always got the 401 error.
The code I tested is

const KEY = `-----BEGIN PRIVATE KEY-----
xxxxxxx
-----END PRIVATE KEY-----`

const KEY_ID = "xxx";
const ISSUER_ID = "xxxx";
const APP_BUNDLE_ID = "xxx";

const ServerApi = new AppStoreServerAPI(
  KEY, KEY_ID, ISSUER_ID, APP_BUNDLE_ID, Environment.Sandbox
);
let results = await ServerApi.getTransactionHistory(1000000944298944);

I have debugged the code, it seems that the jwt lib jose return an invalid token. After replace with jsonwebtoken, the token is valid.

Could you kindly help double-check if this is an existing issue? Thanks! And hope there will be a correction. Thanks!

Add all (or more) types as default exports

Firstly, thank you very much for creating this API client library.

One issue I encountered when using the library is that not every type that our code uses is part of the default exports in src/index.ts.

In particular, we are currently using or plan to use the following types which are not part of the library's default exports:

  • JWSTransactionDecodedPayload
  • OwnershipType
  • TransactionType
  • StatusResponse
  • LastTransactionsItem
  • JWSRenewalInfoDecodedPayload

And in general, others that could be useful that are not default exported:

  • HistoryResponse
  • SubscriptionGroupIdentifierItem
  • OrderLookupResponse

Can these types be added to the default exports in src/index.ts? I plan to open a PR to this effect shortly for your consideration.

Skip check for Apple root CA in sandbox environment

Just wanted to float this for discussion...

When testing StoreKit with Xcode using a StoreKit Configuration file (henceforth referring to as SKC), it appears that the transactions do not include Apple's signature like their production transactions do. However, if you don't use an SKC then the sandbox transactions do get Apple's signature. It is only when using an SKC do the transactions seem to skip the root CA. I'm guessing that this means that using an SKC results in transactions being generated completely locally, whereas otherwise- even in the sandbox environment- they are generated remotely by Apple and signed with their root CA.

What this means for us is that, because our app relies on our backend for tracking user entitlements, we cannot decode and process test transactions generated by our SKC because they are missing Apple's certificate in validateCertificates. The only way to test transactions with our backend is to not use an SKC, which isn't the end of the world but floods Xcode with errors such as Finance Authentication Error. It seems that Xcode wants developers to use an SKC when possible, but as far as I can tell it's not required.

I'm wondering what the implications would be if validateCertificates was changed such that Apple's root CA was only required in the production environment. This would make testing easier, but I'm not certain if there would be negative side effects. The only thing I can think of at the moment would be the potential to forge fake sandbox transactions.

Also curious to know how other developers handle SKCs with their workflows in general. Maybe the solution isn't to modify validateCertificates but instead to have some other flow for SKC transactions entirely.

Thanks.

TypeError: crypto_1.X509Certificate is not a constructor

Hi, when I tried your package, I got the above error with every request for test-notifications.

I have posted the code here.

The exact error is this one. If I have forgotten something in the sample code, please add it here in the comments.

TypeError: crypto_1.X509Certificate is not a constructor
    at /node_modules/app-store-server-api/dist/cjs/Decoding.js:142:60
    at Array.map (<anonymous>)
    at validateCertificates (/node_modules/app-store-server-api/dist/cjs/Decoding.js:142:34)
    at /node_modules/app-store-server-api/dist/cjs/Decoding.js:118:29
    at step (/node_modules/app-store-server-api/dist/cjs/Decoding.js:56:23)
    at Object.next (/node_modules/app-store-server-api/dist/cjs/Decoding.js:37:53)
    at /node_modules/app-store-server-api/dist/cjs/Decoding.js:31:71
    at new Promise (<anonymous>)
    at __awaiter (/node_modules/app-store-server-api/dist/cjs/Decoding.js:27:12)
    at getKey (/node_modules/app-store-server-api/dist/cjs/Decoding.js:113:74)

Missing latest tag on release 0.12.0

Hi August.

I think there is missing the latest tag on the release 0.12.0, so the repo is still showing in the 0.11.1 as latest version.

Screenshot 2023-10-05 at 10 00 43

Thanks for your time!

Occasional timeout on getSubscriptionStatuses

Hi there! I previously was not encountering this issue so I am wondering if this is a current problem with Apple's sandbox server, not sure. Currently when using the AppStoreServerAPI with a sandbox environment, while calling await api.getSubscriptionStatuses(originalTransactionID); every now and then this call will timeout for over 60 seconds. This in itself is confusing because the call will work once or twice and then timeout the next time and then work etc.

I am currently using the AppStoreServerAPI inside a Firebase cloud function which will cancel the function execution after this 60-second timeout. This timeout functionality is triggering because there is no return from the await api.getSubscriptionStatuses(originalTransactionID); in this 60 second time period.

As I stated above I am only noticing this issue now (first on 0.7 but I have since upgraded to 0.9 and the issue still persists) although while testing this functionality a few weeks ago everything was working fine. I have made no changes to my cloud function code within these few weeks so my assumption is that there is an issue with either the API or Apple's sandbox server at the current moment.

I have not tested using the production environment yet (I'm still very new to Apple's subscription framework, and not sure about the implications of using prod vs sandbox for testing). Yeah anyways, so not sure if this is truly an issue with this API but I thought I would bring it to your awareness anyways (could also just be me problem since as I mentioned I'm pretty new to all this subscription stuff in Node js).

Here is a code snippet I'm using this function in.

export const sendIOSSubscriptionInfoSandbox = functions.https.onCall(async (data, context) => {
    // Some authentication code above this
    try {
        functions.logger.warn("Entering updateIOSSubscriptionInfo");
        await updateIOSSubscriptionInfo(originalTransactionId, sandboxAPI, false);
        functions.logger.warn("Finished updateIOSSubscriptionInfo");
    } catch (error) {
        functions.logger.error("Error sending iOS subscription info:", error);
        throw new functions.https.HttpsError("permission-denied", `Error: ${error}`);
    }
});
async function updateIOSSubscriptionInfo(originalTransactionId: string, api: AppStoreServerAPI) {
    // Use fetch subscription to get subscription info
    functions.logger.warn("Entering api.getSubscriptionStatuses");
    const response = await api.getSubscriptionStatuses(originalTransactionId);
    functions.logger.warn("Finished api.getSubscriptionStatuses");
    // Other code using response beneath this
}

During the occasional function calls where api.getSubscriptionStatuses() fails the "Finished api.getSubscriptionStatuses" warning will never trigger and the catch block in sendIOSSubscriptionInfoSandbox will also never trigger which leads me to believe api.getSubscriptionStatuses() is timing out.

No matching export in "node-modules-polyfills:crypto" for import "X509Certificate"

I use a library with Cloudflare Workers:

"devDependencies": {
  "@cloudflare/workers-types": "^4.20230904.0",
  "typescript": "^5.2.2",
  "wrangler": "^3.7.0"
}

when I run the application through the wrangler, it returns an error:

✘ [ERROR] No matching export in "node-modules-polyfills:crypto" for import "X509Certificate"
 ../../node_modules/app-store-server-api/dist/esm/Decoding.js:37:9:
   37 │ import { X509Certificate } from "crypto";~~~~~~~~~~~~~~~
✘ [ERROR] Failed to build

When I make the following changes, everything works as it should:

// src/Decoding.ts | 4 ++--

-import { X509Certificate } from "crypto"
+import * as crypto from "crypto"
 
-  const x509certs = certificates.map(c => new X509Certificate(c))
+  const x509certs = certificates.map(c => new crypto.X509Certificate(c))

Not clear how we detect if subscription is active?

Thanks for this great library, saved me a ton of time!

But; would be nice if we had a short explanation on how we actually know if the user has subscribed or not?

if (renewalInfo.autoRenewStatus == AutoRenewStatus.Off) {

The following code always returns "Off" even though they are still subscribed (although Sandbox)?

Get Refund History

Hi,

I am just wondering if you are planning on adding a getRefundHistory function as well.

Thanks!

401 'Unauthorized' response on first JWT use

I'm getting a 401 response intermittently when calling getSubscriptionStatuses. The issue looks to be time-based, as when I make successive calls (and the previously generated token is picked up from this.token) I get a 200 status - largely on the second attempt.

If I force getToken() to generate a new JWT on each call, by removing the expiration checking logic, the issue starts intermittently affecting every call. So it seems like Apple is failing to verify newly created JWTs that are immediately passed into the request.

It doesn't strike me as being environment related seeing as it is intermittent and hardcoding token in makeRequest() to a JWT generated by getToken() (that originally resulted in a 401 status) always gives me successful responses.

Any help is much appreciated!

Version: 0.6.0
Node: 16.13.0

Certificate validation failed

I have configured everything and also used local fingerprint, but i got this error "Certificate validation failed"

JWSInvalid: Invalid Compact JWS

When I use this library with the signedPayload from Apple I am getting an error:

}
JWSInvalid: Invalid Compact JWS
    at Object.compactVerify (/usr/src/app/node_modules/jose/dist/node/cjs/jws/compact/verify.js:16:15)
    at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:115:47
    at step (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:52:23)
    at Object.next (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:33:53)
    at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:27:71
    at new Promise (<anonymous>)
    at __awaiter (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:23:12)
    at decodeJWS (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:100:12)
    at /usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:90:35
    at step (/usr/src/app/node_modules/app-store-server-api/dist/cjs/Decoding.js:52:23) {
  code: 'ERR_JWS_INVALID'
}

This doesn't surprise me - when I was researching this project I took the signed payload from Apple and just manually decoded it myself. However, Apple says there are three encoded strings separated by .. However, in the string that is sent over there are actually four. That is because in the middle of one of the strings there is a timestamp. I have received multiple payloads from Apple and am seeing this in all situations.

In the below payload you'll see: 2022-05-20T21:43:16.046463081Z with a . before the milliseconds and a (space) after the Z.

eyJhbGciOiJFUzI1NiIsIng1YyI6WyJNSUlFTURDQ0E3YWdBd0lCQWdJUWFQb1BsZHZwU29FSDBsQnJqRFB2OWpBS0JnZ3Foa2pPUFFRREF6QjFNVVF3UWdZRFZRUURERHRCY0hCc1pTQlhiM0pzWkhkcFpHVWdSR1YyWld4dmNHVnlJRkpsYkdGMGFXOXVjeUJEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURUxNQWtHQTFVRUN3d0NSell4RXpBUkJnTlZCQW9NQ2tGd2NHeGxJRWx1WXk0eEN6QUpCZ05WQkFZVEFsVlRNQjRYRFRJeE1EZ3lOVEF5TlRBek5Gb1hEVEl6TURreU5EQXlOVEF6TTFvd2daSXhRREErQmdOVkJBTU1OMUJ5YjJRZ1JVTkRJRTFoWXlCQmNIQWdVM1J2Y21VZ1lXNWtJR2xVZFc1bGN5QlRkRzl5WlNCU1pXTmxhWEIwSUZOcFoyNXBibWN4TERBcUJnTlZCQXNNSTBGd2NHeGxJRmR2Y214a2QybGtaU0JFWlhabGJHOXdaWElnVW1Wc1lYUnBiMjV6TVJNd0VRWURWUVFLREFwQmNIQnNaU0JKYm1NdU1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCT29UY2FQY3BlaXBOTDllUTA2dEN1N3BVY3dkQ1hkTjh2R3FhVWpkNThaOHRMeGlVQzBkQmVBK2V1TVlnZ2gxLzVpQWsrRk14VUZtQTJhMXI0YUNaOFNqZ2dJSU1JSUNCREFNQmdOVkhSTUJBZjhFQWpBQU1COEdBMVVkSXdRWU1CYUFGRDh2bENOUjAxREptaWc5N2JCODVjK2xrR0taTUhBR0NDc0dBUVVGQndFQkJHUXdZakF0QmdnckJnRUZCUWN3QW9ZaGFIUjBjRG92TDJObGNuUnpMbUZ3Y0d4bExtTnZiUzkzZDJSeVp6WXVaR1Z5TURFR0NDc0dBUVVGQnpBQmhpVm9kSFJ3T2k4dmIyTnpjQzVoY0hCc1pTNWpiMjB2YjJOemNEQXpMWGQzWkhKbk5qQXlNSUlCSGdZRFZSMGdCSUlCRlRDQ0FSRXdnZ0VOQmdvcWhraUc5Mk5rQlFZQk1JSCtNSUhEQmdnckJnRUZCUWNDQWpDQnRneUJzMUpsYkdsaGJtTmxJRzl1SUhSb2FYTWdZMlZ5ZEdsbWFXTmhkR1VnWW5rZ1lXNTVJSEJoY25SNUlHRnpjM1Z0WlhNZ1lXTmpaWEIwWVc1alpTQnZaaUIwYUdVZ2RHaGxiaUJoY0hCc2FXTmhZbXhsSUhOMFlXNWtZWEprSUhSbGNtMXpJR0Z1WkNCamIyNWthWFJwYjI1eklHOW1JSFZ6WlN3Z1kyVnlkR2xtYVdOaGRHVWdjRzlzYVdONUlHRnVaQ0JqWlhKMGFXWnBZMkYwYVc5dUlIQnlZV04wYVdObElITjBZWFJsYldWdWRITXVNRFlHQ0NzR0FRVUZCd0lCRmlwb2RIUndPaTh2ZDNkM0xtRndjR3hsTG1OdmJTOWpaWEowYVdacFkyRjBaV0YxZEdodmNtbDBlUzh3SFFZRFZSME9CQllFRkNPQ21NQnEvLzFMNWltdlZtcVgxb0NZZXFyTU1BNEdBMVVkRHdFQi93UUVBd0lIZ0RBUUJnb3Foa2lHOTJOa0Jnc0JCQUlGQURBS0JnZ3Foa2pPUFFRREF3Tm9BREJsQWpFQWw0SkI5R0pIaXhQMm51aWJ5VTFrM3dyaTVwc0dJeFBNRTA1c0ZLcTdoUXV6dmJleUJ1ODJGb3p6eG1ienBvZ29BakJMU0ZsMGRaV0lZbDJlalBWK0RpNWZCbktQdThteW1CUXRvRS9IMmJFUzBxQXM4Yk51ZVUzQ0JqamgxbHduRHNJPSIsIk1JSURGakNDQXB5Z0F3SUJBZ0lVSXNHaFJ3cDBjMm52VTRZU3ljYWZQVGp6Yk5jd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NakV3TXpFM01qQXpOekV3V2hjTk16WXdNekU1TURBd01EQXdXakIxTVVRd1FnWURWUVFERER0QmNIQnNaU0JYYjNKc1pIZHBaR1VnUkdWMlpXeHZjR1Z5SUZKbGJHRjBhVzl1Y3lCRFpYSjBhV1pwWTJGMGFXOXVJRUYxZEdodmNtbDBlVEVMTUFrR0ExVUVDd3dDUnpZeEV6QVJCZ05WQkFvTUNrRndjR3hsSUVsdVl5NHhDekFKQmdOVkJBWVRBbFZUTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVic1FLQzk0UHJsV21aWG5YZ3R4emRWSkw4VDBTR1luZ0RSR3BuZ24zTjZQVDhKTUViN0ZEaTRiQm1QaENuWjMvc3E2UEYvY0djS1hXc0w1dk90ZVJoeUo0NXgzQVNQN2NPQithYW85MGZjcHhTdi9FWkZibmlBYk5nWkdoSWhwSW80SDZNSUgzTUJJR0ExVWRFd0VCL3dRSU1BWUJBZjhDQVFBd0h3WURWUjBqQkJnd0ZvQVV1N0Rlb1ZnemlKcWtpcG5ldnIzcnI5ckxKS3N3UmdZSUt3WUJCUVVIQVFFRU9qQTRNRFlHQ0NzR0FRVUZCekFCaGlwb2RIUndPaTh2YjJOemNDNWhjSEJzWlM1amIyMHZiMk56Y0RBekxXRndjR3hsY205dmRHTmhaek13TndZRFZSMGZCREF3TGpBc29DcWdLSVltYUhSMGNEb3ZMMk55YkM1aGNIQnNaUzVqYjIwdllYQndiR1Z5YjI5MFkyRm5NeTVqY213d0hRWURWUjBPQkJZRUZEOHZsQ05SMDFESm1pZzk3YkI4NWMrbGtHS1pNQTRHQTFVZER3RUIvd1FFQXdJQkJqQVFCZ29xaGtpRzkyTmtCZ0lCQkFJRkFEQUtCZ2dxaGtqT1BRUURBd05vQURCbEFqQkFYaFNxNUl5S29nTUNQdHc0OTBCYUI2NzdDYUVHSlh1ZlFCL0VxWkdkNkNTamlDdE9udU1UYlhWWG14eGN4ZmtDTVFEVFNQeGFyWlh2TnJreFUzVGtVTUkzM3l6dkZWVlJUNHd4V0pDOTk0T3NkY1o0K1JHTnNZRHlSNWdtZHIwbkRHZz0iLCJNSUlDUXpDQ0FjbWdBd0lCQWdJSUxjWDhpTkxGUzVVd0NnWUlLb1pJemowRUF3TXdaekViTUJrR0ExVUVBd3dTUVhCd2JHVWdVbTl2ZENCRFFTQXRJRWN6TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd0hoY05NVFF3TkRNd01UZ3hPVEEyV2hjTk16a3dORE13TVRneE9UQTJXakJuTVJzd0dRWURWUVFEREJKQmNIQnNaU0JTYjI5MElFTkJJQzBnUnpNeEpqQWtCZ05WQkFzTUhVRndjR3hsSUVObGNuUnBabWxqWVhScGIyNGdRWFYwYUc5eWFYUjVNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVFzd0NRWURWUVFHRXdKVlV6QjJNQkFHQnlxR1NNNDlBZ0VHQlN1QkJBQWlBMklBQkpqcEx6MUFjcVR0a3lKeWdSTWMzUkNWOGNXalRuSGNGQmJaRHVXbUJTcDNaSHRmVGpqVHV4eEV0WC8xSDdZeVlsM0o2WVJiVHpCUEVWb0EvVmhZREtYMUR5eE5CMGNUZGRxWGw1ZHZNVnp0SzUxN0lEdll1VlRaWHBta09sRUtNYU5DTUVBd0hRWURWUjBPQkJZRUZMdXczcUZZTTRpYXBJcVozcjY5NjYvYXl5U3JNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdEZ1lEVlIwUEFRSC9CQVFEQWdFR01Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01RQ0Q2Y0hFRmw0YVhUUVkyZTN2OUd3T0FFWkx1Tit5UmhIRkQvM21lb3locG12T3dnUFVuUFdUeG5TNGF0K3FJeFVDTUcxbWloREsxQTNVVDgyTlF6NjBpbU9sTTI3amJkb1h0MlFmeUZNbStZaGlkRGtMRjF2TFVhZ002QmdENTZLeUtBPT0iXX0.eyJub3RpZmljYXRpb25UeXBlIjoiU1VCU0NSSUJFRCIsInN1YnR5cGUiOiJSRVNVQlNDUklCRSIsIm5vdGlmaWNhdGlvblVVSUQiOiIxOWJlYzIxYy1hNzdlLTQ3MDktOTEyNy0wNzJiZjhkZDY5OWYiLCJkYXRhIjp7ImJ1bmRsZUlkIjoiY29tLnNvLmJydW5jaCIsImJ1bmRsZVZlcnNpb24iOiI1NCIsImVudmlyb25tZW50IjoiU2FuZGJveCIsInNpZ25lZFRyYW5zYWN0aW9uSW5mbyI6ImV5SmhiR2NpT2lKRlV6STFOaUlzSW5nMVl5STZXeUpOU1VsRlRVUkRRMEUzWVdkQmQwbENRV2RKVVdGUWIxQnNaSFp3VTI5RlNEQnNRbkpxUkZCMk9XcEJTMEpuWjNGb2EycFBVRkZSUkVGNlFqRk5WVkYzVVdkWlJGWlJVVVJFUkhSQ1kwaENjMXBUUWxoaU0wcHpXa2hrY0ZwSFZXZFNSMVl5V2xkNGRtTkhWbmxKUmtwc1lrZEdNR0ZYT1hWamVVSkVXbGhLTUdGWFduQlpNa1l3WVZjNWRVbEZSakZrUjJoMlkyMXNNR1ZVUlV4TlFXdEhRVEZWUlVOM2QwTlNlbGw0UlhwQlVrSm5UbFpDUVc5TlEydEdkMk5IZUd4SlJXeDFXWGswZUVONlFVcENaMDVXUWtGWlZFRnNWbFJOUWpSWVJGUkplRTFFWjNsT1ZFRjVUbFJCZWs1R2IxaEVWRWw2VFVScmVVNUVRWGxPVkVGNlRURnZkMmRhU1hoUlJFRXJRbWRPVmtKQlRVMU9NVUo1WWpKUloxSlZUa1JKUlRGb1dYbENRbU5JUVdkVk0xSjJZMjFWWjFsWE5XdEpSMnhWWkZjMWJHTjVRbFJrUnpsNVdsTkNVMXBYVG14aFdFSXdTVVpPY0ZveU5YQmliV040VEVSQmNVSm5UbFpDUVhOTlNUQkdkMk5IZUd4SlJtUjJZMjE0YTJReWJHdGFVMEpGV2xoYWJHSkhPWGRhV0VsblZXMVdjMWxZVW5CaU1qVjZUVkpOZDBWUldVUldVVkZMUkVGd1FtTklRbk5hVTBKS1ltMU5kVTFSYzNkRFVWbEVWbEZSUjBWM1NsWlZla0phVFVKTlIwSjVjVWRUVFRRNVFXZEZSME5EY1VkVFRUUTVRWGRGU0VFd1NVRkNUMjlVWTJGUVkzQmxhWEJPVERsbFVUQTJkRU4xTjNCVlkzZGtRMWhrVGpoMlIzRmhWV3BrTlRoYU9IUk1lR2xWUXpCa1FtVkJLMlYxVFZsbloyZ3hMelZwUVdzclJrMTRWVVp0UVRKaE1YSTBZVU5hT0ZOcVoyZEpTVTFKU1VOQ1JFRk5RbWRPVmtoU1RVSkJaamhGUVdwQlFVMUNPRWRCTVZWa1NYZFJXVTFDWVVGR1JEaDJiRU5PVWpBeFJFcHRhV2M1TjJKQ09EVmpLMnhyUjB0YVRVaEJSME5EYzBkQlVWVkdRbmRGUWtKSFVYZFpha0YwUW1kbmNrSm5SVVpDVVdOM1FXOVphR0ZJVWpCalJHOTJUREpPYkdOdVVucE1iVVozWTBkNGJFeHRUblppVXprelpESlNlVnA2V1hWYVIxWjVUVVJGUjBORGMwZEJVVlZHUW5wQlFtaHBWbTlrU0ZKM1QyazRkbUl5VG5walF6Vm9ZMGhDYzFwVE5XcGlNakIyWWpKT2VtTkVRWHBNV0dReldraEtiazVxUVhsTlNVbENTR2RaUkZaU01HZENTVWxDUmxSRFEwRlNSWGRuWjBWT1FtZHZjV2hyYVVjNU1rNXJRbEZaUWsxSlNDdE5TVWhFUW1kbmNrSm5SVVpDVVdORFFXcERRblJuZVVKek1VcHNZa2RzYUdKdFRteEpSemwxU1VoU2IyRllUV2RaTWxaNVpFZHNiV0ZYVG1oa1IxVm5XVzVyWjFsWE5UVkpTRUpvWTI1U05VbEhSbnBqTTFaMFdsaE5aMWxYVG1wYVdFSXdXVmMxYWxwVFFuWmFhVUl3WVVkVloyUkhhR3hpYVVKb1kwaENjMkZYVG1oWmJYaHNTVWhPTUZsWE5XdFpXRXByU1VoU2JHTnRNWHBKUjBaMVdrTkNhbUl5Tld0aFdGSndZakkxZWtsSE9XMUpTRlo2V2xOM1oxa3lWbmxrUjJ4dFlWZE9hR1JIVldkalJ6bHpZVmRPTlVsSFJuVmFRMEpxV2xoS01HRlhXbkJaTWtZd1lWYzVkVWxJUW5sWlYwNHdZVmRPYkVsSVRqQlpXRkpzWWxkV2RXUklUWFZOUkZsSFEwTnpSMEZSVlVaQ2QwbENSbWx3YjJSSVVuZFBhVGgyWkROa00weHRSbmRqUjNoc1RHMU9kbUpUT1dwYVdFb3dZVmRhY0ZreVJqQmFWMFl4WkVkb2RtTnRiREJsVXpoM1NGRlpSRlpTTUU5Q1FsbEZSa05QUTIxTlFuRXZMekZNTldsdGRsWnRjVmd4YjBOWlpYRnlUVTFCTkVkQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlVVSm5iM0ZvYTJsSE9USk9hMEpuYzBKQ1FVbEdRVVJCUzBKblozRm9hMnBQVUZGUlJFRjNUbTlCUkVKc1FXcEZRV3cwU2tJNVIwcElhWGhRTW01MWFXSjVWVEZyTTNkeWFUVndjMGRKZUZCTlJUQTFjMFpMY1Rkb1VYVjZkbUpsZVVKMU9ESkdiM3A2ZUcxaWVuQnZaMjlCYWtKTVUwWnNNR1JhVjBsWmJESmxhbEJXSzBScE5XWkNia3RRZFRodGVXMUNVWFJ2UlM5SU1tSkZVekJ4UVhNNFlrNTFaVlV6UTBKcWFtZ3hiSGR1UkhOSlBTSXNJazFKU1VSR2FrTkRRWEI1WjBGM1NVSkJaMGxWU1hOSGFGSjNjREJqTW01MlZUUlpVM2xqWVdaUVZHcDZZazVqZDBObldVbExiMXBKZW1vd1JVRjNUWGRhZWtWaVRVSnJSMEV4VlVWQmQzZFRVVmhDZDJKSFZXZFZiVGwyWkVOQ1JGRlRRWFJKUldONlRWTlpkMHBCV1VSV1VWRk1SRUl4UW1OSVFuTmFVMEpFV2xoS01HRlhXbkJaTWtZd1lWYzVkVWxGUmpGa1IyaDJZMjFzTUdWVVJWUk5Ra1ZIUVRGVlJVTm5kMHRSV0VKM1lrZFZaMU5YTldwTWFrVk1UVUZyUjBFeFZVVkNhRTFEVmxaTmQwaG9ZMDVOYWtWM1RYcEZNMDFxUVhwT2VrVjNWMmhqVGsxNldYZE5la1UxVFVSQmQwMUVRWGRYYWtJeFRWVlJkMUZuV1VSV1VWRkVSRVIwUW1OSVFuTmFVMEpZWWpOS2MxcElaSEJhUjFWblVrZFdNbHBYZUhaalIxWjVTVVpLYkdKSFJqQmhWemwxWTNsQ1JGcFlTakJoVjFwd1dUSkdNR0ZYT1hWSlJVWXhaRWRvZG1OdGJEQmxWRVZNVFVGclIwRXhWVVZEZDNkRFVucFplRVY2UVZKQ1owNVdRa0Z2VFVOclJuZGpSM2hzU1VWc2RWbDVOSGhEZWtGS1FtZE9Wa0pCV1ZSQmJGWlVUVWhaZDBWQldVaExiMXBKZW1vd1EwRlJXVVpMTkVWRlFVTkpSRmxuUVVWaWMxRkxRemswVUhKc1YyMWFXRzVZWjNSNGVtUldTa3c0VkRCVFIxbHVaMFJTUjNCdVoyNHpUalpRVkRoS1RVVmlOMFpFYVRSaVFtMVFhRU51V2pNdmMzRTJVRVl2WTBkalMxaFhjMHcxZGs5MFpWSm9lVW8wTlhnelFWTlFOMk5QUWl0aFlXODVNR1pqY0hoVGRpOUZXa1ppYm1sQllrNW5Xa2RvU1dod1NXODBTRFpOU1VnelRVSkpSMEV4VldSRmQwVkNMM2RSU1UxQldVSkJaamhEUVZGQmQwaDNXVVJXVWpCcVFrSm5kMFp2UVZWMU4wUmxiMVpuZW1sS2NXdHBjRzVsZG5JemNuSTVja3hLUzNOM1VtZFpTVXQzV1VKQ1VWVklRVkZGUlU5cVFUUk5SRmxIUTBOelIwRlJWVVpDZWtGQ2FHbHdiMlJJVW5kUGFUaDJZakpPZW1ORE5XaGpTRUp6V2xNMWFtSXlNSFppTWs1NlkwUkJla3hYUm5kalIzaHNZMjA1ZG1SSFRtaGFlazEzVG5kWlJGWlNNR1pDUkVGM1RHcEJjMjlEY1dkTFNWbHRZVWhTTUdORWIzWk1NazU1WWtNMWFHTklRbk5hVXpWcVlqSXdkbGxZUW5kaVIxWjVZakk1TUZreVJtNU5lVFZxWTIxM2QwaFJXVVJXVWpCUFFrSlpSVVpFT0hac1EwNVNNREZFU20xcFp6azNZa0k0TldNcmJHdEhTMXBOUVRSSFFURlZaRVIzUlVJdmQxRkZRWGRKUWtKcVFWRkNaMjl4YUd0cFJ6a3lUbXRDWjBsQ1FrRkpSa0ZFUVV0Q1oyZHhhR3RxVDFCUlVVUkJkMDV2UVVSQ2JFRnFRa0ZZYUZOeE5VbDVTMjluVFVOUWRIYzBPVEJDWVVJMk56ZERZVVZIU2xoMVpsRkNMMFZ4V2tka05rTlRhbWxEZEU5dWRVMVVZbGhXV0cxNGVHTjRabXREVFZGRVZGTlFlR0Z5V2xoMlRuSnJlRlV6Vkd0VlRVa3pNM2w2ZGtaV1ZsSlVOSGQ0VjBwRE9UazBUM05rWTFvMEsxSkhUbk5aUkhsU05XZHRaSEl3YmtSSFp6MGlMQ0pOU1VsRFVYcERRMEZqYldkQmQwbENRV2RKU1V4aldEaHBUa3hHVXpWVmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhkYWVrVmlUVUpyUjBFeFZVVkJkM2RUVVZoQ2QySkhWV2RWYlRsMlpFTkNSRkZUUVhSSlJXTjZUVk5aZDBwQldVUldVVkZNUkVJeFFtTklRbk5hVTBKRVdsaEtNR0ZYV25CWk1rWXdZVmM1ZFVsRlJqRmtSMmgyWTIxc01HVlVSVlJOUWtWSFFURlZSVU5uZDB0UldFSjNZa2RWWjFOWE5XcE1ha1ZNVFVGclIwRXhWVVZDYUUxRFZsWk5kMGhvWTA1TlZGRjNUa1JOZDAxVVozaFBWRUV5VjJoalRrMTZhM2RPUkUxM1RWUm5lRTlVUVRKWGFrSnVUVkp6ZDBkUldVUldVVkZFUkVKS1FtTklRbk5hVTBKVFlqSTVNRWxGVGtKSlF6Qm5VbnBOZUVwcVFXdENaMDVXUWtGelRVaFZSbmRqUjNoc1NVVk9iR051VW5CYWJXeHFXVmhTY0dJeU5HZFJXRll3WVVjNWVXRllValZOVWsxM1JWRlpSRlpSVVV0RVFYQkNZMGhDYzFwVFFrcGliVTExVFZGemQwTlJXVVJXVVZGSFJYZEtWbFY2UWpKTlFrRkhRbmx4UjFOTk5EbEJaMFZIUWxOMVFrSkJRV2xCTWtsQlFrcHFjRXg2TVVGamNWUjBhM2xLZVdkU1RXTXpVa05XT0dOWGFsUnVTR05HUW1KYVJIVlhiVUpUY0ROYVNIUm1WR3BxVkhWNGVFVjBXQzh4U0RkWmVWbHNNMG8yV1ZKaVZIcENVRVZXYjBFdlZtaFpSRXRZTVVSNWVFNUNNR05VWkdSeFdHdzFaSFpOVm5wMFN6VXhOMGxFZGxsMVZsUmFXSEJ0YTA5c1JVdE5ZVTVEVFVWQmQwaFJXVVJXVWpCUFFrSlpSVVpNZFhjemNVWlpUVFJwWVhCSmNWb3pjalk1TmpZdllYbDVVM0pOUVRoSFFURlZaRVYzUlVJdmQxRkdUVUZOUWtGbU9IZEVaMWxFVmxJd1VFRlJTQzlDUVZGRVFXZEZSMDFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMVJRMFEyWTBoRlJtdzBZVmhVVVZreVpUTjJPVWQzVDBGRldreDFUaXQ1VW1oSVJrUXZNMjFsYjNsb2NHMTJUM2RuVUZWdVVGZFVlRzVUTkdGMEszRkplRlZEVFVjeGJXbG9SRXN4UVROVlZEZ3lUbEY2TmpCcGJVOXNUVEkzYW1Ka2IxaDBNbEZtZVVaTmJTdFphR2xrUkd0TVJqRjJURlZoWjAwMlFtZEVOVFpMZVV0QlBUMGlYWDAuZXlKMGNtRnVjMkZqZEdsdmJrbGtJam9pTWpBd01EQXdNREEyTURFMk9EQXhOQ0lzSW05eWFXZHBibUZzVkhKaGJuTmhZM1JwYjI1SlpDSTZJakl3TURBd01EQXdNakUxTlRjNU5EWWlMQ0ozWldKUGNtUmxja3hwYm1WSmRHVnRTV1FpT2lJeU1EQXdNREF3TURBeE5qRTNOelF5SWl3aVluVnVaR3hsU1dRaU9pSmpiMjB1YzI4dVluSjFibU5vSWl3aWNISnZaSFZqZEVsa0lqb2lZMjl0TG1KeWRXNWphQzV6Ynk1emRXSXlPVGt1Y21GeGRXVnNiWE50YVhSb0lpd2ljM1ZpYzJOeWFYQjBhVzl1UjNKdmRYQkpaR1Z1ZEdsbWFXVnlJam9pTWpBNU16a3pNVElpTENKd2RYSmphR0Z6WlVSaGRHVWlPakUyTlRNd09ESTVPRFV3TURBc0ltOXlhV2RwYm1Gc1VIVnlZMmhoYzJWRVlYUmxJam94TmpRNE5qQTVOVGsyTURBd0xDSmxlSEJwY21WelJHRjBaU0k2TVRZMU16QTRNekUyTlRBd01Dd2ljWFZoYm5ScGRIa2lPakVzSW5SNWNHVWlPaUpCZFhSdkxWSmxibVYzWVdKc1pTQlRkV0p6WTNKcGNIUnBiMjRpTENKcGJrRndjRTkzYm1WeWMyaHBjRlI1Y0dVaU9pSlFWVkpEU0VGVFJVUWlMQ0p6YVdkdVpXUkVZWFJsSWpveE5qVXpNRGd5T1RrME5EazFMQ0p2Wm1abGNsUjVjR1VpT2pFc0ltVnVkbWx5YjI1dFpXNTBJam9pVTJGdVpHSnZlQ0o5LnNxVk9KMDYzN2ZIaDhzZWZEdEIzZkktU1Boa1M2blQ1SXZjZE1BckJjdjNydzRUZXRrVVZIeE41QzZ3NTExZldPOHRzQVNwMVhod3RaMXMtc1VDQmdBIiwic2lnbmVkUmVuZXdhbEluZm8iOiJleUpoYkdjaU9pSkZVekkxTmlJc0luZzFZeUk2V3lKTlNVbEZUVVJEUTBFM1lXZEJkMGxDUVdkSlVXRlFiMUJzWkhad1UyOUZTREJzUW5KcVJGQjJPV3BCUzBKblozRm9hMnBQVUZGUlJFRjZRakZOVlZGM1VXZFpSRlpSVVVSRVJIUkNZMGhDYzFwVFFsaGlNMHB6V2toa2NGcEhWV2RTUjFZeVdsZDRkbU5IVm5sSlJrcHNZa2RHTUdGWE9YVmplVUpFV2xoS01HRlhXbkJaTWtZd1lWYzVkVWxGUmpGa1IyaDJZMjFzTUdWVVJVeE5RV3RIUVRGVlJVTjNkME5TZWxsNFJYcEJVa0puVGxaQ1FXOU5RMnRHZDJOSGVHeEpSV3gxV1hrMGVFTjZRVXBDWjA1V1FrRlpWRUZzVmxSTlFqUllSRlJKZUUxRVozbE9WRUY1VGxSQmVrNUdiMWhFVkVsNlRVUnJlVTVFUVhsT1ZFRjZUVEZ2ZDJkYVNYaFJSRUVyUW1kT1ZrSkJUVTFPTVVKNVlqSlJaMUpWVGtSSlJURm9XWGxDUW1OSVFXZFZNMUoyWTIxVloxbFhOV3RKUjJ4VlpGYzFiR041UWxSa1J6bDVXbE5DVTFwWFRteGhXRUl3U1VaT2NGb3lOWEJpYldONFRFUkJjVUpuVGxaQ1FYTk5TVEJHZDJOSGVHeEpSbVIyWTIxNGEyUXliR3RhVTBKRldsaGFiR0pIT1hkYVdFbG5WVzFXYzFsWVVuQmlNalY2VFZKTmQwVlJXVVJXVVZGTFJFRndRbU5JUW5OYVUwSktZbTFOZFUxUmMzZERVVmxFVmxGUlIwVjNTbFpWZWtKYVRVSk5SMEo1Y1VkVFRUUTVRV2RGUjBORGNVZFRUVFE1UVhkRlNFRXdTVUZDVDI5VVkyRlFZM0JsYVhCT1REbGxVVEEyZEVOMU4zQlZZM2RrUTFoa1RqaDJSM0ZoVldwa05UaGFPSFJNZUdsVlF6QmtRbVZCSzJWMVRWbG5aMmd4THpWcFFXc3JSazE0VlVadFFUSmhNWEkwWVVOYU9GTnFaMmRKU1UxSlNVTkNSRUZOUW1kT1ZraFNUVUpCWmpoRlFXcEJRVTFDT0VkQk1WVmtTWGRSV1UxQ1lVRkdSRGgyYkVOT1VqQXhSRXB0YVdjNU4ySkNPRFZqSzJ4clIwdGFUVWhCUjBORGMwZEJVVlZHUW5kRlFrSkhVWGRaYWtGMFFtZG5ja0puUlVaQ1VXTjNRVzlaYUdGSVVqQmpSRzkyVERKT2JHTnVVbnBNYlVaM1kwZDRiRXh0VG5aaVV6a3paREpTZVZwNldYVmFSMVo1VFVSRlIwTkRjMGRCVVZWR1FucEJRbWhwVm05a1NGSjNUMms0ZG1JeVRucGpRelZvWTBoQ2MxcFROV3BpTWpCMllqSk9lbU5FUVhwTVdHUXpXa2hLYms1cVFYbE5TVWxDU0dkWlJGWlNNR2RDU1VsQ1JsUkRRMEZTUlhkblowVk9RbWR2Y1docmFVYzVNazVyUWxGWlFrMUpTQ3ROU1VoRVFtZG5ja0puUlVaQ1VXTkRRV3BEUW5SbmVVSnpNVXBzWWtkc2FHSnRUbXhKUnpsMVNVaFNiMkZZVFdkWk1sWjVaRWRzYldGWFRtaGtSMVZuV1c1cloxbFhOVFZKU0VKb1kyNVNOVWxIUm5wak0xWjBXbGhOWjFsWFRtcGFXRUl3V1ZjMWFscFRRblphYVVJd1lVZFZaMlJIYUd4aWFVSm9ZMGhDYzJGWFRtaFpiWGhzU1VoT01GbFhOV3RaV0VwclNVaFNiR050TVhwSlIwWjFXa05DYW1JeU5XdGhXRkp3WWpJMWVrbEhPVzFKU0ZaNldsTjNaMWt5Vm5sa1IyeHRZVmRPYUdSSFZXZGpSemx6WVZkT05VbEhSblZhUTBKcVdsaEtNR0ZYV25CWk1rWXdZVmM1ZFVsSVFubFpWMDR3WVZkT2JFbElUakJaV0ZKc1lsZFdkV1JJVFhWTlJGbEhRME56UjBGUlZVWkNkMGxDUm1sd2IyUklVbmRQYVRoMlpETmtNMHh0Um5kalIzaHNURzFPZG1KVE9XcGFXRW93WVZkYWNGa3lSakJhVjBZeFpFZG9kbU50YkRCbFV6aDNTRkZaUkZaU01FOUNRbGxGUmtOUFEyMU5RbkV2THpGTU5XbHRkbFp0Y1ZneGIwTlpaWEZ5VFUxQk5FZEJNVlZrUkhkRlFpOTNVVVZCZDBsSVowUkJVVUpuYjNGb2EybEhPVEpPYTBKbmMwSkNRVWxHUVVSQlMwSm5aM0ZvYTJwUFVGRlJSRUYzVG05QlJFSnNRV3BGUVd3MFNrSTVSMHBJYVhoUU1tNTFhV0o1VlRGck0zZHlhVFZ3YzBkSmVGQk5SVEExYzBaTGNUZG9VWFY2ZG1KbGVVSjFPREpHYjNwNmVHMWllbkJ2WjI5QmFrSk1VMFpzTUdSYVYwbFpiREpsYWxCV0swUnBOV1pDYmt0UWRUaHRlVzFDVVhSdlJTOUlNbUpGVXpCeFFYTTRZazUxWlZVelEwSnFhbWd4YkhkdVJITkpQU0lzSWsxSlNVUkdha05EUVhCNVowRjNTVUpCWjBsVlNYTkhhRkozY0RCak1tNTJWVFJaVTNsallXWlFWR3A2WWs1amQwTm5XVWxMYjFwSmVtb3dSVUYzVFhkYWVrVmlUVUpyUjBFeFZVVkJkM2RUVVZoQ2QySkhWV2RWYlRsMlpFTkNSRkZUUVhSSlJXTjZUVk5aZDBwQldVUldVVkZNUkVJeFFtTklRbk5hVTBKRVdsaEtNR0ZYV25CWk1rWXdZVmM1ZFVsRlJqRmtSMmgyWTIxc01HVlVSVlJOUWtWSFFURlZSVU5uZDB0UldFSjNZa2RWWjFOWE5XcE1ha1ZNVFVGclIwRXhWVVZDYUUxRFZsWk5kMGhvWTA1TmFrVjNUWHBGTTAxcVFYcE9la1YzVjJoalRrMTZXWGROZWtVMVRVUkJkMDFFUVhkWGFrSXhUVlZSZDFGbldVUldVVkZFUkVSMFFtTklRbk5hVTBKWVlqTktjMXBJWkhCYVIxVm5Va2RXTWxwWGVIWmpSMVo1U1VaS2JHSkhSakJoVnpsMVkzbENSRnBZU2pCaFYxcHdXVEpHTUdGWE9YVkpSVVl4WkVkb2RtTnRiREJsVkVWTVRVRnJSMEV4VlVWRGQzZERVbnBaZUVWNlFWSkNaMDVXUWtGdlRVTnJSbmRqUjNoc1NVVnNkVmw1TkhoRGVrRktRbWRPVmtKQldWUkJiRlpVVFVoWmQwVkJXVWhMYjFwSmVtb3dRMEZSV1VaTE5FVkZRVU5KUkZsblFVVmljMUZMUXprMFVISnNWMjFhV0c1WVozUjRlbVJXU2t3NFZEQlRSMWx1WjBSU1IzQnVaMjR6VGpaUVZEaEtUVVZpTjBaRWFUUmlRbTFRYUVOdVdqTXZjM0UyVUVZdlkwZGpTMWhYYzB3MWRrOTBaVkpvZVVvME5YZ3pRVk5RTjJOUFFpdGhZVzg1TUdaamNIaFRkaTlGV2taaWJtbEJZazVuV2tkb1NXaHdTVzgwU0RaTlNVZ3pUVUpKUjBFeFZXUkZkMFZDTDNkUlNVMUJXVUpCWmpoRFFWRkJkMGgzV1VSV1VqQnFRa0puZDBadlFWVjFOMFJsYjFabmVtbEtjV3RwY0c1bGRuSXpjbkk1Y2t4S1MzTjNVbWRaU1V0M1dVSkNVVlZJUVZGRlJVOXFRVFJOUkZsSFEwTnpSMEZSVlVaQ2VrRkNhR2x3YjJSSVVuZFBhVGgyWWpKT2VtTkROV2hqU0VKeldsTTFhbUl5TUhaaU1rNTZZMFJCZWt4WFJuZGpSM2hzWTIwNWRtUkhUbWhhZWsxM1RuZFpSRlpTTUdaQ1JFRjNUR3BCYzI5RGNXZExTVmx0WVVoU01HTkViM1pNTWs1NVlrTTFhR05JUW5OYVV6VnFZakl3ZGxsWVFuZGlSMVo1WWpJNU1Ga3lSbTVOZVRWcVkyMTNkMGhSV1VSV1VqQlBRa0paUlVaRU9IWnNRMDVTTURGRVNtMXBaemszWWtJNE5XTXJiR3RIUzFwTlFUUkhRVEZWWkVSM1JVSXZkMUZGUVhkSlFrSnFRVkZDWjI5eGFHdHBSemt5VG10Q1owbENRa0ZKUmtGRVFVdENaMmR4YUd0cVQxQlJVVVJCZDA1dlFVUkNiRUZxUWtGWWFGTnhOVWw1UzI5blRVTlFkSGMwT1RCQ1lVSTJOemREWVVWSFNsaDFabEZDTDBWeFdrZGtOa05UYW1sRGRFOXVkVTFVWWxoV1dHMTRlR040Wm10RFRWRkVWRk5RZUdGeVdsaDJUbkpyZUZVelZHdFZUVWt6TTNsNmRrWldWbEpVTkhkNFYwcERPVGswVDNOa1kxbzBLMUpIVG5OWlJIbFNOV2R0WkhJd2JrUkhaejBpTENKTlNVbERVWHBEUTBGamJXZEJkMGxDUVdkSlNVeGpXRGhwVGt4R1V6VlZkME5uV1VsTGIxcEplbW93UlVGM1RYZGFla1ZpVFVKclIwRXhWVVZCZDNkVFVWaENkMkpIVldkVmJUbDJaRU5DUkZGVFFYUkpSV042VFZOWmQwcEJXVVJXVVZGTVJFSXhRbU5JUW5OYVUwSkVXbGhLTUdGWFduQlpNa1l3WVZjNWRVbEZSakZrUjJoMlkyMXNNR1ZVUlZSTlFrVkhRVEZWUlVObmQwdFJXRUozWWtkVloxTl2022-05-20T21:43:16.046463081Z hOV3BNYWtWTVRVRnJSMEV4VlVWQ2FFMURWbFpOZDBob1kwNU5WRkYzVGtSTmQwMVVaM2hQVkVFeVYyaGpUazE2YTNkT1JFMTNUVlJuZUU5VVFUSlhha0p1VFZKemQwZFJXVVJXVVZGRVJFSktRbU5JUW5OYVUwSlRZakk1TUVsRlRrSkpRekJuVW5wTmVFcHFRV3RDWjA1V1FrRnpUVWhWUm5kalIzaHNTVVZPYkdOdVVuQmFiV3hxV1ZoU2NHSXlOR2RSV0ZZd1lVYzVlV0ZZVWpWTlVrMTNSVkZaUkZaUlVVdEVRWEJDWTBoQ2MxcFRRa3BpYlUxMVRWRnpkME5SV1VSV1VWRkhSWGRLVmxWNlFqSk5Ra0ZIUW5seFIxTk5ORGxCWjBWSFFsTjFRa0pCUVdsQk1rbEJRa3BxY0V4Nk1VRmpjVlIwYTNsS2VXZFNUV016VWtOV09HTlhhbFJ1U0dOR1FtSmFSSFZYYlVKVGNETmFTSFJtVkdwcVZIVjRlRVYwV0M4eFNEZFplVmxzTTBvMldWSmlWSHBDVUVWV2IwRXZWbWhaUkV0WU1VUjVlRTVDTUdOVVpHUnhXR3cxWkhaTlZucDBTelV4TjBsRWRsbDFWbFJhV0hCdGEwOXNSVXROWVU1RFRVVkJkMGhSV1VSV1VqQlBRa0paUlVaTWRYY3pjVVpaVFRScFlYQkpjVm96Y2pZNU5qWXZZWGw1VTNKTlFUaEhRVEZWWkVWM1JVSXZkMUZHVFVGTlFrRm1PSGRFWjFsRVZsSXdVRUZSU0M5Q1FWRkVRV2RGUjAxQmIwZERRM0ZIVTAwME9VSkJUVVJCTW1kQlRVZFZRMDFSUTBRMlkwaEZSbXcwWVZoVVVWa3laVE4yT1VkM1QwRkZXa3gxVGl0NVVtaElSa1F2TTIxbGIzbG9jRzEyVDNkblVGVnVVRmRVZUc1VE5HRjBLM0ZKZUZWRFRVY3hiV2xvUkVzeFFUTlZWRGd5VGxGNk5qQnBiVTlzVFRJM2FtSmtiMWgwTWxGbWVVWk5iU3RaYUdsa1JHdE1SakYyVEZWaFowMDJRbWRFTlRaTGVVdEJQVDBpWFgwLmV5SnZjbWxuYVc1aGJGUnlZVzV6WVdOMGFXOXVTV1FpT2lJeU1EQXdNREF3TURJeE5UVTNPVFEySWl3aVlYVjBiMUpsYm1WM1VISnZaSFZqZEVsa0lqb2lZMjl0TG1KeWRXNWphQzV6Ynk1emRXSXlPVGt1Y21GeGRXVnNiWE50YVhSb0lpd2ljSEp2WkhWamRFbGtJam9pWTI5dExtSnlkVzVqYUM1emJ5NXpkV0l5T1RrdWNtRnhkV1ZzYlhOdGFYUm9JaXdpWVhWMGIxSmxibVYzVTNSaGRIVnpJam94TENKemFXZHVaV1JFWVhSbElqb3hOalV6TURneU9UazBORGN6TENKbGJuWnBjbTl1YldWdWRDSTZJbE5oYm1SaWIzZ2lmUS5ieU9GbFJYR2t3V1BpdGlkbVZkQ1FMTFNFMTFDakVHWFNrbWNtU1Z2ZUxNTnpORV9TalNyQkRtbFYyZkJ2SFBvS2hmenowWmNuSFZTVVdyUktHVkhmUSJ9LCJ2ZXJzaW9uIjoiMi4wIn0.8yczpW8t4GX_3LiIjPtdL6NTY03h7oYCkHku0M0qonGtFMPE6AmyvAaQQVNIo-ikujHnMfeSM2EukM2nLwHSfA

I was hoping that this library would know how to handle it, but alas. Do you have any ideas what should be done with this payload? Are you seeing the same thing in your projects using this library?

App Store Server Notifications 2.7 adds new field "summary" mutually exclusive with "data"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.