Skip to content

Commit

Permalink
fix: support SF_ and SFDX_ prefixed env vars (#668)
Browse files Browse the repository at this point in the history
* chore: lint fixes

* chore: bump deps

---------

Co-authored-by: Cristian Dominguez <cdominguez@salesforce.com>
  • Loading branch information
shetzel and cristiand391 authored Sep 4, 2024
1 parent 236a0c6 commit c64812e
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 77 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@
},
"dependencies": {
"@oclif/core": "^4.0.18",
"@salesforce/core": "^8.4.0",
"@salesforce/core": "^8.5.4",
"@salesforce/kit": "^3.2.1",
"@salesforce/source-deploy-retrieve": "^12.5.1",
"@salesforce/source-deploy-retrieve": "^12.6.0",
"@salesforce/ts-types": "^2.0.12",
"fast-xml-parser": "^4.4.1",
"graceful-fs": "^4.2.11",
Expand Down
12 changes: 6 additions & 6 deletions src/shared/remoteSourceTrackingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import path from 'node:path';
import fs from 'node:fs';
import { EOL } from 'node:os';
import { retryDecorator, NotRetryableError } from 'ts-retry-promise';
import { Logger, Org, Messages, Lifecycle, SfError, Connection, lockInit } from '@salesforce/core';
import { env, Duration, parseJsonMap } from '@salesforce/kit';
import { envVars as env, Logger, Org, Messages, Lifecycle, SfError, Connection, lockInit } from '@salesforce/core';
import { Duration, parseJsonMap } from '@salesforce/kit';
import { isString } from '@salesforce/ts-types';
import {
ChangeResult,
Expand Down Expand Up @@ -40,7 +40,7 @@ const FILENAME = 'maxRevision.json';
*/
const POLLING_DELAY_MS = 1000;
const CONSECUTIVE_EMPTY_POLLING_RESULT_LIMIT =
(env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT') ?? 120) / Duration.milliseconds(POLLING_DELAY_MS).seconds;
(env.getNumber('SF_SOURCE_MEMBER_POLLING_TIMEOUT') ?? 120) / Duration.milliseconds(POLLING_DELAY_MS).seconds;

/** Options for RemoteSourceTrackingService.getInstance */
export type RemoteSourceTrackingServiceOptions = {
Expand Down Expand Up @@ -237,8 +237,8 @@ export class RemoteSourceTrackingService {
* @param pollingTimeout maximum amount of time in seconds to poll for SourceMembers
*/
public async pollForSourceTracking(expectedMembers: RemoteSyncInput[]): Promise<void> {
if (env.getBoolean('SFDX_DISABLE_SOURCE_MEMBER_POLLING', false)) {
this.logger.warn('Not polling for SourceMembers since SFDX_DISABLE_SOURCE_MEMBER_POLLING = true.');
if (env.getBoolean('SF_DISABLE_SOURCE_MEMBER_POLLING')) {
this.logger.warn('Not polling for SourceMembers since SF_DISABLE_SOURCE_MEMBER_POLLING = true.');
return;
}

Expand Down Expand Up @@ -572,7 +572,7 @@ const readFileContents = async (filePath: string): Promise<Contents | Record<str
export const calculateTimeout =
(logger: PinoLogger) =>
(memberCount: number): Duration => {
const overriddenTimeout = env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', 0);
const overriddenTimeout = env.getNumber('SF_SOURCE_MEMBER_POLLING_TIMEOUT', 0);
if (overriddenTimeout > 0) {
logger.debug(`Overriding SourceMember polling timeout to ${overriddenTimeout}`);
return Duration.seconds(overriddenTimeout);
Expand Down
67 changes: 58 additions & 9 deletions test/unit/remoteSourceTracking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import { writeFile, mkdir, readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { sep, dirname } from 'node:path';
import { MockTestOrgData, instantiateContext, stubContext, restoreContext } from '@salesforce/core/testSetup';
import { Logger, Messages, Org } from '@salesforce/core';
// eslint-disable-next-line no-restricted-imports
import * as kit from '@salesforce/kit';
import { EnvVars, envVars, Logger, Messages, Org } from '@salesforce/core';
import { expect } from 'chai';
import { ComponentStatus } from '@salesforce/source-deploy-retrieve';
import { RemoteSourceTrackingService, calculateTimeout, Contents } from '../../src/shared/remoteSourceTrackingService';
Expand Down Expand Up @@ -42,6 +40,13 @@ const getMemberRevisionEntries = (revision: number, synced = false): { [key: str
return sourceMemberEntries;
};

const reResolveEnvVars = (): void => {
/* eslint-disable @typescript-eslint/no-unsafe-call */
// @ts-ignore to force a re-resolve
envVars.resolve();
/* eslint-enable @typescript-eslint/no-unsafe-call */
};

describe('remoteSourceTrackingService', () => {
const username = 'foo@bar.com';
let orgId: string;
Expand Down Expand Up @@ -408,6 +413,13 @@ describe('remoteSourceTrackingService', () => {
state: ComponentStatus.Changed,
}));

afterEach(() => {
envVars.unset('SFDX_DISABLE_SOURCE_MEMBER_POLLING');
envVars.unset('SF_DISABLE_SOURCE_MEMBER_POLLING');
envVars.unset('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT');
envVars.unset('SF_SOURCE_MEMBER_POLLING_TIMEOUT');
});

it('should sync SourceMembers when query results match', async () => {
// @ts-ignore
const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom');
Expand Down Expand Up @@ -469,15 +481,31 @@ describe('remoteSourceTrackingService', () => {
});
});
it('should not poll when SFDX_DISABLE_SOURCE_MEMBER_POLLING=true', async () => {
const getBooleanStub = $$.SANDBOX.stub(kit.env, 'getBoolean').callsFake(() => true);
envVars.setString('SFDX_DISABLE_SOURCE_MEMBER_POLLING', 'true');

reResolveEnvVars();
const getBooleanSpy = $$.SANDBOX.spy(EnvVars.prototype, 'getBoolean');

// @ts-ignore
const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers');

// @ts-ignore
await remoteSourceTrackingService.pollForSourceTracking(memberNames, 2);
expect(trackSpy.called).to.equal(false);
expect(getBooleanSpy.calledOnce).to.equal(true);
});
it('should not poll when SF_DISABLE_SOURCE_MEMBER_POLLING=true', async () => {
envVars.setString('SF_DISABLE_SOURCE_MEMBER_POLLING', 'true');
reResolveEnvVars();
const getBooleanSpy = $$.SANDBOX.spy(EnvVars.prototype, 'getBoolean');

// @ts-ignore
const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers');

// @ts-ignore
await remoteSourceTrackingService.pollForSourceTracking(memberNames, 2);
expect(trackSpy.called).to.equal(false);
expect(getBooleanStub.calledOnce).to.equal(true);
expect(getBooleanSpy.calledOnce).to.equal(true);
});

describe('timeout handling', () => {
Expand Down Expand Up @@ -511,8 +539,26 @@ describe('remoteSourceTrackingService', () => {
}).timeout(10_000);

it('should stop if SFDX_SOURCE_MEMBER_POLLING_TIMEOUT is exceeded', async () => {
envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '3');
reResolveEnvVars();
// @ts-ignore
$$.SANDBOX.stub(kit.env, 'getString').callsFake(() => '3');
const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom').resolves([]);

// @ts-ignore
const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers');

// @ts-ignore
await remoteSourceTrackingService.pollForSourceTracking(memberNames);
expect(trackSpy.called).to.equal(true);

expect(warns.size).to.be.greaterThan(0);
const expectedMsg = 'Polling for 3 SourceMembers timed out after 3 attempts';
expect(Array.from(warns).some((w) => w.includes(expectedMsg))).to.equal(true);
expect(queryStub.called).to.equal(true);
});
it('should stop if SF_SOURCE_MEMBER_POLLING_TIMEOUT is exceeded', async () => {
envVars.setString('SF_SOURCE_MEMBER_POLLING_TIMEOUT', '3');
reResolveEnvVars();
// @ts-ignore
const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom').resolves([]);

Expand Down Expand Up @@ -587,7 +633,8 @@ describe('calculateTimeout', () => {
const logger = new Logger({ useMemoryLogger: true, name: 'test' }).getRawLogger();
const functionUnderTest = calculateTimeout(logger);
afterEach(() => {
delete process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT;
envVars.unset('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT');
envVars.unset('SF_SOURCE_MEMBER_POLLING_TIMEOUT');
});
it('0 members => 5 sec', () => {
expect(functionUnderTest(0).seconds).to.equal(5);
Expand All @@ -596,11 +643,13 @@ describe('calculateTimeout', () => {
expect(functionUnderTest(10_000).seconds).to.equal(505);
});
it('override 60 in env', () => {
process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT = '60';
envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '60');
reResolveEnvVars();
expect(functionUnderTest(10_000).seconds).to.equal(60);
});
it('override 0 in env has no effect', () => {
process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT = '0';
envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '0');
reResolveEnvVars();
expect(functionUnderTest(10_000).seconds).to.equal(505);
});
});
87 changes: 27 additions & 60 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"

"@jsforce/jsforce-node@^3.4.0":
"@jsforce/jsforce-node@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.4.1.tgz#36f5cba775b395eeedba676a78eafe447c3f4b28"
integrity sha512-PsBKfglH0/8W/Srr4LsxEFsVmjmZjEj/T4XLGpbBoK8yVObwbiMk4VqwA6XwiA6SHqnEqqQbHZxk2rr7dZC+4A==
Expand Down Expand Up @@ -546,13 +546,13 @@
strip-ansi "6.0.1"
ts-retry-promise "^0.8.1"

"@salesforce/core@^8.3.0", "@salesforce/core@^8.4.0":
version "8.4.0"
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.4.0.tgz#d2ddfe07994c42b1e917e581e9cf47ad27b97a93"
integrity sha512-P+n0+Sp+v6voLTShW2E5sdF7gCUxEXJjNcc9Jtto0ZMyQesmQJ6WGpWmAuRoi+BVYc8OPSlEffndaYDAo/u73g==
"@salesforce/core@^8.3.0", "@salesforce/core@^8.5.2", "@salesforce/core@^8.5.4":
version "8.5.4"
resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.5.4.tgz#1cdd669462d2c2859b72135d1138a1b790b1fbcc"
integrity sha512-dO8tzFxq811qNPeKPPO2OA2KPYW5rO0YRinW/+7zmRJW3EtNpe93dsQVGwBSAAYrSbYeBwiKdliNqNTN7tKJ0A==
dependencies:
"@jsforce/jsforce-node" "^3.4.0"
"@salesforce/kit" "^3.1.6"
"@jsforce/jsforce-node" "^3.4.1"
"@salesforce/kit" "^3.2.2"
"@salesforce/schemas" "^1.9.0"
"@salesforce/ts-types" "^2.0.10"
ajv "^8.17.1"
Expand Down Expand Up @@ -607,10 +607,10 @@
typescript "^5.5.4"
wireit "^0.14.5"

"@salesforce/kit@^3.1.6", "@salesforce/kit@^3.2.1":
version "3.2.1"
resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.2.1.tgz#3de2c9ff52710a169fc887716d97c00d26065c56"
integrity sha512-LrZH2F06XPLUTMXC3av6A0VDAJykUqRtYB6tTjAKzwS1gCnp6BEn6VyjZNg0Fg/Kfp6OTrMxiIgbUFsNehEV7A==
"@salesforce/kit@^3.2.1", "@salesforce/kit@^3.2.2":
version "3.2.2"
resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.2.2.tgz#2a0db472116a416cb12b510d546cb35a582d619a"
integrity sha512-Qh+Jx65LKR3BlH+bxNBbvI4+/+/igAJ9x2iEDM3tHb3B2JCEnssPP0lw+K/zWHsdtk+OorBiKpHaC6RrjW+9fw==
dependencies:
"@salesforce/ts-types" "^2.0.12"

Expand All @@ -624,19 +624,20 @@
resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca"
integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA==

"@salesforce/source-deploy-retrieve@^12.5.1":
version "12.5.1"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.5.1.tgz#55e915201b2c9320b9662b2c8500a191c8770ecf"
integrity sha512-jakBWFSIb8oZlUAf0QKHXaeFA/KuTQZwaKZVevdwaiuy43lJHzVVrSRfcNv/kjXxmg0oq5TAI8vUo2CC5Hq04A==
"@salesforce/source-deploy-retrieve@^12.6.0":
version "12.6.2"
resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.6.2.tgz#eb9ab120621c80a404b9ec45a2b102f3f2befbff"
integrity sha512-ucEt/CyzL4ovMc2cYREk4meQzKe6/FlY/D09yLmOQ118Oec680ehEhJ1kGRE/I7HTzfgQP3Fy2GzhQX1bOYC5Q==
dependencies:
"@salesforce/core" "^8.4.0"
"@salesforce/kit" "^3.2.1"
"@salesforce/core" "^8.5.2"
"@salesforce/kit" "^3.2.2"
"@salesforce/ts-types" "^2.0.12"
fast-levenshtein "^3.0.0"
fast-xml-parser "^4.4.1"
got "^11.8.6"
graceful-fs "^4.2.11"
ignore "^5.3.2"
isbinaryfile "^5.0.2"
jszip "^3.10.1"
mime "2.6.0"
minimatch "^9.0.5"
Expand Down Expand Up @@ -1339,20 +1340,13 @@ brace-expansion@^4.0.0:
dependencies:
balanced-match "^3.0.0"

braces@^3.0.3:
braces@^3.0.3, braces@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
dependencies:
fill-range "^7.1.1"

braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
dependencies:
fill-range "^7.0.1"

browser-stdout@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60"
Expand Down Expand Up @@ -2499,13 +2493,6 @@ filelist@^1.0.4:
dependencies:
minimatch "^5.0.1"

fill-range@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
dependencies:
to-regex-range "^5.0.1"

fill-range@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
Expand Down Expand Up @@ -3307,6 +3294,11 @@ isarray@~1.0.0:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==

isbinaryfile@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.2.tgz#fe6e4dfe2e34e947ffa240c113444876ba393ae0"
integrity sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==

isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
Expand Down Expand Up @@ -5146,16 +5138,7 @@ srcset@^5.0.0:
resolved "https://registry.yarnpkg.com/srcset/-/srcset-5.0.0.tgz#9df6c3961b5b44a02532ce6ae4544832609e2e3f"
integrity sha512-SqEZaAEhe0A6ETEa9O1IhSPC7MdvehZtCnTR0AftXk3QhY2UNgb+NApFOUPZILXk/YTDfFxMTNJOBpzrJsEdIA==

"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
Expand Down Expand Up @@ -5214,14 +5197,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"

strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
Expand Down Expand Up @@ -5721,7 +5697,7 @@ workerpool@^6.5.1:
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544"
integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==

"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
Expand All @@ -5739,15 +5715,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"

wrap-ansi@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
Expand Down

0 comments on commit c64812e

Please sign in to comment.