Merge pull request #484 from ylei-tsubame/rebuild-web

Web UI: patch fence manager, manifest creation
main
Digimer 1 year ago committed by GitHub
commit 5210700247
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      striker-ui-api/out/index.js
  2. 15
      striker-ui-api/src/lib/request_handlers/fence/createFence.ts
  3. 33
      striker-ui-api/src/lib/request_handlers/fence/getFence.ts
  4. 180
      striker-ui-api/src/lib/request_handlers/manifest/buildManifest.ts
  5. 6
      striker-ui-api/src/lib/request_handlers/manifest/createManifest.ts
  6. 6
      striker-ui-api/src/lib/request_handlers/manifest/updateManifest.ts
  7. 2
      striker-ui-api/src/lib/sanitizeSQLParam.ts
  8. 10
      striker-ui-api/src/lib/shell.ts
  9. 6
      striker-ui/components/Bars/StackBar.tsx
  10. 1
      striker-ui/out/_next/static/UY89Wl2fvgEKnUqzsKV5-/_buildManifest.js
  11. 0
      striker-ui/out/_next/static/UY89Wl2fvgEKnUqzsKV5-/_middlewareManifest.js
  12. 0
      striker-ui/out/_next/static/UY89Wl2fvgEKnUqzsKV5-/_ssgManifest.js
  13. 2
      striker-ui/out/_next/static/chunks/336-6e600f08d9387d72.js
  14. 154
      striker-ui/out/_next/static/chunks/382-f51344f6f9208507.js
  15. 154
      striker-ui/out/_next/static/chunks/412-ae4bab5809f6a209.js
  16. 1
      striker-ui/out/_next/static/chunks/519-4b7761e884c88eb9.js
  17. 1
      striker-ui/out/_next/static/chunks/586-4e70511cf6d7632f.js
  18. 1
      striker-ui/out/_next/static/chunks/62-2c80eba24b792af8.js
  19. 1
      striker-ui/out/_next/static/chunks/62-532ed713980da8db.js
  20. 2
      striker-ui/out/_next/static/chunks/825-a143aba6cb430f0f.js
  21. 2
      striker-ui/out/_next/static/chunks/900-af716a39aed22219.js
  22. 1
      striker-ui/out/_next/static/chunks/pages/anvil-53b02ffa883f4c5a.js
  23. 1
      striker-ui/out/_next/static/chunks/pages/anvil-5ff2efa937105177.js
  24. 2
      striker-ui/out/_next/static/chunks/pages/config-7be24d332b231569.js
  25. 1
      striker-ui/out/_next/static/chunks/pages/file-manager-0697bf1cd793df6d.js
  26. 1
      striker-ui/out/_next/static/chunks/pages/file-manager-1ae01a78e266275a.js
  27. 1
      striker-ui/out/_next/static/chunks/pages/index-0771f2825962ebc3.js
  28. 1
      striker-ui/out/_next/static/chunks/pages/index-6ff72adab3a682db.js
  29. 2
      striker-ui/out/_next/static/chunks/pages/init-7cf62951388d0e3b.js
  30. 1
      striker-ui/out/_next/static/chunks/pages/login-0b2f91a926538f7c.js
  31. 1
      striker-ui/out/_next/static/chunks/pages/login-1b987b077ffc3420.js
  32. 2
      striker-ui/out/_next/static/chunks/pages/manage-element-3ed34f8c3a72590a.js
  33. 2
      striker-ui/out/_next/static/chunks/pages/server-d4d91dcbacc827c4.js
  34. 1
      striker-ui/out/_next/static/tsboOH-aG8W5HRHH4dt2_/_buildManifest.js
  35. 2
      striker-ui/out/anvil.html
  36. 2
      striker-ui/out/config.html
  37. 2
      striker-ui/out/file-manager.html
  38. 2
      striker-ui/out/index.html
  39. 2
      striker-ui/out/init.html
  40. 2
      striker-ui/out/login.html
  41. 2
      striker-ui/out/manage-element.html
  42. 2
      striker-ui/out/server.html

File diff suppressed because one or more lines are too long

@ -7,9 +7,11 @@ import { getFenceSpec, timestamp, write } from '../../accessModule';
import { sanitize } from '../../sanitize';
import { stderr, stdoutVar, uuid } from '../../shell';
const handleNumberType = (v: unknown) => String(sanitize(v, 'number'));
const handleNumberType = (v: unknown) =>
String(sanitize(v, 'number', { modifierType: 'sql' }));
const handleStringType = (v: unknown) => sanitize(v, 'string');
const handleStringType = (v: unknown) =>
sanitize(v, 'string', { modifierType: 'sql' });
const MAP_TO_VAR_TYPE: Record<
AnvilDataFenceParameterType,
@ -46,9 +48,12 @@ export const createFence: RequestHandler<
return response.status(500).send();
}
const agent = sanitize(rAgent, 'string');
const name = sanitize(rName, 'string');
const fenceUuid = sanitize(rUuid, 'string', { fallback: uuid() });
const agent = sanitize(rAgent, 'string', { modifierType: 'sql' });
const name = sanitize(rName, 'string', { modifierType: 'sql' });
const fenceUuid = sanitize(rUuid, 'string', {
fallback: uuid(),
modifierType: 'sql',
});
const { [agent]: agentSpec } = fenceSpec;

@ -20,16 +20,33 @@ export const getFence: RequestHandler = buildGetRequestHandler(
const afterQueryReturn: QueryResultModifierFunction | undefined =
buildQueryResultReducer<{ [fenceUUID: string]: FenceOverview }>(
(previous, [fenceUUID, fenceName, fenceAgent, fenceArgumentString]) => {
const fenceParameters = fenceArgumentString
.split(/\s+/)
.reduce<FenceParameters>((previous, parameterPair) => {
const [parameterId, parameterValue] = parameterPair.split(/=/);
(
previous,
[fenceUUID, fenceName, fenceAgent, fenceParametersString],
) => {
const fenceParametersArray = fenceParametersString.match(
/(?:[^\s'"]+|'[^']*'|"[^"]*")+/g,
);
previous[parameterId] = parameterValue.replace(/['"]/g, '');
if (!fenceParametersArray) return previous;
return previous;
}, {});
const fenceParameters = fenceParametersArray.reduce<FenceParameters>(
(previousParameters, parameterString) => {
const parameterPair = parameterString.split(/=(.*)/, 2);
if (parameterPair.length !== 2) return previousParameters;
const [parameterId, parameterValue] = parameterPair;
previousParameters[parameterId] = parameterValue.replace(
/['"]/g,
'',
);
return previousParameters;
},
{},
);
stdout(
`${fenceAgent}: ${fenceName} (${fenceUUID})\n${JSON.stringify(

@ -2,7 +2,6 @@ import assert from 'assert';
import { RequestHandler } from 'express';
import {
REP_INTEGER,
REP_IPV4,
REP_IPV4_CSV,
REP_PEACEFUL_STRING,
@ -41,168 +40,173 @@ export const buildManifest = async (
stdout('Begin building install manifest.');
const dns = sanitize(rawDns, 'string');
const domain = sanitize(rawDomain, 'string');
const manifestUuid = sanitize(rawManifestUuid, 'string');
const mtu = sanitize(rawMtu, 'number');
const ntp = sanitize(rawNtp, 'string');
const prefix = sanitize(rawPrefix, 'string');
const sequence = sanitize(rawSequence, 'number');
try {
assert(REP_IPV4_CSV.test(dns), `DNS must be an IPv4 CSV; got [${dns}]`);
const domain = sanitize(rawDomain, 'string');
assert(
REP_PEACEFUL_STRING.test(domain),
`Domain must be a peaceful string; got [${domain}]`,
);
const manifestUuid = sanitize(rawManifestUuid, 'string');
assert(
manifestUuid === 'new' || REP_UUID.test(manifestUuid),
`Manifest UUID must be a UUIDv4; got [${manifestUuid}]`,
);
const mtu = sanitize(rawMtu, 'number');
assert(REP_INTEGER.test(String(mtu)), `MTU must be an integer; got [${mtu}]`);
const ntp = sanitize(rawNtp, 'string');
assert(Number.isSafeInteger(mtu), `MTU must be an integer; got [${mtu}]`);
if (ntp) {
assert(REP_IPV4_CSV.test(ntp), `NTP must be an IPv4 CSV; got [${ntp}]`);
}
const prefix = sanitize(rawPrefix, 'string');
assert(
REP_PEACEFUL_STRING.test(prefix),
`Prefix must be a peaceful string; got [${prefix}]`,
);
const sequence = sanitize(rawSequence, 'number');
assert(
REP_INTEGER.test(String(sequence)),
Number.isSafeInteger(sequence),
`Sequence must be an integer; got [${sequence}]`,
);
} catch (error) {
throw new Error(`Failed to assert build manifest input; CAUSE: ${error}`);
}
const { counts: networkCountContainer, networks: networkContainer } =
Object.values(networkList).reduce<{
counts: Record<string, number>;
networks: Record<string, string>;
}>(
(
previous,
{
const netCounts: Record<string, number> = {};
const netConfigs: Record<string, string> = {};
try {
Object.values(networkList).forEach((network) => {
const {
networkGateway: rawGateway,
networkMinIp: rawMinIp,
networkNumber: rawNetworkNumber,
networkSubnetMask: rawSubnetMask,
networkType: rawNetworkType,
},
) => {
} = network;
const gateway = sanitize(rawGateway, 'string');
const minIp = sanitize(rawMinIp, 'string');
const networkNumber = sanitize(rawNetworkNumber, 'number');
const networkType = sanitize(rawNetworkType, 'string');
const subnetMask = sanitize(rawSubnetMask, 'string');
const networkId = `${networkType}${networkNumber}`;
assert(
REP_PEACEFUL_STRING.test(networkType),
`Network type must be a peaceful string; got [${networkType}]`,
);
const networkNumber = sanitize(rawNetworkNumber, 'number');
assert(
REP_INTEGER.test(String(networkNumber)),
Number.isSafeInteger(networkNumber),
`Network number must be an integer; got [${networkNumber}]`,
);
const networkId = `${networkType}${networkNumber}`;
const gateway = sanitize(rawGateway, 'string');
if (networkType === 'ifn') {
assert(
REP_IPV4.test(gateway),
`Gateway of ${networkId} must be an IPv4; got [${gateway}]`,
);
}
const minIp = sanitize(rawMinIp, 'string');
assert(
REP_IPV4.test(minIp),
`Minimum IP of ${networkId} must be an IPv4; got [${minIp}]`,
);
const subnetMask = sanitize(rawSubnetMask, 'string');
assert(
REP_IPV4.test(subnetMask),
`Subnet mask of ${networkId} must be an IPv4; got [${subnetMask}]`,
);
const { counts: countContainer, networks: networkContainer } = previous;
if (networkType === 'ifn') {
assert(
REP_IPV4.test(gateway),
`Gateway of ${networkId} must be an IPv4; got [${gateway}]`,
);
}
const countKey = `${networkType}_count`;
const countValue = countContainer[countKey] ?? 0;
const countValue = netCounts[countKey] ?? 0;
countContainer[countKey] = countValue + 1;
netCounts[countKey] = countValue + 1;
const gatewayKey = `${networkId}_gateway`;
const minIpKey = `${networkId}_network`;
const subnetMaskKey = `${networkId}_subnet`;
networkContainer[gatewayKey] = gateway;
networkContainer[minIpKey] = minIp;
networkContainer[subnetMaskKey] = subnetMask;
netConfigs[gatewayKey] = gateway;
netConfigs[minIpKey] = minIp;
netConfigs[subnetMaskKey] = subnetMask;
});
} catch (error) {
throw new Error(`Failed to build networks for manifest; CAUSE: ${error}`);
}
return previous;
},
{ counts: {}, networks: {} },
);
const hosts: Record<string, string> = {};
const hostContainer = Object.values(hostList).reduce<Record<string, string>>(
(
previous,
{
try {
Object.values(hostList).forEach((host) => {
const {
fences,
hostNumber: rawHostNumber,
hostType: rawHostType,
ipmiIp: rawIpmiIp,
networks,
upses,
},
) => {
} = host;
const hostNumber = sanitize(rawHostNumber, 'number');
const hostType = sanitize(rawHostType, 'string');
const ipmiIp = sanitize(rawIpmiIp, 'string');
const hostId = `${hostType}${hostNumber}`;
assert(
REP_PEACEFUL_STRING.test(hostType),
`Host type must be a peaceful string; got [${hostType}]`,
);
const hostNumber = sanitize(rawHostNumber, 'number');
assert(
REP_INTEGER.test(String(hostNumber)),
Number.isSafeInteger(hostNumber),
`Host number must be an integer; got [${hostNumber}]`,
);
const hostId = `${hostType}${hostNumber}`;
const ipmiIp = sanitize(rawIpmiIp, 'string');
assert(
REP_IPV4.test(ipmiIp),
`IPMI IP of ${hostId} must be an IPv4; got [${ipmiIp}]`,
);
assert.ok(networks, `Host networks is required`);
const ipmiIpKey = `${hostId}_ipmi_ip`;
previous[ipmiIpKey] = ipmiIp;
hosts[ipmiIpKey] = ipmiIp;
try {
Object.values(networks).forEach(
({
networkIp: rawIp,
networkNumber: rawNetworkNumber,
networkType: rawNetworkType,
}) => {
const ip = sanitize(rawIp, 'string');
const networkNumber = sanitize(rawNetworkNumber, 'number');
const networkType = sanitize(rawNetworkType, 'string');
const networkId = `${networkType}${networkNumber}`;
assert(
REP_PEACEFUL_STRING.test(networkType),
`Network type must be a peaceful string; got [${networkType}]`,
);
const networkNumber = sanitize(rawNetworkNumber, 'number');
assert(
REP_INTEGER.test(String(networkNumber)),
Number.isSafeInteger(networkNumber),
`Network number must be an integer; got [${networkNumber}]`,
);
const networkId = `${networkType}${networkNumber}`;
const ip = sanitize(rawIp, 'string');
assert(
REP_IPV4.test(ip),
`IP of host network ${networkId} must be an IPv4; got [${ip}]`,
@ -210,33 +214,50 @@ export const buildManifest = async (
const networkIpKey = `${hostId}_${networkId}_ip`;
previous[networkIpKey] = ip;
hosts[networkIpKey] = ip;
},
);
} catch (error) {
throw new Error(
`Failed to build [${hostId}] networks for manifest; CAUSE: ${error}`,
);
}
try {
if (fences) {
Object.values(fences).forEach(
({ fenceName: rawFenceName, fencePort: rawPort }) => {
const fenceName = sanitize(rawFenceName, 'string');
const port = sanitize(rawPort, 'string');
assert(
REP_PEACEFUL_STRING.test(fenceName),
`Fence name must be a peaceful string; got [${fenceName}]`,
);
const fenceKey = `${hostId}_fence_${fenceName}`;
const port = sanitize(rawPort, 'string');
assert(
REP_PEACEFUL_STRING.test(port),
`Port of ${fenceName} must be a peaceful string; got [${port}]`,
);
previous[fenceKey] = port;
const fenceKey = `${hostId}_fence_${fenceName}`;
hosts[fenceKey] = port;
},
);
}
} catch (error) {
throw new Error(
`Failed to build [${hostId}] fences for manifest; CAUSE: ${error}`,
);
}
try {
if (upses) {
Object.values(upses).forEach(
({ isUsed: rawIsUsed, upsName: rawUpsName }) => {
const upsName = sanitize(rawUpsName, 'string');
assert(
REP_PEACEFUL_STRING.test(upsName),
`UPS name must be a peaceful string; got [${upsName}]`,
@ -247,15 +268,20 @@ export const buildManifest = async (
const isUsed = sanitize(rawIsUsed, 'boolean');
if (isUsed) {
previous[upsKey] = 'checked';
hosts[upsKey] = 'checked';
}
},
);
return previous;
},
{},
}
} catch (error) {
throw new Error(
`Failed to build ${hostId} UPSes for manifest; CAUSE: ${error}`,
);
}
});
} catch (error) {
throw new Error(`Failed to build hosts for manifest; CAUSE: ${error}`);
}
let result: { name: string; uuid: string };
@ -272,9 +298,9 @@ export const buildManifest = async (
ntp,
prefix,
sequence,
...networkCountContainer,
...networkContainer,
...hostContainer,
...netCounts,
...netConfigs,
...hosts,
},
],
pre: ['Striker'],
@ -282,8 +308,8 @@ export const buildManifest = async (
);
result = { name, uuid };
} catch (subError) {
throw new Error(`Failed to generate manifest; CAUSE: ${subError}`);
} catch (error) {
throw new Error(`Failed to generate manifest; CAUSE: ${error}`);
}
return result;

@ -11,12 +11,12 @@ export const createManifest: RequestHandler = async (...handlerArgs) => {
try {
result = await buildManifest(...handlerArgs);
} catch (buildError) {
stderr(`Failed to create new install manifest; CAUSE ${buildError}`);
} catch (error) {
stderr(`Failed to create new install manifest; CAUSE ${error}`);
let code = 500;
if (buildError instanceof AssertionError) {
if (error instanceof AssertionError) {
code = 400;
}

@ -14,14 +14,14 @@ export const updateManifest: RequestHandler = async (...args) => {
try {
result = await buildManifest(...args);
} catch (buildError) {
} catch (error) {
stderr(
`Failed to update install manifest ${manifestUuid}; CAUSE: ${buildError}`,
`Failed to update install manifest ${manifestUuid}; CAUSE: ${error}`,
);
let code = 500;
if (buildError instanceof AssertionError) {
if (error instanceof AssertionError) {
code = 400;
}

@ -1,2 +1,2 @@
export const sanitizeSQLParam = (variable: string): string =>
variable.replace(/[']/g, '');
variable.replace(/'/g, `''`);

@ -54,7 +54,15 @@ export const resolveGid = (id: number | string) => resolveId(id, 'group');
export const resolveUid = (id: number | string) => resolveId(id, 'passwd');
export const stderr = (message: string) => print(message, { stream: 'stderr' });
export const stderr = (message: string, error?: unknown) => {
let msg = message;
if (error instanceof Error) {
msg += `\n${error.stack}`;
}
print(msg, { stream: 'stderr' });
};
export const stdout = (message: string) => print(message);

@ -46,9 +46,9 @@ const StackBar: FC<StackBarProps> = (props) => {
const backgroundColor =
typeof colour === 'string'
? colour
: Object.entries(colour).findLast(
([mark]) => val >= Number(mark),
)?.[1] ?? GREY;
: Object.entries(colour)
.reverse()
.find(([mark]) => val >= Number(mark))?.[1] ?? GREY;
let position: 'absolute' | 'relative' = 'relative';
let top: 0 | undefined;

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(s,a,c,e,t,n,i,f,b,u,k,h,j,d,r,g,l,_){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,c,e,f,b,j,"static/chunks/433-a3be905e7a7d3bfc.js",a,t,n,i,d,r,"static/chunks/pages/index-0771f2825962ebc3.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,c,e,f,b,j,a,t,n,i,d,"static/chunks/pages/anvil-53b02ffa883f4c5a.js"],"/config":[s,c,e,k,"static/chunks/519-4b7761e884c88eb9.js",a,t,n,i,u,h,g,"static/chunks/pages/config-7be24d332b231569.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,c,e,f,"static/chunks/176-7308c25ba374961e.js",a,t,i,u,"static/chunks/pages/file-manager-0697bf1cd793df6d.js"],"/init":[s,c,f,b,k,l,a,t,n,i,_,"static/chunks/pages/init-7cf62951388d0e3b.js"],"/login":[s,c,e,a,t,n,u,h,"static/chunks/pages/login-0b2f91a926538f7c.js"],"/manage-element":[s,c,e,f,b,k,l,"static/chunks/111-2605129c170ed35d.js",a,t,n,i,u,h,_,g,"static/chunks/pages/manage-element-3ed34f8c3a72590a.js"],"/server":[s,e,"static/chunks/528-72edc50189f30fa9.js",a,r,"static/chunks/pages/server-d4d91dcbacc827c4.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/412-ae4bab5809f6a209.js","static/chunks/62-2c80eba24b792af8.js","static/chunks/438-0147a63d98e89439.js","static/chunks/894-e57948de523bcf96.js","static/chunks/195-fa06e61dd4339031.js","static/chunks/987-1ff0d82724b0e58b.js","static/chunks/157-d1418743accab385.js","static/chunks/182-08683bbe95fbb010.js","static/chunks/900-af716a39aed22219.js","static/chunks/248-749f2bec4cb43d28.js","static/chunks/644-c7c6e21c71345aed.js","static/chunks/336-6e600f08d9387d72.js","static/chunks/485-77798bccc4308d0e.js","static/chunks/825-a143aba6cb430f0f.js","static/chunks/94-8322ed453a3c08f0.js","static/chunks/560-0ed707609765e23a.js","static/chunks/676-6159ce853338cc1f.js","static/chunks/86-447b52c8195dea3d.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1 +0,0 @@
self.__BUILD_MANIFEST=function(s,c,a,t,e,n,i,f,d,b,u,k,h,j,r,g,l,_){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,a,t,f,d,h,"static/chunks/433-a3be905e7a7d3bfc.js",c,e,n,i,j,r,"static/chunks/pages/index-6ff72adab3a682db.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,a,t,f,d,h,c,e,n,i,j,"static/chunks/pages/anvil-5ff2efa937105177.js"],"/config":[s,a,t,u,"static/chunks/586-4e70511cf6d7632f.js",c,e,n,i,b,k,g,"static/chunks/pages/config-0cb597caf390573f.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,a,t,f,"static/chunks/176-7308c25ba374961e.js",c,e,i,b,"static/chunks/pages/file-manager-1ae01a78e266275a.js"],"/init":[s,a,f,d,u,l,c,e,n,i,_,"static/chunks/pages/init-053607258b5d7d64.js"],"/login":[s,a,t,c,e,n,b,k,"static/chunks/pages/login-1b987b077ffc3420.js"],"/manage-element":[s,a,t,f,d,u,l,"static/chunks/111-2605129c170ed35d.js",c,e,n,i,b,k,_,g,"static/chunks/pages/manage-element-6b42a013966413d3.js"],"/server":[s,t,"static/chunks/528-72edc50189f30fa9.js",c,r,"static/chunks/pages/server-4ac03eba56ccfcbf.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/382-f51344f6f9208507.js","static/chunks/62-532ed713980da8db.js","static/chunks/438-0147a63d98e89439.js","static/chunks/894-e57948de523bcf96.js","static/chunks/195-fa06e61dd4339031.js","static/chunks/987-1ff0d82724b0e58b.js","static/chunks/157-d1418743accab385.js","static/chunks/182-08683bbe95fbb010.js","static/chunks/434-07ec1dcc649bdd0c.js","static/chunks/248-749f2bec4cb43d28.js","static/chunks/644-c7c6e21c71345aed.js","static/chunks/336-8a7866afcf131f68.js","static/chunks/485-77798bccc4308d0e.js","static/chunks/825-0b3ee47570192a02.js","static/chunks/94-8322ed453a3c08f0.js","static/chunks/560-0ed707609765e23a.js","static/chunks/676-6159ce853338cc1f.js","static/chunks/86-447b52c8195dea3d.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save