diff --git a/src/cli/repl/commands/repl-query.ts b/src/cli/repl/commands/repl-query.ts
index 64547ca7ab..e8c683d909 100644
--- a/src/cli/repl/commands/repl-query.ts
+++ b/src/cli/repl/commands/repl-query.ts
@@ -22,6 +22,7 @@ import { normalizedAstToMermaidUrl } from '../../../util/mermaid/ast';
import { printAsMs } from '../../../util/time';
import { textWithTooltip } from '../../../documentation/doc-util/doc-hover-over';
+import type { StaticSliceQuery } from '../../../queries/catalog/static-slice-query/static-slice-query-format';
async function getDataflow(shell: RShell, remainingLine: string) {
return await new PipelineExecutor(DEFAULT_DATAFLOW_PIPELINE, {
@@ -162,6 +163,26 @@ export function asciiSummaryOfQueryResult(formatter: OutputFormatter, totalInMs:
result.push(`Query: ${bold(query, formatter)} (${printAsMs(out['.meta'].timing, 0)})`);
result.push(` ╰ [Normalized AST](${normalizedAstToMermaidUrl(out.normalized.ast)})`);
continue;
+ } else if(query === 'static-slice') {
+ const out = queryResults as QueryResults<'static-slice'>['static-slice'];
+ result.push(`Query: ${bold(query, formatter)} (${printAsMs(out['.meta'].timing, 0)})`);
+ for(const [fingerprint, obj] of Object.entries(out.results)) {
+ const { criteria, noMagicComments, noReconstruction } = JSON.parse(fingerprint) as StaticSliceQuery;
+ const addons = [];
+ if(noReconstruction) {
+ addons.push('no reconstruction');
+ }
+ if(noMagicComments) {
+ addons.push('no magic comments');
+ }
+ result.push(` ╰ Slice for {${criteria.join(', ')}} ${addons.join(', ')}`);
+ if('reconstruct' in obj) {
+ result.push(' ╰ Code (newline as \n
): ' + obj.reconstruct.code.split('\n').join('\\n') + '
');
+ } else {
+ result.push(` ╰ Id List: {${summarizeIdsIfTooLong([...obj.slice.result])}}`);
+ }
+ }
+ continue;
} else if(query === 'dataflow-cluster') {
const out = queryResults as QueryResults<'dataflow-cluster'>['dataflow-cluster'];
result.push(`Query: ${bold(query, formatter)} (${out['.meta'].timing.toFixed(0)}ms)`);
diff --git a/src/core/steps/pipeline/default-pipelines.ts b/src/core/steps/pipeline/default-pipelines.ts
index 97c4c36da9..4ecca7506d 100644
--- a/src/core/steps/pipeline/default-pipelines.ts
+++ b/src/core/steps/pipeline/default-pipelines.ts
@@ -10,6 +10,7 @@ import { NAIVE_RECONSTRUCT } from '../all/static-slicing/10-reconstruct';
export const DEFAULT_SLICING_PIPELINE = createPipeline(PARSE_WITH_R_SHELL_STEP, NORMALIZE, STATIC_DATAFLOW, STATIC_SLICE, NAIVE_RECONSTRUCT);
export const DEFAULT_SLICE_AND_RECONSTRUCT_PIPELINE = DEFAULT_SLICING_PIPELINE;
+export const DEFAULT_SLICE_WITHOUT_RECONSTRUCT_PIPELINE = createPipeline(PARSE_WITH_R_SHELL_STEP, NORMALIZE, STATIC_DATAFLOW, STATIC_SLICE);
export const DEFAULT_DATAFLOW_PIPELINE = createPipeline(PARSE_WITH_R_SHELL_STEP, NORMALIZE, STATIC_DATAFLOW);
diff --git a/src/documentation/data/server/doc-data-server-messages.ts b/src/documentation/data/server/doc-data-server-messages.ts
index 99bc3d6fe0..caed6191a2 100644
--- a/src/documentation/data/server/doc-data-server-messages.ts
+++ b/src/documentation/data/server/doc-data-server-messages.ts
@@ -28,8 +28,9 @@ import {
import { exampleQueryCode } from '../query/example-query-code';
import { CallTargets } from '../../../queries/catalog/call-context-query/call-context-query-format';
import { requestLineageMessage, responseLineageMessage } from '../../../cli/repl/server/messages/message-lineage';
+import { block } from '../../doc-util/doc-structure';
-export function documentAllMessages() {
+export function documentAllServerMessages() {
documentServerMessage({
title: 'Hello',
@@ -244,9 +245,14 @@ While the context is derived from the \`filename\`, we currently offer no way to
end
deactivate Server
`,
- shortDescription: 'The server slices a file based on the given criteria.',
+ shortDescription: `([DEPRECATED](${FlowrWikiBaseRef}/Query%20API)) The server slices a file based on the given criteria.`,
text: async(shell: RShell) => {
return `
+${block({
+ type: 'WARNING',
+ content: `We deprecated the slice request in favor of the \`static-slice\` [Query](${FlowrWikiBaseRef}/Query%20API).`
+ })}
+
To slice, you have to send a file analysis request first. The \`filetoken\` you assign is of use here as you can re-use it to repeatedly slice the same file.
Besides that, you only need to add an array of slicing criteria, using one of the formats described on the [terminology wiki page](${FlowrWikiBaseRef}/Terminology#slicing-criterion)
(however, instead of using \`;\`, you can simply pass separate array elements).
diff --git a/src/documentation/print-interface-wiki.ts b/src/documentation/print-interface-wiki.ts
index ffc37dff3f..99e1c053bb 100644
--- a/src/documentation/print-interface-wiki.ts
+++ b/src/documentation/print-interface-wiki.ts
@@ -5,7 +5,7 @@ import { FlowrGithubBaseRef, FlowrNpmRef, FlowrWikiBaseRef, getFileContentFromRo
import { autoGenHeader } from './doc-util/doc-auto-gen';
import { getCliLongOptionOf, getReplCommand, multipleCliOptions } from './doc-util/doc-cli-option';
import { printServerMessages } from './doc-util/doc-server-message';
-import { documentAllMessages } from './data/server/doc-data-server-messages';
+import { documentAllServerMessages } from './data/server/doc-data-server-messages';
import { codeBlock } from './doc-util/doc-code';
import type { FileAnalysisRequestMessage } from '../cli/repl/server/messages/message-analysis';
import { fileProtocol, removeRQuotes, requestFromInput } from '../r-bridge/retriever';
@@ -21,7 +21,7 @@ import { NewIssueUrl } from './doc-util/doc-issue';
import { PipelineExecutor } from '../core/pipeline-executor';
async function explainServer(shell: RShell): Promise {
- documentAllMessages();
+ documentAllServerMessages();
return `
As explained in the [Overview](${FlowrWikiBaseRef}/Overview), you can simply run the [TCP](https://de.wikipedia.org/wiki/Transmission_Control_Protocol) server by adding the ${getCliLongOptionOf('flowr', 'server', true)} flag (and, due to the interactive mode, exit with the conventional CTRL+C).
diff --git a/src/documentation/print-query-wiki.ts b/src/documentation/print-query-wiki.ts
index 4b2b20a025..84c87802f0 100644
--- a/src/documentation/print-query-wiki.ts
+++ b/src/documentation/print-query-wiki.ts
@@ -19,6 +19,7 @@ import { executeDataflowQuery } from '../queries/catalog/dataflow-query/dataflow
import { executeIdMapQuery } from '../queries/catalog/id-map-query/id-map-query-executor';
import { executeNormalizedAstQuery } from '../queries/catalog/normalized-ast-query/normalized-ast-query-executor';
import { executeDataflowClusterQuery } from '../queries/catalog/cluster-query/cluster-query-executor';
+import { executeStaticSliceClusterQuery } from '../queries/catalog/static-slice-query/static-slice-query-executor';
registerQueryDocumentation('call-context', {
@@ -246,6 +247,51 @@ Now, the results no longer contain calls to \`plot\` that are not defined locall
});
+registerQueryDocumentation('static-slice', {
+ name: 'Static Slice Query',
+ type: 'active',
+ shortDescription: 'Slice the dataflow graph reducing the code to just the parts relevant for the given criteria.',
+ functionName: executeStaticSliceClusterQuery.name,
+ functionFile: '../queries/catalog/static-slice-query/static-slice-query-executor.ts',
+ buildExplanation: async(shell: RShell) => {
+ const exampleCode = 'x <- 1\ny <- 2\nx';
+ return `
+To slice, _flowR_ needs one thing from you: a variable or a list of variables (function calls are supported to, referring to the anonymous
+return of the call) that you want to slice the dataflow graph for.
+Given this, the slice is essentially the subpart of the program that may influence the value of the variables you are interested in.
+To specify a variable of interest, you have to present flowR with a [slicing criterion](${FlowrWikiBaseRef}/Terminology#slicing-criterion) (or, respectively, an array of them).
+
+To exemplify the capabilities, consider the following code:
+${codeBlock('r', exampleCode)}
+If you are interested in the parts required for the use of \`x\` in the last line, you can use the following query:
+
+${
+ await showQuery(shell, exampleCode, [{
+ type: 'static-slice',
+ criteria: ['3@x']
+ }], { showCode: false })
+}
+
+In general you may be uninterested in seeing the reconstructed version and want to save some computation time, for this,
+you can use the \`noReconstruction\` flag.
+
+${
+ details('No Reconstruction Example',
+ await showQuery(shell, exampleCode, [{
+ type: 'static-slice',
+ criteria: ['3@x'],
+ noReconstruction: true
+ }], { showCode: false })
+ )
+}
+
+You can disable [magic comments](${FlowrWikiBaseRef}/Interface#slice-magic-comments) using the \`noMagicComments\` flag.
+This query replaces the old [\`request-slice\`](${FlowrWikiBaseRef}/Interface#message-request-slice) message.
+ `;
+ }
+});
+
+
async function getText(shell: RShell) {
const rversion = (await shell.usedRVersion())?.format() ?? 'unknown';
return `${autoGenHeader({ filename: module.filename, purpose: 'query API', rVersion: rversion })}
diff --git a/src/queries/catalog/call-context-query/call-context-query-executor.ts b/src/queries/catalog/call-context-query/call-context-query-executor.ts
index 8c53a72879..a18592848b 100644
--- a/src/queries/catalog/call-context-query/call-context-query-executor.ts
+++ b/src/queries/catalog/call-context-query/call-context-query-executor.ts
@@ -46,7 +46,7 @@ function satisfiesCallTargets(id: NodeId, graph: DataflowGraph, callTarget: Call
* including any potential built-in mapping.
*/
const reResolved = resolveByName(info.name, info.environment, ReferenceType.Unknown);
- if(reResolved && reResolved.some(t => t.definedAt === BuiltIn)) {
+ if(reResolved?.some(t => t.definedAt === BuiltIn)) {
builtIn = true;
}
}
diff --git a/src/queries/catalog/static-slice-query/static-slice-query-executor.ts b/src/queries/catalog/static-slice-query/static-slice-query-executor.ts
new file mode 100644
index 0000000000..8faaabab80
--- /dev/null
+++ b/src/queries/catalog/static-slice-query/static-slice-query-executor.ts
@@ -0,0 +1,38 @@
+import type { BasicQueryData } from '../../query';
+import type { StaticSliceQuery, StaticSliceQueryResult } from './static-slice-query-format';
+import { staticSlicing } from '../../../slicing/static/static-slicer';
+import { reconstructToCode } from '../../../reconstruct/reconstruct';
+import { doNotAutoSelect } from '../../../reconstruct/auto-select/auto-select-defaults';
+import { makeMagicCommentHandler } from '../../../reconstruct/auto-select/magic-comments';
+import { log } from '../../../util/log';
+
+export function fingerPrintOfQuery(query: StaticSliceQuery): string {
+ return JSON.stringify(query);
+}
+
+export function executeStaticSliceClusterQuery({ graph, ast }: BasicQueryData, queries: readonly StaticSliceQuery[]): StaticSliceQueryResult {
+ const start = Date.now();
+ const results: StaticSliceQueryResult['results'] = {};
+ for(const query of queries) {
+ const key = fingerPrintOfQuery(query);
+ if(results[key]) {
+ log.warn(`Duplicate Key for slicing-query: ${key}, skipping...`);
+ }
+ const { criteria, noReconstruction, noMagicComments } = query;
+ const slice = staticSlicing(graph, ast, criteria);
+ if(noReconstruction) {
+ results[key] = { slice };
+ } else {
+ results[key] = {
+ slice,
+ reconstruct: reconstructToCode(ast, slice.result, noMagicComments ? doNotAutoSelect : makeMagicCommentHandler(doNotAutoSelect))
+ };
+ }
+ }
+ return {
+ '.meta': {
+ timing: Date.now() - start
+ },
+ results
+ };
+}
diff --git a/src/queries/catalog/static-slice-query/static-slice-query-format.ts b/src/queries/catalog/static-slice-query/static-slice-query-format.ts
new file mode 100644
index 0000000000..8c80c17f26
--- /dev/null
+++ b/src/queries/catalog/static-slice-query/static-slice-query-format.ts
@@ -0,0 +1,32 @@
+import type { BaseQueryFormat, BaseQueryResult } from '../../base-query-format';
+import type { PipelineOutput } from '../../../core/steps/pipeline/pipeline';
+import type {
+ DEFAULT_DATAFLOW_PIPELINE, DEFAULT_SLICE_WITHOUT_RECONSTRUCT_PIPELINE,
+ DEFAULT_SLICING_PIPELINE
+} from '../../../core/steps/pipeline/default-pipelines';
+import type { SlicingCriteria } from '../../../slicing/criterion/parse';
+
+/** Calculates and returns all clusters encountered in the dataflow graph. */
+export interface StaticSliceQuery extends BaseQueryFormat {
+ readonly type: 'static-slice';
+ /** The slicing criteria to use */
+ readonly criteria: SlicingCriteria,
+ /** do not reconstruct the slice into readable code */
+ readonly noReconstruction?: boolean;
+ /** Should the magic comments (force-including lines within the slice) be ignored? */
+ readonly noMagicComments?: boolean
+}
+
+export interface StaticSliceQueryResult extends BaseQueryResult {
+ /**
+ * only contains the results of the slice steps to not repeat ourselves, this does not contain the reconstruction
+ * if you set the {@link SliceQuery#noReconstruction|noReconstruction} flag.
+ *
+ * The keys are serialized versions of the used queries (i.e., the result of `JSON.stringify`).
+ * This implies that multiple slice queries with the same query configuration will _not_ be re-executed.
+ */
+ results: Record, keyof PipelineOutput> |
+ Omit, keyof PipelineOutput>
+ >
+}
diff --git a/src/queries/query-schema.ts b/src/queries/query-schema.ts
index 07751dc133..0e3e891837 100644
--- a/src/queries/query-schema.ts
+++ b/src/queries/query-schema.ts
@@ -31,13 +31,21 @@ export const DataflowClusterQuerySchema = Joi.object({
type: Joi.string().valid('dataflow-cluster').required().description('The type of the query.'),
}).description('The cluster query calculates and returns all clusters in the dataflow graph.');
+export const StaticSliceQuerySchema = Joi.object({
+ type: Joi.string().valid('static-slice').required().description('The type of the query.'),
+ criteria: Joi.array().items(Joi.string()).min(0).required().description('The slicing criteria to use.'),
+ noReconstruction: Joi.boolean().optional().description('Do not reconstruct the slice into readable code.'),
+ noMagicComments: Joi.boolean().optional().description('Should the magic comments (force-including lines within the slice) be ignored?')
+}).description('Slice query used to slice the dataflow graph');
+
export const SupportedQueriesSchema = Joi.alternatives(
CallContextQuerySchema,
DataflowQuerySchema,
IdMapQuerySchema,
NormalizedAstQuerySchema,
- DataflowClusterQuerySchema
+ DataflowClusterQuerySchema,
+ StaticSliceQuerySchema
).description('Supported queries');
export const CompoundQuerySchema = Joi.object({
diff --git a/src/queries/query.ts b/src/queries/query.ts
index d5c60344f9..466e28eb17 100644
--- a/src/queries/query.ts
+++ b/src/queries/query.ts
@@ -16,8 +16,10 @@ import { executeNormalizedAstQuery } from './catalog/normalized-ast-query/normal
import type { NormalizedAstQuery } from './catalog/normalized-ast-query/normalized-ast-query-format';
import type { DataflowClusterQuery } from './catalog/cluster-query/cluster-query-format';
import { executeDataflowClusterQuery } from './catalog/cluster-query/cluster-query-executor';
+import type { StaticSliceQuery } from './catalog/static-slice-query/static-slice-query-format';
+import { executeStaticSliceClusterQuery } from './catalog/static-slice-query/static-slice-query-executor';
-export type Query = CallContextQuery | DataflowQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery;
+export type Query = CallContextQuery | DataflowQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery;
export type QueryArgumentsWithType = Query & { type: QueryType };
@@ -39,6 +41,7 @@ export const SupportedQueries = {
'id-map': executeIdMapQuery,
'normalized-ast': executeNormalizedAstQuery,
'dataflow-cluster': executeDataflowClusterQuery,
+ 'static-slice': executeStaticSliceClusterQuery
} as const satisfies SupportedQueries;
export type SupportedQueryTypes = keyof typeof SupportedQueries;
diff --git a/test/functionality/_helper/query.ts b/test/functionality/_helper/query.ts
index 93d60b4d9c..8ca65fbc08 100644
--- a/test/functionality/_helper/query.ts
+++ b/test/functionality/_helper/query.ts
@@ -47,8 +47,12 @@ function normalizeResults(result: QueryResults = VirtualCompoundConstraint
->(name: string | TestLabel, shell: RShell, code: string, queries: readonly (Queries | VirtualQueryArgumentsWithType)[], expected:
- QueryResultsWithoutMeta | ((info: PipelineOutput) => QueryResultsWithoutMeta)
+>(
+ name: string | TestLabel,
+ shell: RShell,
+ code: string,
+ queries: readonly (Queries | VirtualQueryArgumentsWithType)[],
+ expected: QueryResultsWithoutMeta | ((info: PipelineOutput) => (QueryResultsWithoutMeta | Promise>))
) {
const effectiveName = decorateLabelContext(name, ['query']);
@@ -68,7 +72,7 @@ export function assertQuery<
/* expect them to be deeply equal */
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
- const expectedNormalized = typeof expected === 'function' ? expected(info) : expected;
+ const expectedNormalized = typeof expected === 'function' ? await expected(info) : expected;
assert.deepStrictEqual(normalized, expectedNormalized, 'The result of the call context query does not match the expected result');
} catch(e: unknown) {
console.error('Dataflow-Graph', dataflowGraphToMermaidUrl(info.dataflow));
diff --git a/test/functionality/dataflow/query/slice-query-tests.ts b/test/functionality/dataflow/query/slice-query-tests.ts
new file mode 100644
index 0000000000..88dd34f84a
--- /dev/null
+++ b/test/functionality/dataflow/query/slice-query-tests.ts
@@ -0,0 +1,51 @@
+import { assertQuery } from '../../_helper/query';
+import { label } from '../../_helper/label';
+import { withShell } from '../../_helper/shell';
+import type {
+ StaticSliceQuery,
+ StaticSliceQueryResult
+} from '../../../../src/queries/catalog/static-slice-query/static-slice-query-format';
+import { fingerPrintOfQuery } from '../../../../src/queries/catalog/static-slice-query/static-slice-query-executor';
+import { PipelineExecutor } from '../../../../src/core/pipeline-executor';
+import {
+ DEFAULT_SLICE_WITHOUT_RECONSTRUCT_PIPELINE,
+ DEFAULT_SLICING_PIPELINE
+} from '../../../../src/core/steps/pipeline/default-pipelines';
+import { requestFromInput } from '../../../../src/r-bridge/retriever';
+import { doNotAutoSelect } from '../../../../src/reconstruct/auto-select/auto-select-defaults';
+import { makeMagicCommentHandler } from '../../../../src/reconstruct/auto-select/magic-comments';
+
+describe('Static Slice Query', withShell(shell => {
+ function testQuery(name: string, code: string, queries: readonly StaticSliceQuery[]) {
+ assertQuery(label(name), shell, code, queries, async() => {
+ const results: StaticSliceQueryResult['results'] = {};
+ for(const query of queries) {
+ const out = await new PipelineExecutor(query.noReconstruction ? DEFAULT_SLICE_WITHOUT_RECONSTRUCT_PIPELINE : DEFAULT_SLICING_PIPELINE, {
+ shell: shell,
+ request: requestFromInput(code),
+ criterion: query.criteria,
+ autoSelectIf: query.noMagicComments ? doNotAutoSelect : makeMagicCommentHandler(doNotAutoSelect)
+ }).allRemainingSteps();
+ const key = fingerPrintOfQuery(query);
+ results[key] = query.noReconstruction ? { slice: out.slice } : { slice: out.slice, reconstruct: out.reconstruct };
+ }
+
+ return {
+ 'static-slice': {
+ results
+ }
+ };
+ });
+ }
+
+ const baseQuery: StaticSliceQuery = { type: 'static-slice', criteria: ['1@x'] };
+ describe('With Reconstruction', () => {
+ testQuery('Single Expression', 'x + 1', [baseQuery]);
+ testQuery('Multiple Queries', 'x + 1', [baseQuery, baseQuery, baseQuery]);
+ });
+ const noReconstructQuery: StaticSliceQuery = { type: 'static-slice', criteria: ['1@x'], noReconstruction: true };
+ describe('Without Reconstruction', () => {
+ testQuery('Single Expression (No Reconstruct)', 'x + 1', [noReconstructQuery]);
+ testQuery('Multiple Queries (No Reconstruct)', 'x + 1', [noReconstructQuery, noReconstructQuery, noReconstructQuery]);
+ });
+}));
diff --git a/wiki/Query API.md b/wiki/Query API.md
index 1ead6d2bd6..95e010aac3 100644
--- a/wiki/Query API.md
+++ b/wiki/Query API.md
@@ -1,4 +1,4 @@
-_This document was generated from 'src/documentation/print-query-wiki.ts' on 2024-10-12, 17:01:05 UTC presenting an overview of flowR's query API (v2.1.1, using R v4.4.0)._
+_This document was generated from 'src/documentation/print-query-wiki.ts' on 2024-10-12, 18:57:38 UTC presenting an overview of flowR's query API (v2.1.1, using R v4.4.1)._
This page briefly summarizes flowR's query API, represented by the executeQueries function in [`./src/queries/query.ts`](https://github.com/flowr-analysis/flowr/tree/main/./src/queries/query.ts).
Please see the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to access this API.
@@ -24,6 +24,8 @@ For now, we support the following **active** queries (which we will refer to sim
Returns the id-map of the normalized AST of the given code.
1. [Normalized AST Query](#normalized-ast-query) (`normalized-ast`):\
Returns the normalized AST of the given code.
+1. [Static Slice Query](#static-slice-query) (`static-slice`):\
+ Slice the dataflow graph reducing the code to just the parts relevant for the given criteria.
Similarly, we support the following **virtual** queries:
@@ -89,6 +91,19 @@ Valid item types:
- **type** string [required]
_The type of the query._
Allows only the values: 'dataflow-cluster'
+ - **.** object
+ _Slice query used to slice the dataflow graph_
+ - **type** string [required]
+ _The type of the query._
+ Allows only the values: 'static-slice'
+ - **criteria** array [required]
+ _The slicing criteria to use._
+ Valid item types:
+ - **.** string
+ - **noReconstruction** boolean [optional]
+ _Do not reconstruct the slice into readable code._
+ - **noMagicComments** boolean [optional]
+ _Should the magic comments (force-including lines within the slice) be ignored?_
- **.** alternatives
_Virtual queries (used for structure)_
- **.** object
@@ -408,7 +423,7 @@ flowchart LR
89 -->|"reads, returns, argument"| 87
```
-(The analysis required _20.18 ms_ (incl. parse and normalize) within the generation environment.)
+(The analysis required _18.88 ms_ (incl. parse and normalize) within the generation environment.)
@@ -454,7 +469,7 @@ _All queries together required ≈1 ms (1ms accuracy, total 8 ms)_
Show Detailed Results as Json
-The analysis required _8.16 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _7.93 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -556,17 +571,17 @@ all calls that start with `read_` to the kind `input` but only if they are not l
_Results (prettified and summarized):_
-Query: **call-context** (2 ms)\
+Query: **call-context** (3 ms)\
╰ **input**\
╰ **csv-file**: _`read_csv`_ (L.6), _`read_csv`_ (L.7)\
╰ **visualize**\
╰ **text**: _`mean`_ (L.9), _`mean`_ (L.19)\
╰ **plot**: _`points`_ (L.17) with 1 link (_`plot`_ (L.16))\
-_All queries together required ≈2 ms (1ms accuracy, total 13 ms)_
+_All queries together required ≈3 ms (1ms accuracy, total 12 ms)_
Show Detailed Results as Json
-The analysis required _12.61 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _11.76 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -578,7 +593,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
{
"call-context": {
".meta": {
- "timing": 2
+ "timing": 3
},
"kinds": {
"input": {
@@ -618,7 +633,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
}
},
".meta": {
- "timing": 2
+ "timing": 3
}
}
```
@@ -668,11 +683,11 @@ _Results (prettified and summarized):_
Query: **call-context** (0 ms)\
╰ **.**\
╰ **.**: _`foo`_ (L.2) with 1 alias root (_`my_test_function`_ (L.1)), _`bar`_ (L.4) with 1 alias root (_`my_test_function`_ (L.1)), _`my_test_function`_ (L.5)\
-_All queries together required ≈0 ms (1ms accuracy, total 4 ms)_
+_All queries together required ≈0 ms (1ms accuracy, total 5 ms)_
Show Detailed Results as Json
-The analysis required _4.15 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _4.74 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -769,7 +784,7 @@ _All queries together required ≈0 ms (1ms accuracy, total 2 ms)_
Show Detailed Results as Json
-The analysis required _1.73 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _1.56 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -797,7 +812,7 @@ x + 1
Dataflow Graph of the R Code
-The analysis required _1.31 ms_ (incl. parse and normalize) within the generation environment.
+The analysis required _1.35 ms_ (incl. parse and normalize) within the generation environment.
We encountered no unknown side effects during the analysis.
@@ -891,7 +906,7 @@ _All queries together required ≈0 ms (1ms accuracy, total 1 ms)_
Show Detailed Results as Json
-The analysis required _1.22 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _1.24 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -919,7 +934,7 @@ x + 1
Dataflow Graph of the R Code
-The analysis required _1.26 ms_ (incl. parse and normalize) within the generation environment.
+The analysis required _1.21 ms_ (incl. parse and normalize) within the generation environment.
We encountered no unknown side effects during the analysis.
@@ -1020,7 +1035,7 @@ _All queries together required ≈0 ms (1ms accuracy, total 2 ms)_
Show Detailed Results as Json
-The analysis required _1.90 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _1.81 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1086,11 +1101,11 @@ Query: **dataflow-cluster** (0ms)\
╰ Found 2 clusters\
╰ {3} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JOdW1iZXIjOTM7IDFcbiAgICAgICgxKVxuICAgICAgKjEuNipgXCJ9fVxuICAgIDBbXCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICgwKVxuICAgICAgKjEuMSpgXCJdXG4gICAgMltbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzYwOyM0NTtcbiAgICAgICgyKVxuICAgICAgKjEuMS02KlxuICAgICgwLCAxKWBcIl1dXG4gICAgMyhbXCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICgzKVxuICAgICAgKjEuOSpgXCJdKVxuICAgIHN0eWxlIDMgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDFcbiAgICAwIC0tPnxcImRlZmluZWQtYnlcInwgMlxuICAgIDIgLS0+fFwiYXJndW1lbnRcInwgMVxuICAgIDIgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMCIsIm1lcm1haWQiOnsiYXV0b1N5bmMiOnRydWV9fQ==))\
╰ {2, 1, 0} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JOdW1iZXIjOTM7IDFcbiAgICAgICgxKVxuICAgICAgKjEuNipgXCJ9fVxuICAgIHN0eWxlIDEgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMFtcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDApXG4gICAgICAqMS4xKmBcIl1cbiAgICBzdHlsZSAwIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDJbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMilcbiAgICAgICoxLjEtNipcbiAgICAoMCwgMSlgXCJdXVxuICAgIHN0eWxlIDIgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMyhbXCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICgzKVxuICAgICAgKjEuOSpgXCJdKVxuICAgIDAgLS0+fFwiZGVmaW5lZC1ieVwifCAxXG4gICAgMCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDJcbiAgICAyIC0tPnxcImFyZ3VtZW50XCJ8IDFcbiAgICAyIC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDAiLCJtZXJtYWlkIjp7ImF1dG9TeW5jIjp0cnVlfX0=))\
-_All queries together required ≈0 ms (1ms accuracy, total 1 ms)_
+_All queries together required ≈0 ms (1ms accuracy, total 2 ms)_
Show Detailed Results as Json
-The analysis required _1.40 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _1.53 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1157,18 +1172,18 @@ Using the example code from above, the following query returns all clusters:
_Results (prettified and summarized):_
-Query: **dataflow-cluster** (0ms)\
+Query: **dataflow-cluster** (1ms)\
╰ Found 5 clusters\
╰ {89, 87, 85, 82, 18, 22, ... (see JSON below)} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JTeW1ib2wjOTM7IGdncGxvdFxuICAgICAgKDEpXG4gICAgICAqMS45LTE0KmBcIn19XG4gICAgM1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgzKVxuICAgICAgKjEuMS0xNSpcbiAgICAoMSlgXCJdXVxuICAgIHN0eWxlIDMgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICA1e3tcImAjOTE7UlN5bWJvbCM5MzsgZHBseXJcbiAgICAgICg1KVxuICAgICAgKjIuOS0xMypgXCJ9fVxuICAgIDdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBsaWJyYXJ5XG4gICAgICAoNylcbiAgICAgICoyLjEtMTQqXG4gICAgKDUpYFwiXV1cbiAgICBzdHlsZSA3IHN0cm9rZTpyZWQsc3Ryb2tlLXdpZHRoOjVweDsgXG4gICAgOXt7XCJgIzkxO1JTeW1ib2wjOTM7IHJlYWRyXG4gICAgICAoOSlcbiAgICAgICozLjktMTMqYFwifX1cbiAgICAxMVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgxMSlcbiAgICAgICozLjEtMTQqXG4gICAgKDkpYFwiXV1cbiAgICBzdHlsZSAxMSBzdHJva2U6cmVkLHN0cm9rZS13aWR0aDo1cHg7IFxuICAgIDE0e3tcImAjOTE7UlN0cmluZyM5MzsgIzM5O2RhdGEuY3N2IzM5O1xuICAgICAgKDE0KVxuICAgICAgKjYuMTgtMjcqYFwifX1cbiAgICAxNltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHJlYWQjOTU7Y3N2XG4gICAgICAoMTYpXG4gICAgICAqNi45LTI4KlxuICAgICgxNClgXCJdXVxuICAgIDEyW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMTIpXG4gICAgICAqNi4xLTQqYFwiXVxuICAgIDE3W1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDE3KVxuICAgICAgKjYuMS0yOCpcbiAgICAoMTIsIDE2KWBcIl1dXG4gICAgMjB7e1wiYCM5MTtSU3RyaW5nIzkzOyAjMzk7ZGF0YTIuY3N2IzM5O1xuICAgICAgKDIwKVxuICAgICAgKjcuMTktMjkqYFwifX1cbiAgICBzdHlsZSAyMCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAyMltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHJlYWQjOTU7Y3N2XG4gICAgICAoMjIpXG4gICAgICAqNy4xMC0zMCpcbiAgICAoMjApYFwiXV1cbiAgICBzdHlsZSAyMiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAxOFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICgxOClcbiAgICAgICo3LjEtNSpgXCJdXG4gICAgc3R5bGUgMTggc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMjNbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMjMpXG4gICAgICAqNy4xLTMwKlxuICAgICgxOCwgMjIpYFwiXV1cbiAgICBzdHlsZSAyMyBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAyNihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGFcbiAgICAgICgyNilcbiAgICAgICo5LjExLTE0KmBcIl0pXG4gICAgMjd7e1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoMjcpXG4gICAgICAqOS4xMS0xNipgXCJ9fVxuICAgIDI5W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDI5KVxuICAgICAgKjkuMTEtMTYqXG4gICAgKDI2LCAyNylgXCJdXVxuICAgIDMxW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbWVhblxuICAgICAgKDMxKVxuICAgICAgKjkuNi0xNypcbiAgICAoMjkpYFwiXV1cbiAgICAyNFtcImAjOTE7UlN5bWJvbCM5MzsgbVxuICAgICAgKDI0KVxuICAgICAgKjkuMSpgXCJdXG4gICAgMzJbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMzIpXG4gICAgICAqOS4xLTE3KlxuICAgICgyNCwgMzEpYFwiXV1cbiAgICAzNChbXCJgIzkxO1JTeW1ib2wjOTM7IG1cbiAgICAgICgzNClcbiAgICAgICoxMC43KmBcIl0pXG4gICAgMzZbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwcmludFxuICAgICAgKDM2KVxuICAgICAgKjEwLjEtOCpcbiAgICAoMzQpYFwiXV1cbiAgICAzOChbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGFcbiAgICAgICgzOClcbiAgICAgICoxMi4xLTQqYFwiXSlcbiAgICA0MyhbXCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg0MylcbiAgICAgICoxMy4yNCpgXCJdKVxuICAgIDQ0KFtcImAjOTE7UkFyZ3VtZW50IzkzOyB4XG4gICAgICAoNDQpXG4gICAgICAqMTMuMjAqYFwiXSlcbiAgICA0NihbXCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg0NilcbiAgICAgICoxMy4zMSpgXCJdKVxuICAgIDQ3KFtcImAjOTE7UkFyZ3VtZW50IzkzOyB5XG4gICAgICAoNDcpXG4gICAgICAqMTMuMjcqYFwiXSlcbiAgICA0OFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGFlc1xuICAgICAgKDQ4KVxuICAgICAgKjEzLjE2LTMyKlxuICAgICh4ICg0NCksIHkgKDQ3KSlgXCJdXVxuICAgIDUwW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgZ2dwbG90XG4gICAgICAoNTApXG4gICAgICAqMTMuOS0zMypcbiAgICAoMzgsIDQ4KWBcIl1dXG4gICAgNTJbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBkYXRhICUjNjI7JVxuXHRnZ3Bsb3QoYWVzKHggPSB4LCB5ID0geSkpXG4gICAgICAoNTIpXG4gICAgICAqMTIuNi04KlxuICAgICgzOCwgNTApYFwiXV1cbiAgICA1NFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGdlb20jOTU7cG9pbnRcbiAgICAgICg1NClcbiAgICAgICoxNC45LTIwKmBcIl1dXG4gICAgNTVbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM0MztcbiAgICAgICg1NSlcbiAgICAgICoxMi4xLTE0LjIwKlxuICAgICg1MiwgNTQpYFwiXV1cbiAgICA1NyhbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNTcpXG4gICAgICAqMTYuNi0xMCpgXCJdKVxuICAgIHN0eWxlIDU3IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDU4e3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDU4KVxuICAgICAgKjE2LjYtMTIqYFwifX1cbiAgICBzdHlsZSA1OCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA2MFtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg2MClcbiAgICAgICoxNi42LTEyKlxuICAgICg1NywgNTgpYFwiXV1cbiAgICBzdHlsZSA2MCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA2MihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNjIpXG4gICAgICAqMTYuMTUtMTkqYFwiXSlcbiAgICBzdHlsZSA2MiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA2M3t7XCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg2MylcbiAgICAgICoxNi4xNS0yMSpgXCJ9fVxuICAgIHN0eWxlIDYzIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDY1W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDY1KVxuICAgICAgKjE2LjE1LTIxKlxuICAgICg2MiwgNjMpYFwiXV1cbiAgICBzdHlsZSA2NSBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA2N1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHBsb3RcbiAgICAgICg2NylcbiAgICAgICoxNi4xLTIyKlxuICAgICg2MCwgNjUpYFwiXV1cbiAgICBzdHlsZSA2NyBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA2OShbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNjkpXG4gICAgICAqMTcuOC0xMipgXCJdKVxuICAgIHN0eWxlIDY5IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDcwe3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDcwKVxuICAgICAgKjE3LjgtMTQqYFwifX1cbiAgICBzdHlsZSA3MCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA3MltbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg3MilcbiAgICAgICoxNy44LTE0KlxuICAgICg2OSwgNzApYFwiXV1cbiAgICBzdHlsZSA3MiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA3NChbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNzQpXG4gICAgICAqMTcuMTctMjEqYFwiXSlcbiAgICBzdHlsZSA3NCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA3NXt7XCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg3NSlcbiAgICAgICoxNy4xNy0yMypgXCJ9fVxuICAgIHN0eWxlIDc1IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDc3W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDc3KVxuICAgICAgKjE3LjE3LTIzKlxuICAgICg3NCwgNzUpYFwiXV1cbiAgICBzdHlsZSA3NyBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA3OVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHBvaW50c1xuICAgICAgKDc5KVxuICAgICAgKjE3LjEtMjQqXG4gICAgKDcyLCA3NylgXCJdXVxuICAgIHN0eWxlIDc5IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDgyKFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg4MilcbiAgICAgICoxOS4xMi0xNipgXCJdKVxuICAgIHN0eWxlIDgyIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDgze3tcImAjOTE7UlN5bWJvbCM5Mzsga1xuICAgICAgKDgzKVxuICAgICAgKjE5LjEyLTE4KmBcIn19XG4gICAgc3R5bGUgODMgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgODVbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoODUpXG4gICAgICAqMTkuMTItMTgqXG4gICAgKDgyLCA4MylgXCJdXVxuICAgIHN0eWxlIDg1IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDg3W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbWVhblxuICAgICAgKDg3KVxuICAgICAgKjE5LjctMTkqXG4gICAgKDg1KWBcIl1dXG4gICAgc3R5bGUgODcgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgODlbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwcmludFxuICAgICAgKDg5KVxuICAgICAgKjE5LjEtMjAqXG4gICAgKDg3KWBcIl1dXG4gICAgc3R5bGUgODkgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMyAtLT58XCJhcmd1bWVudFwifCAxXG4gICAgNyAtLT58XCJhcmd1bWVudFwifCA1XG4gICAgMTEgLS0+fFwiYXJndW1lbnRcInwgOVxuICAgIDE2IC0tPnxcImFyZ3VtZW50XCJ8IDE0XG4gICAgMTIgLS0+fFwiZGVmaW5lZC1ieVwifCAxNlxuICAgIDEyIC0tPnxcImRlZmluZWQtYnlcInwgMTdcbiAgICAxNyAtLT58XCJhcmd1bWVudFwifCAxNlxuICAgIDE3IC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDEyXG4gICAgMjIgLS0+fFwiYXJndW1lbnRcInwgMjBcbiAgICAxOCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDIyXG4gICAgMTggLS0+fFwiZGVmaW5lZC1ieVwifCAyM1xuICAgIDIzIC0tPnxcImFyZ3VtZW50XCJ8IDIyXG4gICAgMjMgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMThcbiAgICAyNiAtLT58XCJyZWFkc1wifCAxMlxuICAgIDI5IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCAyNlxuICAgIDI5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCAyN1xuICAgIDMxIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCAyOVxuICAgIDI0IC0tPnxcImRlZmluZWQtYnlcInwgMzFcbiAgICAyNCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDMyXG4gICAgMzIgLS0+fFwiYXJndW1lbnRcInwgMzFcbiAgICAzMiAtLT58XCJyZXR1cm5zLCBhcmd1bWVudFwifCAyNFxuICAgIDM0IC0tPnxcInJlYWRzXCJ8IDI0XG4gICAgMzYgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDM0XG4gICAgMzggLS0+fFwicmVhZHNcInwgMTJcbiAgICA0NCAtLT58XCJyZWFkc1wifCA0M1xuICAgIDQ3IC0tPnxcInJlYWRzXCJ8IDQ2XG4gICAgNDggLS0+fFwicmVhZHNcInwgNDNcbiAgICA0OCAtLT58XCJhcmd1bWVudFwifCA0NFxuICAgIDQ4IC0tPnxcInJlYWRzXCJ8IDQ2XG4gICAgNDggLS0+fFwiYXJndW1lbnRcInwgNDdcbiAgICA1MCAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNDhcbiAgICA1MCAtLT58XCJhcmd1bWVudFwifCAzOFxuICAgIDUyIC0tPnxcImFyZ3VtZW50XCJ8IDM4XG4gICAgNTIgLS0+fFwiYXJndW1lbnRcInwgNTBcbiAgICA1NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNTJcbiAgICA1NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNTRcbiAgICA1NyAtLT58XCJyZWFkc1wifCAxOFxuICAgIDYwIC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA1N1xuICAgIDYwIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA1OFxuICAgIDYyIC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNjUgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDYyXG4gICAgNjUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDYzXG4gICAgNjcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDYwXG4gICAgNjcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDY1XG4gICAgNjkgLS0+fFwicmVhZHNcInwgMThcbiAgICA3MiAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNjlcbiAgICA3MiAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzBcbiAgICA3NCAtLT58XCJyZWFkc1wifCAxOFxuICAgIDc3IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA3NFxuICAgIDc3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3NVxuICAgIDc5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3MlxuICAgIDc5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3N1xuICAgIDgyIC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgODUgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDgyXG4gICAgODUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDgzXG4gICAgODcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDg1XG4gICAgODkgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDg3IiwibWVybWFpZCI6eyJhdXRvU3luYyI6dHJ1ZX19))\
╰ {55, 52, 38, 12, 16, 14, ... (see JSON below)} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JTeW1ib2wjOTM7IGdncGxvdFxuICAgICAgKDEpXG4gICAgICAqMS45LTE0KmBcIn19XG4gICAgM1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgzKVxuICAgICAgKjEuMS0xNSpcbiAgICAoMSlgXCJdXVxuICAgIHN0eWxlIDMgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICA1e3tcImAjOTE7UlN5bWJvbCM5MzsgZHBseXJcbiAgICAgICg1KVxuICAgICAgKjIuOS0xMypgXCJ9fVxuICAgIDdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBsaWJyYXJ5XG4gICAgICAoNylcbiAgICAgICoyLjEtMTQqXG4gICAgKDUpYFwiXV1cbiAgICBzdHlsZSA3IHN0cm9rZTpyZWQsc3Ryb2tlLXdpZHRoOjVweDsgXG4gICAgOXt7XCJgIzkxO1JTeW1ib2wjOTM7IHJlYWRyXG4gICAgICAoOSlcbiAgICAgICozLjktMTMqYFwifX1cbiAgICAxMVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgxMSlcbiAgICAgICozLjEtMTQqXG4gICAgKDkpYFwiXV1cbiAgICBzdHlsZSAxMSBzdHJva2U6cmVkLHN0cm9rZS13aWR0aDo1cHg7IFxuICAgIDE0e3tcImAjOTE7UlN0cmluZyM5MzsgIzM5O2RhdGEuY3N2IzM5O1xuICAgICAgKDE0KVxuICAgICAgKjYuMTgtMjcqYFwifX1cbiAgICBzdHlsZSAxNCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAxNltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHJlYWQjOTU7Y3N2XG4gICAgICAoMTYpXG4gICAgICAqNi45LTI4KlxuICAgICgxNClgXCJdXVxuICAgIHN0eWxlIDE2IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDEyW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMTIpXG4gICAgICAqNi4xLTQqYFwiXVxuICAgIHN0eWxlIDEyIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDE3W1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDE3KVxuICAgICAgKjYuMS0yOCpcbiAgICAoMTIsIDE2KWBcIl1dXG4gICAgc3R5bGUgMTcgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMjB7e1wiYCM5MTtSU3RyaW5nIzkzOyAjMzk7ZGF0YTIuY3N2IzM5O1xuICAgICAgKDIwKVxuICAgICAgKjcuMTktMjkqYFwifX1cbiAgICAyMltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHJlYWQjOTU7Y3N2XG4gICAgICAoMjIpXG4gICAgICAqNy4xMC0zMCpcbiAgICAoMjApYFwiXV1cbiAgICAxOFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICgxOClcbiAgICAgICo3LjEtNSpgXCJdXG4gICAgMjNbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMjMpXG4gICAgICAqNy4xLTMwKlxuICAgICgxOCwgMjIpYFwiXV1cbiAgICAyNihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGFcbiAgICAgICgyNilcbiAgICAgICo5LjExLTE0KmBcIl0pXG4gICAgc3R5bGUgMjYgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMjd7e1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoMjcpXG4gICAgICAqOS4xMS0xNipgXCJ9fVxuICAgIHN0eWxlIDI3IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDI5W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDI5KVxuICAgICAgKjkuMTEtMTYqXG4gICAgKDI2LCAyNylgXCJdXVxuICAgIHN0eWxlIDI5IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDMxW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbWVhblxuICAgICAgKDMxKVxuICAgICAgKjkuNi0xNypcbiAgICAoMjkpYFwiXV1cbiAgICBzdHlsZSAzMSBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAyNFtcImAjOTE7UlN5bWJvbCM5MzsgbVxuICAgICAgKDI0KVxuICAgICAgKjkuMSpgXCJdXG4gICAgc3R5bGUgMjQgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMzJbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMzIpXG4gICAgICAqOS4xLTE3KlxuICAgICgyNCwgMzEpYFwiXV1cbiAgICBzdHlsZSAzMiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAzNChbXCJgIzkxO1JTeW1ib2wjOTM7IG1cbiAgICAgICgzNClcbiAgICAgICoxMC43KmBcIl0pXG4gICAgc3R5bGUgMzQgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgMzZbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwcmludFxuICAgICAgKDM2KVxuICAgICAgKjEwLjEtOCpcbiAgICAoMzQpYFwiXV1cbiAgICBzdHlsZSAzNiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAzOChbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGFcbiAgICAgICgzOClcbiAgICAgICoxMi4xLTQqYFwiXSlcbiAgICBzdHlsZSAzOCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA0MyhbXCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg0MylcbiAgICAgICoxMy4yNCpgXCJdKVxuICAgIHN0eWxlIDQzIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDQ0KFtcImAjOTE7UkFyZ3VtZW50IzkzOyB4XG4gICAgICAoNDQpXG4gICAgICAqMTMuMjAqYFwiXSlcbiAgICBzdHlsZSA0NCBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA0NihbXCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg0NilcbiAgICAgICoxMy4zMSpgXCJdKVxuICAgIHN0eWxlIDQ2IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDQ3KFtcImAjOTE7UkFyZ3VtZW50IzkzOyB5XG4gICAgICAoNDcpXG4gICAgICAqMTMuMjcqYFwiXSlcbiAgICBzdHlsZSA0NyBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA0OFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGFlc1xuICAgICAgKDQ4KVxuICAgICAgKjEzLjE2LTMyKlxuICAgICh4ICg0NCksIHkgKDQ3KSlgXCJdXVxuICAgIHN0eWxlIDQ4IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDUwW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgZ2dwbG90XG4gICAgICAoNTApXG4gICAgICAqMTMuOS0zMypcbiAgICAoMzgsIDQ4KWBcIl1dXG4gICAgc3R5bGUgNTAgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgNTJbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBkYXRhICUjNjI7JVxuXHRnZ3Bsb3QoYWVzKHggPSB4LCB5ID0geSkpXG4gICAgICAoNTIpXG4gICAgICAqMTIuNi04KlxuICAgICgzOCwgNTApYFwiXV1cbiAgICBzdHlsZSA1MiBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA1NFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGdlb20jOTU7cG9pbnRcbiAgICAgICg1NClcbiAgICAgICoxNC45LTIwKmBcIl1dXG4gICAgc3R5bGUgNTQgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgNTVbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM0MztcbiAgICAgICg1NSlcbiAgICAgICoxMi4xLTE0LjIwKlxuICAgICg1MiwgNTQpYFwiXV1cbiAgICBzdHlsZSA1NSBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICA1NyhbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNTcpXG4gICAgICAqMTYuNi0xMCpgXCJdKVxuICAgIDU4e3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDU4KVxuICAgICAgKjE2LjYtMTIqYFwifX1cbiAgICA2MFtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg2MClcbiAgICAgICoxNi42LTEyKlxuICAgICg1NywgNTgpYFwiXV1cbiAgICA2MihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNjIpXG4gICAgICAqMTYuMTUtMTkqYFwiXSlcbiAgICA2M3t7XCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg2MylcbiAgICAgICoxNi4xNS0yMSpgXCJ9fVxuICAgIDY1W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDY1KVxuICAgICAgKjE2LjE1LTIxKlxuICAgICg2MiwgNjMpYFwiXV1cbiAgICA2N1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHBsb3RcbiAgICAgICg2NylcbiAgICAgICoxNi4xLTIyKlxuICAgICg2MCwgNjUpYFwiXV1cbiAgICA2OShbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNjkpXG4gICAgICAqMTcuOC0xMipgXCJdKVxuICAgIDcwe3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDcwKVxuICAgICAgKjE3LjgtMTQqYFwifX1cbiAgICA3MltbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg3MilcbiAgICAgICoxNy44LTE0KlxuICAgICg2OSwgNzApYFwiXV1cbiAgICA3NChbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoNzQpXG4gICAgICAqMTcuMTctMjEqYFwiXSlcbiAgICA3NXt7XCJgIzkxO1JTeW1ib2wjOTM7IHlcbiAgICAgICg3NSlcbiAgICAgICoxNy4xNy0yMypgXCJ9fVxuICAgIDc3W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDc3KVxuICAgICAgKjE3LjE3LTIzKlxuICAgICg3NCwgNzUpYFwiXV1cbiAgICA3OVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHBvaW50c1xuICAgICAgKDc5KVxuICAgICAgKjE3LjEtMjQqXG4gICAgKDcyLCA3NylgXCJdXVxuICAgIDgyKFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg4MilcbiAgICAgICoxOS4xMi0xNipgXCJdKVxuICAgIDgze3tcImAjOTE7UlN5bWJvbCM5Mzsga1xuICAgICAgKDgzKVxuICAgICAgKjE5LjEyLTE4KmBcIn19XG4gICAgODVbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoODUpXG4gICAgICAqMTkuMTItMTgqXG4gICAgKDgyLCA4MylgXCJdXVxuICAgIDg3W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbWVhblxuICAgICAgKDg3KVxuICAgICAgKjE5LjctMTkqXG4gICAgKDg1KWBcIl1dXG4gICAgODlbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwcmludFxuICAgICAgKDg5KVxuICAgICAgKjE5LjEtMjAqXG4gICAgKDg3KWBcIl1dXG4gICAgMyAtLT58XCJhcmd1bWVudFwifCAxXG4gICAgNyAtLT58XCJhcmd1bWVudFwifCA1XG4gICAgMTEgLS0+fFwiYXJndW1lbnRcInwgOVxuICAgIDE2IC0tPnxcImFyZ3VtZW50XCJ8IDE0XG4gICAgMTIgLS0+fFwiZGVmaW5lZC1ieVwifCAxNlxuICAgIDEyIC0tPnxcImRlZmluZWQtYnlcInwgMTdcbiAgICAxNyAtLT58XCJhcmd1bWVudFwifCAxNlxuICAgIDE3IC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDEyXG4gICAgMjIgLS0+fFwiYXJndW1lbnRcInwgMjBcbiAgICAxOCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDIyXG4gICAgMTggLS0+fFwiZGVmaW5lZC1ieVwifCAyM1xuICAgIDIzIC0tPnxcImFyZ3VtZW50XCJ8IDIyXG4gICAgMjMgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMThcbiAgICAyNiAtLT58XCJyZWFkc1wifCAxMlxuICAgIDI5IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCAyNlxuICAgIDI5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCAyN1xuICAgIDMxIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCAyOVxuICAgIDI0IC0tPnxcImRlZmluZWQtYnlcInwgMzFcbiAgICAyNCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDMyXG4gICAgMzIgLS0+fFwiYXJndW1lbnRcInwgMzFcbiAgICAzMiAtLT58XCJyZXR1cm5zLCBhcmd1bWVudFwifCAyNFxuICAgIDM0IC0tPnxcInJlYWRzXCJ8IDI0XG4gICAgMzYgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDM0XG4gICAgMzggLS0+fFwicmVhZHNcInwgMTJcbiAgICA0NCAtLT58XCJyZWFkc1wifCA0M1xuICAgIDQ3IC0tPnxcInJlYWRzXCJ8IDQ2XG4gICAgNDggLS0+fFwicmVhZHNcInwgNDNcbiAgICA0OCAtLT58XCJhcmd1bWVudFwifCA0NFxuICAgIDQ4IC0tPnxcInJlYWRzXCJ8IDQ2XG4gICAgNDggLS0+fFwiYXJndW1lbnRcInwgNDdcbiAgICA1MCAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNDhcbiAgICA1MCAtLT58XCJhcmd1bWVudFwifCAzOFxuICAgIDUyIC0tPnxcImFyZ3VtZW50XCJ8IDM4XG4gICAgNTIgLS0+fFwiYXJndW1lbnRcInwgNTBcbiAgICA1NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNTJcbiAgICA1NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNTRcbiAgICA1NyAtLT58XCJyZWFkc1wifCAxOFxuICAgIDYwIC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA1N1xuICAgIDYwIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA1OFxuICAgIDYyIC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNjUgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDYyXG4gICAgNjUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDYzXG4gICAgNjcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDYwXG4gICAgNjcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDY1XG4gICAgNjkgLS0+fFwicmVhZHNcInwgMThcbiAgICA3MiAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNjlcbiAgICA3MiAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzBcbiAgICA3NCAtLT58XCJyZWFkc1wifCAxOFxuICAgIDc3IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA3NFxuICAgIDc3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3NVxuICAgIDc5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3MlxuICAgIDc5IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3N1xuICAgIDgyIC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgODUgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDgyXG4gICAgODUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDgzXG4gICAgODcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDg1XG4gICAgODkgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDg3IiwibWVybWFpZCI6eyJhdXRvU3luYyI6dHJ1ZX19))\
╰ (has unknown side effect) {11, 9} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JTeW1ib2wjOTM7IGdncGxvdFxuICAgICAgKDEpXG4gICAgICAqMS45LTE0KmBcIn19XG4gICAgM1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgzKVxuICAgICAgKjEuMS0xNSpcbiAgICAoMSlgXCJdXVxuICAgIHN0eWxlIDMgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICA1e3tcImAjOTE7UlN5bWJvbCM5MzsgZHBseXJcbiAgICAgICg1KVxuICAgICAgKjIuOS0xMypgXCJ9fVxuICAgIDdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBsaWJyYXJ5XG4gICAgICAoNylcbiAgICAgICoyLjEtMTQqXG4gICAgKDUpYFwiXV1cbiAgICBzdHlsZSA3IHN0cm9rZTpyZWQsc3Ryb2tlLXdpZHRoOjVweDsgXG4gICAgOXt7XCJgIzkxO1JTeW1ib2wjOTM7IHJlYWRyXG4gICAgICAoOSlcbiAgICAgICozLjktMTMqYFwifX1cbiAgICBzdHlsZSA5IHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIDExW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbGlicmFyeVxuICAgICAgKDExKVxuICAgICAgKjMuMS0xNCpcbiAgICAoOSlgXCJdXVxuICAgIHN0eWxlIDExIHN0cm9rZTp0ZWFsLHN0cm9rZS13aWR0aDo3cHgsc3Ryb2tlLW9wYWNpdHk6Ljg7IFxuICAgIHN0eWxlIDExIHN0cm9rZTpyZWQsc3Ryb2tlLXdpZHRoOjVweDsgXG4gICAgMTR7e1wiYCM5MTtSU3RyaW5nIzkzOyAjMzk7ZGF0YS5jc3YjMzk7XG4gICAgICAoMTQpXG4gICAgICAqNi4xOC0yNypgXCJ9fVxuICAgIDE2W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcmVhZCM5NTtjc3ZcbiAgICAgICgxNilcbiAgICAgICo2LjktMjgqXG4gICAgKDE0KWBcIl1dXG4gICAgMTJbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGFcbiAgICAgICgxMilcbiAgICAgICo2LjEtNCpgXCJdXG4gICAgMTdbW1wiYCM5MTtSQmluYXJ5T3AjOTM7ICM2MDsjNDU7XG4gICAgICAoMTcpXG4gICAgICAqNi4xLTI4KlxuICAgICgxMiwgMTYpYFwiXV1cbiAgICAyMHt7XCJgIzkxO1JTdHJpbmcjOTM7ICMzOTtkYXRhMi5jc3YjMzk7XG4gICAgICAoMjApXG4gICAgICAqNy4xOS0yOSpgXCJ9fVxuICAgIDIyW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcmVhZCM5NTtjc3ZcbiAgICAgICgyMilcbiAgICAgICo3LjEwLTMwKlxuICAgICgyMClgXCJdXVxuICAgIDE4W1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDE4KVxuICAgICAgKjcuMS01KmBcIl1cbiAgICAyM1tbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzYwOyM0NTtcbiAgICAgICgyMylcbiAgICAgICo3LjEtMzAqXG4gICAgKDE4LCAyMilgXCJdXVxuICAgIDI2KFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YVxuICAgICAgKDI2KVxuICAgICAgKjkuMTEtMTQqYFwiXSlcbiAgICAyN3t7XCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICgyNylcbiAgICAgICo5LjExLTE2KmBcIn19XG4gICAgMjlbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoMjkpXG4gICAgICAqOS4xMS0xNipcbiAgICAoMjYsIDI3KWBcIl1dXG4gICAgMzFbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBtZWFuXG4gICAgICAoMzEpXG4gICAgICAqOS42LTE3KlxuICAgICgyOSlgXCJdXVxuICAgIDI0W1wiYCM5MTtSU3ltYm9sIzkzOyBtXG4gICAgICAoMjQpXG4gICAgICAqOS4xKmBcIl1cbiAgICAzMltbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzYwOyM0NTtcbiAgICAgICgzMilcbiAgICAgICo5LjEtMTcqXG4gICAgKDI0LCAzMSlgXCJdXVxuICAgIDM0KFtcImAjOTE7UlN5bWJvbCM5MzsgbVxuICAgICAgKDM0KVxuICAgICAgKjEwLjcqYFwiXSlcbiAgICAzNltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHByaW50XG4gICAgICAoMzYpXG4gICAgICAqMTAuMS04KlxuICAgICgzNClgXCJdXVxuICAgIDM4KFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YVxuICAgICAgKDM4KVxuICAgICAgKjEyLjEtNCpgXCJdKVxuICAgIDQzKFtcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDQzKVxuICAgICAgKjEzLjI0KmBcIl0pXG4gICAgNDQoW1wiYCM5MTtSQXJndW1lbnQjOTM7IHhcbiAgICAgICg0NClcbiAgICAgICoxMy4yMCpgXCJdKVxuICAgIDQ2KFtcImAjOTE7UlN5bWJvbCM5MzsgeVxuICAgICAgKDQ2KVxuICAgICAgKjEzLjMxKmBcIl0pXG4gICAgNDcoW1wiYCM5MTtSQXJndW1lbnQjOTM7IHlcbiAgICAgICg0NylcbiAgICAgICoxMy4yNypgXCJdKVxuICAgIDQ4W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgYWVzXG4gICAgICAoNDgpXG4gICAgICAqMTMuMTYtMzIqXG4gICAgKHggKDQ0KSwgeSAoNDcpKWBcIl1dXG4gICAgNTBbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBnZ3Bsb3RcbiAgICAgICg1MClcbiAgICAgICoxMy45LTMzKlxuICAgICgzOCwgNDgpYFwiXV1cbiAgICA1MltbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGRhdGEgJSM2MjslXG5cdGdncGxvdChhZXMoeCA9IHgsIHkgPSB5KSlcbiAgICAgICg1MilcbiAgICAgICoxMi42LTgqXG4gICAgKDM4LCA1MClgXCJdXVxuICAgIDU0W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgZ2VvbSM5NTtwb2ludFxuICAgICAgKDU0KVxuICAgICAgKjE0LjktMjAqYFwiXV1cbiAgICA1NVtbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzQzO1xuICAgICAgKDU1KVxuICAgICAgKjEyLjEtMTQuMjAqXG4gICAgKDUyLCA1NClgXCJdXVxuICAgIDU3KFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg1NylcbiAgICAgICoxNi42LTEwKmBcIl0pXG4gICAgNTh7e1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoNTgpXG4gICAgICAqMTYuNi0xMipgXCJ9fVxuICAgIDYwW1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDYwKVxuICAgICAgKjE2LjYtMTIqXG4gICAgKDU3LCA1OClgXCJdXVxuICAgIDYyKFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg2MilcbiAgICAgICoxNi4xNS0xOSpgXCJdKVxuICAgIDYze3tcImAjOTE7UlN5bWJvbCM5MzsgeVxuICAgICAgKDYzKVxuICAgICAgKjE2LjE1LTIxKmBcIn19XG4gICAgNjVbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNjUpXG4gICAgICAqMTYuMTUtMjEqXG4gICAgKDYyLCA2MylgXCJdXVxuICAgIDY3W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcGxvdFxuICAgICAgKDY3KVxuICAgICAgKjE2LjEtMjIqXG4gICAgKDYwLCA2NSlgXCJdXVxuICAgIDY5KFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg2OSlcbiAgICAgICoxNy44LTEyKmBcIl0pXG4gICAgNzB7e1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoNzApXG4gICAgICAqMTcuOC0xNCpgXCJ9fVxuICAgIDcyW1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDcyKVxuICAgICAgKjE3LjgtMTQqXG4gICAgKDY5LCA3MClgXCJdXVxuICAgIDc0KFtcImAjOTE7UlN5bWJvbCM5MzsgZGF0YTJcbiAgICAgICg3NClcbiAgICAgICoxNy4xNy0yMSpgXCJdKVxuICAgIDc1e3tcImAjOTE7UlN5bWJvbCM5MzsgeVxuICAgICAgKDc1KVxuICAgICAgKjE3LjE3LTIzKmBcIn19XG4gICAgNzdbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNzcpXG4gICAgICAqMTcuMTctMjMqXG4gICAgKDc0LCA3NSlgXCJdXVxuICAgIDc5W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcG9pbnRzXG4gICAgICAoNzkpXG4gICAgICAqMTcuMS0yNCpcbiAgICAoNzIsIDc3KWBcIl1dXG4gICAgODIoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDgyKVxuICAgICAgKjE5LjEyLTE2KmBcIl0pXG4gICAgODN7e1wiYCM5MTtSU3ltYm9sIzkzOyBrXG4gICAgICAoODMpXG4gICAgICAqMTkuMTItMTgqYFwifX1cbiAgICA4NVtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg4NSlcbiAgICAgICoxOS4xMi0xOCpcbiAgICAoODIsIDgzKWBcIl1dXG4gICAgODdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBtZWFuXG4gICAgICAoODcpXG4gICAgICAqMTkuNy0xOSpcbiAgICAoODUpYFwiXV1cbiAgICA4OVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IHByaW50XG4gICAgICAoODkpXG4gICAgICAqMTkuMS0yMCpcbiAgICAoODcpYFwiXV1cbiAgICAzIC0tPnxcImFyZ3VtZW50XCJ8IDFcbiAgICA3IC0tPnxcImFyZ3VtZW50XCJ8IDVcbiAgICAxMSAtLT58XCJhcmd1bWVudFwifCA5XG4gICAgMTYgLS0+fFwiYXJndW1lbnRcInwgMTRcbiAgICAxMiAtLT58XCJkZWZpbmVkLWJ5XCJ8IDE2XG4gICAgMTIgLS0+fFwiZGVmaW5lZC1ieVwifCAxN1xuICAgIDE3IC0tPnxcImFyZ3VtZW50XCJ8IDE2XG4gICAgMTcgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMTJcbiAgICAyMiAtLT58XCJhcmd1bWVudFwifCAyMFxuICAgIDE4IC0tPnxcImRlZmluZWQtYnlcInwgMjJcbiAgICAxOCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDIzXG4gICAgMjMgLS0+fFwiYXJndW1lbnRcInwgMjJcbiAgICAyMyAtLT58XCJyZXR1cm5zLCBhcmd1bWVudFwifCAxOFxuICAgIDI2IC0tPnxcInJlYWRzXCJ8IDEyXG4gICAgMjkgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDI2XG4gICAgMjkgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDI3XG4gICAgMzEgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDI5XG4gICAgMjQgLS0+fFwiZGVmaW5lZC1ieVwifCAzMVxuICAgIDI0IC0tPnxcImRlZmluZWQtYnlcInwgMzJcbiAgICAzMiAtLT58XCJhcmd1bWVudFwifCAzMVxuICAgIDMyIC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDI0XG4gICAgMzQgLS0+fFwicmVhZHNcInwgMjRcbiAgICAzNiAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgMzRcbiAgICAzOCAtLT58XCJyZWFkc1wifCAxMlxuICAgIDQ0IC0tPnxcInJlYWRzXCJ8IDQzXG4gICAgNDcgLS0+fFwicmVhZHNcInwgNDZcbiAgICA0OCAtLT58XCJyZWFkc1wifCA0M1xuICAgIDQ4IC0tPnxcImFyZ3VtZW50XCJ8IDQ0XG4gICAgNDggLS0+fFwicmVhZHNcInwgNDZcbiAgICA0OCAtLT58XCJhcmd1bWVudFwifCA0N1xuICAgIDUwIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA0OFxuICAgIDUwIC0tPnxcImFyZ3VtZW50XCJ8IDM4XG4gICAgNTIgLS0+fFwiYXJndW1lbnRcInwgMzhcbiAgICA1MiAtLT58XCJhcmd1bWVudFwifCA1MFxuICAgIDU1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA1MlxuICAgIDU1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA1NFxuICAgIDU3IC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNjAgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDU3XG4gICAgNjAgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDU4XG4gICAgNjIgLS0+fFwicmVhZHNcInwgMThcbiAgICA2NSAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNjJcbiAgICA2NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNjNcbiAgICA2NyAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNjBcbiAgICA2NyAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNjVcbiAgICA2OSAtLT58XCJyZWFkc1wifCAxOFxuICAgIDcyIC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA2OVxuICAgIDcyIC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA3MFxuICAgIDc0IC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNzcgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDc0XG4gICAgNzcgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDc1XG4gICAgNzkgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDcyXG4gICAgNzkgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDc3XG4gICAgODIgLS0+fFwicmVhZHNcInwgMThcbiAgICA4NSAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgODJcbiAgICA4NSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgODNcbiAgICA4NyAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgODVcbiAgICA4OSAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgODciLCJtZXJtYWlkIjp7ImF1dG9TeW5jIjp0cnVlfX0=))\
╰ (has unknown side effect) {7, 5} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JTeW1ib2wjOTM7IGdncGxvdFxuICAgICAgKDEpXG4gICAgICAqMS45LTE0KmBcIn19XG4gICAgM1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICgzKVxuICAgICAgKjEuMS0xNSpcbiAgICAoMSlgXCJdXVxuICAgIHN0eWxlIDMgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICA1e3tcImAjOTE7UlN5bWJvbCM5MzsgZHBseXJcbiAgICAgICg1KVxuICAgICAgKjIuOS0xMypgXCJ9fVxuICAgIHN0eWxlIDUgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgN1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGxpYnJhcnlcbiAgICAgICg3KVxuICAgICAgKjIuMS0xNCpcbiAgICAoNSlgXCJdXVxuICAgIHN0eWxlIDcgc3Ryb2tlOnRlYWwsc3Ryb2tlLXdpZHRoOjdweCxzdHJva2Utb3BhY2l0eTouODsgXG4gICAgc3R5bGUgNyBzdHJva2U6cmVkLHN0cm9rZS13aWR0aDo1cHg7IFxuICAgIDl7e1wiYCM5MTtSU3ltYm9sIzkzOyByZWFkclxuICAgICAgKDkpXG4gICAgICAqMy45LTEzKmBcIn19XG4gICAgMTFbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBsaWJyYXJ5XG4gICAgICAoMTEpXG4gICAgICAqMy4xLTE0KlxuICAgICg5KWBcIl1dXG4gICAgc3R5bGUgMTEgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICAxNHt7XCJgIzkxO1JTdHJpbmcjOTM7ICMzOTtkYXRhLmNzdiMzOTtcbiAgICAgICgxNClcbiAgICAgICo2LjE4LTI3KmBcIn19XG4gICAgMTZbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyByZWFkIzk1O2NzdlxuICAgICAgKDE2KVxuICAgICAgKjYuOS0yOCpcbiAgICAoMTQpYFwiXV1cbiAgICAxMltcImAjOTE7UlN5bWJvbCM5MzsgZGF0YVxuICAgICAgKDEyKVxuICAgICAgKjYuMS00KmBcIl1cbiAgICAxN1tbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzYwOyM0NTtcbiAgICAgICgxNylcbiAgICAgICo2LjEtMjgqXG4gICAgKDEyLCAxNilgXCJdXVxuICAgIDIwe3tcImAjOTE7UlN0cmluZyM5MzsgIzM5O2RhdGEyLmNzdiMzOTtcbiAgICAgICgyMClcbiAgICAgICo3LjE5LTI5KmBcIn19XG4gICAgMjJbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyByZWFkIzk1O2NzdlxuICAgICAgKDIyKVxuICAgICAgKjcuMTAtMzAqXG4gICAgKDIwKWBcIl1dXG4gICAgMThbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoMTgpXG4gICAgICAqNy4xLTUqYFwiXVxuICAgIDIzW1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDIzKVxuICAgICAgKjcuMS0zMCpcbiAgICAoMTgsIDIyKWBcIl1dXG4gICAgMjYoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMjYpXG4gICAgICAqOS4xMS0xNCpgXCJdKVxuICAgIDI3e3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDI3KVxuICAgICAgKjkuMTEtMTYqYFwifX1cbiAgICAyOVtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICgyOSlcbiAgICAgICo5LjExLTE2KlxuICAgICgyNiwgMjcpYFwiXV1cbiAgICAzMVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IG1lYW5cbiAgICAgICgzMSlcbiAgICAgICo5LjYtMTcqXG4gICAgKDI5KWBcIl1dXG4gICAgMjRbXCJgIzkxO1JTeW1ib2wjOTM7IG1cbiAgICAgICgyNClcbiAgICAgICo5LjEqYFwiXVxuICAgIDMyW1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDMyKVxuICAgICAgKjkuMS0xNypcbiAgICAoMjQsIDMxKWBcIl1dXG4gICAgMzQoW1wiYCM5MTtSU3ltYm9sIzkzOyBtXG4gICAgICAoMzQpXG4gICAgICAqMTAuNypgXCJdKVxuICAgIDM2W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcHJpbnRcbiAgICAgICgzNilcbiAgICAgICoxMC4xLTgqXG4gICAgKDM0KWBcIl1dXG4gICAgMzgoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMzgpXG4gICAgICAqMTIuMS00KmBcIl0pXG4gICAgNDMoW1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoNDMpXG4gICAgICAqMTMuMjQqYFwiXSlcbiAgICA0NChbXCJgIzkxO1JBcmd1bWVudCM5MzsgeFxuICAgICAgKDQ0KVxuICAgICAgKjEzLjIwKmBcIl0pXG4gICAgNDYoW1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNDYpXG4gICAgICAqMTMuMzEqYFwiXSlcbiAgICA0NyhbXCJgIzkxO1JBcmd1bWVudCM5MzsgeVxuICAgICAgKDQ3KVxuICAgICAgKjEzLjI3KmBcIl0pXG4gICAgNDhbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBhZXNcbiAgICAgICg0OClcbiAgICAgICoxMy4xNi0zMipcbiAgICAoeCAoNDQpLCB5ICg0NykpYFwiXV1cbiAgICA1MFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGdncGxvdFxuICAgICAgKDUwKVxuICAgICAgKjEzLjktMzMqXG4gICAgKDM4LCA0OClgXCJdXVxuICAgIDUyW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgZGF0YSAlIzYyOyVcblx0Z2dwbG90KGFlcyh4ID0geCwgeSA9IHkpKVxuICAgICAgKDUyKVxuICAgICAgKjEyLjYtOCpcbiAgICAoMzgsIDUwKWBcIl1dXG4gICAgNTRbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBnZW9tIzk1O3BvaW50XG4gICAgICAoNTQpXG4gICAgICAqMTQuOS0yMCpgXCJdXVxuICAgIDU1W1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNDM7XG4gICAgICAoNTUpXG4gICAgICAqMTIuMS0xNC4yMCpcbiAgICAoNTIsIDU0KWBcIl1dXG4gICAgNTcoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDU3KVxuICAgICAgKjE2LjYtMTAqYFwiXSlcbiAgICA1OHt7XCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg1OClcbiAgICAgICoxNi42LTEyKmBcIn19XG4gICAgNjBbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNjApXG4gICAgICAqMTYuNi0xMipcbiAgICAoNTcsIDU4KWBcIl1dXG4gICAgNjIoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDYyKVxuICAgICAgKjE2LjE1LTE5KmBcIl0pXG4gICAgNjN7e1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNjMpXG4gICAgICAqMTYuMTUtMjEqYFwifX1cbiAgICA2NVtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg2NSlcbiAgICAgICoxNi4xNS0yMSpcbiAgICAoNjIsIDYzKWBcIl1dXG4gICAgNjdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwbG90XG4gICAgICAoNjcpXG4gICAgICAqMTYuMS0yMipcbiAgICAoNjAsIDY1KWBcIl1dXG4gICAgNjkoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDY5KVxuICAgICAgKjE3LjgtMTIqYFwiXSlcbiAgICA3MHt7XCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg3MClcbiAgICAgICoxNy44LTE0KmBcIn19XG4gICAgNzJbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNzIpXG4gICAgICAqMTcuOC0xNCpcbiAgICAoNjksIDcwKWBcIl1dXG4gICAgNzQoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDc0KVxuICAgICAgKjE3LjE3LTIxKmBcIl0pXG4gICAgNzV7e1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNzUpXG4gICAgICAqMTcuMTctMjMqYFwifX1cbiAgICA3N1tbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg3NylcbiAgICAgICoxNy4xNy0yMypcbiAgICAoNzQsIDc1KWBcIl1dXG4gICAgNzlbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwb2ludHNcbiAgICAgICg3OSlcbiAgICAgICoxNy4xLTI0KlxuICAgICg3MiwgNzcpYFwiXV1cbiAgICA4MihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoODIpXG4gICAgICAqMTkuMTItMTYqYFwiXSlcbiAgICA4M3t7XCJgIzkxO1JTeW1ib2wjOTM7IGtcbiAgICAgICg4MylcbiAgICAgICoxOS4xMi0xOCpgXCJ9fVxuICAgIDg1W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDg1KVxuICAgICAgKjE5LjEyLTE4KlxuICAgICg4MiwgODMpYFwiXV1cbiAgICA4N1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IG1lYW5cbiAgICAgICg4NylcbiAgICAgICoxOS43LTE5KlxuICAgICg4NSlgXCJdXVxuICAgIDg5W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcHJpbnRcbiAgICAgICg4OSlcbiAgICAgICoxOS4xLTIwKlxuICAgICg4NylgXCJdXVxuICAgIDMgLS0+fFwiYXJndW1lbnRcInwgMVxuICAgIDcgLS0+fFwiYXJndW1lbnRcInwgNVxuICAgIDExIC0tPnxcImFyZ3VtZW50XCJ8IDlcbiAgICAxNiAtLT58XCJhcmd1bWVudFwifCAxNFxuICAgIDEyIC0tPnxcImRlZmluZWQtYnlcInwgMTZcbiAgICAxMiAtLT58XCJkZWZpbmVkLWJ5XCJ8IDE3XG4gICAgMTcgLS0+fFwiYXJndW1lbnRcInwgMTZcbiAgICAxNyAtLT58XCJyZXR1cm5zLCBhcmd1bWVudFwifCAxMlxuICAgIDIyIC0tPnxcImFyZ3VtZW50XCJ8IDIwXG4gICAgMTggLS0+fFwiZGVmaW5lZC1ieVwifCAyMlxuICAgIDE4IC0tPnxcImRlZmluZWQtYnlcInwgMjNcbiAgICAyMyAtLT58XCJhcmd1bWVudFwifCAyMlxuICAgIDIzIC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDE4XG4gICAgMjYgLS0+fFwicmVhZHNcInwgMTJcbiAgICAyOSAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgMjZcbiAgICAyOSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgMjdcbiAgICAzMSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgMjlcbiAgICAyNCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDMxXG4gICAgMjQgLS0+fFwiZGVmaW5lZC1ieVwifCAzMlxuICAgIDMyIC0tPnxcImFyZ3VtZW50XCJ8IDMxXG4gICAgMzIgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMjRcbiAgICAzNCAtLT58XCJyZWFkc1wifCAyNFxuICAgIDM2IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCAzNFxuICAgIDM4IC0tPnxcInJlYWRzXCJ8IDEyXG4gICAgNDQgLS0+fFwicmVhZHNcInwgNDNcbiAgICA0NyAtLT58XCJyZWFkc1wifCA0NlxuICAgIDQ4IC0tPnxcInJlYWRzXCJ8IDQzXG4gICAgNDggLS0+fFwiYXJndW1lbnRcInwgNDRcbiAgICA0OCAtLT58XCJyZWFkc1wifCA0NlxuICAgIDQ4IC0tPnxcImFyZ3VtZW50XCJ8IDQ3XG4gICAgNTAgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDQ4XG4gICAgNTAgLS0+fFwiYXJndW1lbnRcInwgMzhcbiAgICA1MiAtLT58XCJhcmd1bWVudFwifCAzOFxuICAgIDUyIC0tPnxcImFyZ3VtZW50XCJ8IDUwXG4gICAgNTUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDUyXG4gICAgNTUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDU0XG4gICAgNTcgLS0+fFwicmVhZHNcInwgMThcbiAgICA2MCAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNTdcbiAgICA2MCAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNThcbiAgICA2MiAtLT58XCJyZWFkc1wifCAxOFxuICAgIDY1IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA2MlxuICAgIDY1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2M1xuICAgIDY3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2MFxuICAgIDY3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2NVxuICAgIDY5IC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNzIgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDY5XG4gICAgNzIgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDcwXG4gICAgNzQgLS0+fFwicmVhZHNcInwgMThcbiAgICA3NyAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNzRcbiAgICA3NyAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzVcbiAgICA3OSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzJcbiAgICA3OSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzdcbiAgICA4MiAtLT58XCJyZWFkc1wifCAxOFxuICAgIDg1IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA4MlxuICAgIDg1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA4M1xuICAgIDg3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA4NVxuICAgIDg5IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA4NyIsIm1lcm1haWQiOnsiYXV0b1N5bmMiOnRydWV9fQ==))\
╰ (has unknown side effect) {3, 1} ([marked](https://mermaid.live/view#base64:eyJjb2RlIjoiZmxvd2NoYXJ0IFREXG4gICAgMXt7XCJgIzkxO1JTeW1ib2wjOTM7IGdncGxvdFxuICAgICAgKDEpXG4gICAgICAqMS45LTE0KmBcIn19XG4gICAgc3R5bGUgMSBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICAzW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbGlicmFyeVxuICAgICAgKDMpXG4gICAgICAqMS4xLTE1KlxuICAgICgxKWBcIl1dXG4gICAgc3R5bGUgMyBzdHJva2U6dGVhbCxzdHJva2Utd2lkdGg6N3B4LHN0cm9rZS1vcGFjaXR5Oi44OyBcbiAgICBzdHlsZSAzIHN0cm9rZTpyZWQsc3Ryb2tlLXdpZHRoOjVweDsgXG4gICAgNXt7XCJgIzkxO1JTeW1ib2wjOTM7IGRwbHlyXG4gICAgICAoNSlcbiAgICAgICoyLjktMTMqYFwifX1cbiAgICA3W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgbGlicmFyeVxuICAgICAgKDcpXG4gICAgICAqMi4xLTE0KlxuICAgICg1KWBcIl1dXG4gICAgc3R5bGUgNyBzdHJva2U6cmVkLHN0cm9rZS13aWR0aDo1cHg7IFxuICAgIDl7e1wiYCM5MTtSU3ltYm9sIzkzOyByZWFkclxuICAgICAgKDkpXG4gICAgICAqMy45LTEzKmBcIn19XG4gICAgMTFbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBsaWJyYXJ5XG4gICAgICAoMTEpXG4gICAgICAqMy4xLTE0KlxuICAgICg5KWBcIl1dXG4gICAgc3R5bGUgMTEgc3Ryb2tlOnJlZCxzdHJva2Utd2lkdGg6NXB4OyBcbiAgICAxNHt7XCJgIzkxO1JTdHJpbmcjOTM7ICMzOTtkYXRhLmNzdiMzOTtcbiAgICAgICgxNClcbiAgICAgICo2LjE4LTI3KmBcIn19XG4gICAgMTZbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyByZWFkIzk1O2NzdlxuICAgICAgKDE2KVxuICAgICAgKjYuOS0yOCpcbiAgICAoMTQpYFwiXV1cbiAgICAxMltcImAjOTE7UlN5bWJvbCM5MzsgZGF0YVxuICAgICAgKDEyKVxuICAgICAgKjYuMS00KmBcIl1cbiAgICAxN1tbXCJgIzkxO1JCaW5hcnlPcCM5MzsgIzYwOyM0NTtcbiAgICAgICgxNylcbiAgICAgICo2LjEtMjgqXG4gICAgKDEyLCAxNilgXCJdXVxuICAgIDIwe3tcImAjOTE7UlN0cmluZyM5MzsgIzM5O2RhdGEyLmNzdiMzOTtcbiAgICAgICgyMClcbiAgICAgICo3LjE5LTI5KmBcIn19XG4gICAgMjJbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyByZWFkIzk1O2NzdlxuICAgICAgKDIyKVxuICAgICAgKjcuMTAtMzAqXG4gICAgKDIwKWBcIl1dXG4gICAgMThbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoMTgpXG4gICAgICAqNy4xLTUqYFwiXVxuICAgIDIzW1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDIzKVxuICAgICAgKjcuMS0zMCpcbiAgICAoMTgsIDIyKWBcIl1dXG4gICAgMjYoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMjYpXG4gICAgICAqOS4xMS0xNCpgXCJdKVxuICAgIDI3e3tcImAjOTE7UlN5bWJvbCM5MzsgeFxuICAgICAgKDI3KVxuICAgICAgKjkuMTEtMTYqYFwifX1cbiAgICAyOVtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICgyOSlcbiAgICAgICo5LjExLTE2KlxuICAgICgyNiwgMjcpYFwiXV1cbiAgICAzMVtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IG1lYW5cbiAgICAgICgzMSlcbiAgICAgICo5LjYtMTcqXG4gICAgKDI5KWBcIl1dXG4gICAgMjRbXCJgIzkxO1JTeW1ib2wjOTM7IG1cbiAgICAgICgyNClcbiAgICAgICo5LjEqYFwiXVxuICAgIDMyW1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNjA7IzQ1O1xuICAgICAgKDMyKVxuICAgICAgKjkuMS0xNypcbiAgICAoMjQsIDMxKWBcIl1dXG4gICAgMzQoW1wiYCM5MTtSU3ltYm9sIzkzOyBtXG4gICAgICAoMzQpXG4gICAgICAqMTAuNypgXCJdKVxuICAgIDM2W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcHJpbnRcbiAgICAgICgzNilcbiAgICAgICoxMC4xLTgqXG4gICAgKDM0KWBcIl1dXG4gICAgMzgoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhXG4gICAgICAoMzgpXG4gICAgICAqMTIuMS00KmBcIl0pXG4gICAgNDMoW1wiYCM5MTtSU3ltYm9sIzkzOyB4XG4gICAgICAoNDMpXG4gICAgICAqMTMuMjQqYFwiXSlcbiAgICA0NChbXCJgIzkxO1JBcmd1bWVudCM5MzsgeFxuICAgICAgKDQ0KVxuICAgICAgKjEzLjIwKmBcIl0pXG4gICAgNDYoW1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNDYpXG4gICAgICAqMTMuMzEqYFwiXSlcbiAgICA0NyhbXCJgIzkxO1JBcmd1bWVudCM5MzsgeVxuICAgICAgKDQ3KVxuICAgICAgKjEzLjI3KmBcIl0pXG4gICAgNDhbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBhZXNcbiAgICAgICg0OClcbiAgICAgICoxMy4xNi0zMipcbiAgICAoeCAoNDQpLCB5ICg0NykpYFwiXV1cbiAgICA1MFtbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IGdncGxvdFxuICAgICAgKDUwKVxuICAgICAgKjEzLjktMzMqXG4gICAgKDM4LCA0OClgXCJdXVxuICAgIDUyW1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgZGF0YSAlIzYyOyVcblx0Z2dwbG90KGFlcyh4ID0geCwgeSA9IHkpKVxuICAgICAgKDUyKVxuICAgICAgKjEyLjYtOCpcbiAgICAoMzgsIDUwKWBcIl1dXG4gICAgNTRbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBnZW9tIzk1O3BvaW50XG4gICAgICAoNTQpXG4gICAgICAqMTQuOS0yMCpgXCJdXVxuICAgIDU1W1tcImAjOTE7UkJpbmFyeU9wIzkzOyAjNDM7XG4gICAgICAoNTUpXG4gICAgICAqMTIuMS0xNC4yMCpcbiAgICAoNTIsIDU0KWBcIl1dXG4gICAgNTcoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDU3KVxuICAgICAgKjE2LjYtMTAqYFwiXSlcbiAgICA1OHt7XCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg1OClcbiAgICAgICoxNi42LTEyKmBcIn19XG4gICAgNjBbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNjApXG4gICAgICAqMTYuNi0xMipcbiAgICAoNTcsIDU4KWBcIl1dXG4gICAgNjIoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDYyKVxuICAgICAgKjE2LjE1LTE5KmBcIl0pXG4gICAgNjN7e1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNjMpXG4gICAgICAqMTYuMTUtMjEqYFwifX1cbiAgICA2NVtbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg2NSlcbiAgICAgICoxNi4xNS0yMSpcbiAgICAoNjIsIDYzKWBcIl1dXG4gICAgNjdbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwbG90XG4gICAgICAoNjcpXG4gICAgICAqMTYuMS0yMipcbiAgICAoNjAsIDY1KWBcIl1dXG4gICAgNjkoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDY5KVxuICAgICAgKjE3LjgtMTIqYFwiXSlcbiAgICA3MHt7XCJgIzkxO1JTeW1ib2wjOTM7IHhcbiAgICAgICg3MClcbiAgICAgICoxNy44LTE0KmBcIn19XG4gICAgNzJbW1wiYCM5MTtSQWNjZXNzIzkzOyAkXG4gICAgICAoNzIpXG4gICAgICAqMTcuOC0xNCpcbiAgICAoNjksIDcwKWBcIl1dXG4gICAgNzQoW1wiYCM5MTtSU3ltYm9sIzkzOyBkYXRhMlxuICAgICAgKDc0KVxuICAgICAgKjE3LjE3LTIxKmBcIl0pXG4gICAgNzV7e1wiYCM5MTtSU3ltYm9sIzkzOyB5XG4gICAgICAoNzUpXG4gICAgICAqMTcuMTctMjMqYFwifX1cbiAgICA3N1tbXCJgIzkxO1JBY2Nlc3MjOTM7ICRcbiAgICAgICg3NylcbiAgICAgICoxNy4xNy0yMypcbiAgICAoNzQsIDc1KWBcIl1dXG4gICAgNzlbW1wiYCM5MTtSRnVuY3Rpb25DYWxsIzkzOyBwb2ludHNcbiAgICAgICg3OSlcbiAgICAgICoxNy4xLTI0KlxuICAgICg3MiwgNzcpYFwiXV1cbiAgICA4MihbXCJgIzkxO1JTeW1ib2wjOTM7IGRhdGEyXG4gICAgICAoODIpXG4gICAgICAqMTkuMTItMTYqYFwiXSlcbiAgICA4M3t7XCJgIzkxO1JTeW1ib2wjOTM7IGtcbiAgICAgICg4MylcbiAgICAgICoxOS4xMi0xOCpgXCJ9fVxuICAgIDg1W1tcImAjOTE7UkFjY2VzcyM5MzsgJFxuICAgICAgKDg1KVxuICAgICAgKjE5LjEyLTE4KlxuICAgICg4MiwgODMpYFwiXV1cbiAgICA4N1tbXCJgIzkxO1JGdW5jdGlvbkNhbGwjOTM7IG1lYW5cbiAgICAgICg4NylcbiAgICAgICoxOS43LTE5KlxuICAgICg4NSlgXCJdXVxuICAgIDg5W1tcImAjOTE7UkZ1bmN0aW9uQ2FsbCM5MzsgcHJpbnRcbiAgICAgICg4OSlcbiAgICAgICoxOS4xLTIwKlxuICAgICg4NylgXCJdXVxuICAgIDMgLS0+fFwiYXJndW1lbnRcInwgMVxuICAgIDcgLS0+fFwiYXJndW1lbnRcInwgNVxuICAgIDExIC0tPnxcImFyZ3VtZW50XCJ8IDlcbiAgICAxNiAtLT58XCJhcmd1bWVudFwifCAxNFxuICAgIDEyIC0tPnxcImRlZmluZWQtYnlcInwgMTZcbiAgICAxMiAtLT58XCJkZWZpbmVkLWJ5XCJ8IDE3XG4gICAgMTcgLS0+fFwiYXJndW1lbnRcInwgMTZcbiAgICAxNyAtLT58XCJyZXR1cm5zLCBhcmd1bWVudFwifCAxMlxuICAgIDIyIC0tPnxcImFyZ3VtZW50XCJ8IDIwXG4gICAgMTggLS0+fFwiZGVmaW5lZC1ieVwifCAyMlxuICAgIDE4IC0tPnxcImRlZmluZWQtYnlcInwgMjNcbiAgICAyMyAtLT58XCJhcmd1bWVudFwifCAyMlxuICAgIDIzIC0tPnxcInJldHVybnMsIGFyZ3VtZW50XCJ8IDE4XG4gICAgMjYgLS0+fFwicmVhZHNcInwgMTJcbiAgICAyOSAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgMjZcbiAgICAyOSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgMjdcbiAgICAzMSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgMjlcbiAgICAyNCAtLT58XCJkZWZpbmVkLWJ5XCJ8IDMxXG4gICAgMjQgLS0+fFwiZGVmaW5lZC1ieVwifCAzMlxuICAgIDMyIC0tPnxcImFyZ3VtZW50XCJ8IDMxXG4gICAgMzIgLS0+fFwicmV0dXJucywgYXJndW1lbnRcInwgMjRcbiAgICAzNCAtLT58XCJyZWFkc1wifCAyNFxuICAgIDM2IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCAzNFxuICAgIDM4IC0tPnxcInJlYWRzXCJ8IDEyXG4gICAgNDQgLS0+fFwicmVhZHNcInwgNDNcbiAgICA0NyAtLT58XCJyZWFkc1wifCA0NlxuICAgIDQ4IC0tPnxcInJlYWRzXCJ8IDQzXG4gICAgNDggLS0+fFwiYXJndW1lbnRcInwgNDRcbiAgICA0OCAtLT58XCJyZWFkc1wifCA0NlxuICAgIDQ4IC0tPnxcImFyZ3VtZW50XCJ8IDQ3XG4gICAgNTAgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDQ4XG4gICAgNTAgLS0+fFwiYXJndW1lbnRcInwgMzhcbiAgICA1MiAtLT58XCJhcmd1bWVudFwifCAzOFxuICAgIDUyIC0tPnxcImFyZ3VtZW50XCJ8IDUwXG4gICAgNTUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDUyXG4gICAgNTUgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDU0XG4gICAgNTcgLS0+fFwicmVhZHNcInwgMThcbiAgICA2MCAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNTdcbiAgICA2MCAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNThcbiAgICA2MiAtLT58XCJyZWFkc1wifCAxOFxuICAgIDY1IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA2MlxuICAgIDY1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2M1xuICAgIDY3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2MFxuICAgIDY3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA2NVxuICAgIDY5IC0tPnxcInJlYWRzXCJ8IDE4XG4gICAgNzIgLS0+fFwicmVhZHMsIHJldHVybnMsIGFyZ3VtZW50XCJ8IDY5XG4gICAgNzIgLS0+fFwicmVhZHMsIGFyZ3VtZW50XCJ8IDcwXG4gICAgNzQgLS0+fFwicmVhZHNcInwgMThcbiAgICA3NyAtLT58XCJyZWFkcywgcmV0dXJucywgYXJndW1lbnRcInwgNzRcbiAgICA3NyAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzVcbiAgICA3OSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzJcbiAgICA3OSAtLT58XCJyZWFkcywgYXJndW1lbnRcInwgNzdcbiAgICA4MiAtLT58XCJyZWFkc1wifCAxOFxuICAgIDg1IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA4MlxuICAgIDg1IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA4M1xuICAgIDg3IC0tPnxcInJlYWRzLCBhcmd1bWVudFwifCA4NVxuICAgIDg5IC0tPnxcInJlYWRzLCByZXR1cm5zLCBhcmd1bWVudFwifCA4NyIsIm1lcm1haWQiOnsiYXV0b1N5bmMiOnRydWV9fQ==))\
-_All queries together required ≈0 ms (1ms accuracy, total 5 ms)_
+_All queries together required ≈1 ms (1ms accuracy, total 6 ms)_
Show Detailed Results as Json
-The analysis required _5.24 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _5.91 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1180,7 +1195,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
{
"dataflow-cluster": {
".meta": {
- "timing": 0
+ "timing": 1
},
"clusters": [
{
@@ -1267,7 +1282,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
]
},
".meta": {
- "timing": 0
+ "timing": 1
}
}
```
@@ -1321,7 +1336,7 @@ _All queries together required ≈0 ms (1ms accuracy, total 1 ms)_
Show Detailed Results as Json
-The analysis required _1.38 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _1.28 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1349,7 +1364,7 @@ x + 1
Dataflow Graph of the R Code
-The analysis required _1.19 ms_ (incl. parse and normalize) within the generation environment.
+The analysis required _1.15 ms_ (incl. parse and normalize) within the generation environment.
We encountered no unknown side effects during the analysis.
@@ -1415,6 +1430,202 @@ Responsible for the execution of the Id-Map Query query is `executeIdMapQuery` i
+
+### Static Slice Query
+
+
+To slice, _flowR_ needs one thing from you: a variable or a list of variables (function calls are supported to, referring to the anonymous
+return of the call) that you want to slice the dataflow graph for.
+Given this, the slice is essentially the subpart of the program that may influence the value of the variables you are interested in.
+To specify a variable of interest, you have to present flowR with a [slicing criterion](https://github.com/flowr-analysis/flowr/wiki//Terminology#slicing-criterion) (or, respectively, an array of them).
+
+To exemplify the capabilities, consider the following code:
+
+```r
+x <- 1
+y <- 2
+x
+```
+
+If you are interested in the parts required for the use of `x` in the last line, you can use the following query:
+
+
+
+```json
+[
+ {
+ "type": "static-slice",
+ "criteria": [
+ "3@x"
+ ]
+ }
+]
+```
+
+
+
+_Results (prettified and summarized):_
+
+Query: **static-slice** (2 ms)\
+ ╰ ["3@x"] \
+ ╰ Code (newline as \n
): x <- 1\\nx
\
+_All queries together required ≈2 ms (1ms accuracy, total 3 ms)_
+
+ Show Detailed Results as Json
+
+The analysis required _3.48 ms_ (including parsing and normalization and the query) within the generation environment.
+
+In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
+Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
+
+
+
+
+```json
+{
+ "static-slice": {
+ ".meta": {
+ "timing": 2
+ },
+ "results": {
+ "{\"type\":\"static-slice\",\"criteria\":[\"3@x\"]}": {
+ "slice": {
+ "timesHitThreshold": 0,
+ "result": [
+ 6,
+ 0,
+ 1,
+ 2
+ ],
+ "decodedCriteria": [
+ {
+ "criterion": "3@x",
+ "id": 6
+ }
+ ]
+ },
+ "reconstruct": {
+ "code": "x <- 1\nx",
+ "linesWithAutoSelected": 0
+ }
+ }
+ }
+ },
+ ".meta": {
+ "timing": 2
+ }
+}
+```
+
+
+
+
+
+
+
+
+
+
+
+In general you may be uninterested in seeing the reconstructed version and want to save some computation time, for this,
+you can use the `noReconstruction` flag.
+
+
+No Reconstruction Example
+
+
+
+```json
+[
+ {
+ "type": "static-slice",
+ "criteria": [
+ "3@x"
+ ],
+ "noReconstruction": true
+ }
+]
+```
+
+
+
+_Results (prettified and summarized):_
+
+Query: **static-slice** (1 ms)\
+ ╰ ["3@x"] no reconstruction\
+ ╰ Id List: {6, 0, 1, 2}\
+_All queries together required ≈1 ms (1ms accuracy, total 2 ms)_
+
+ Show Detailed Results as Json
+
+The analysis required _2.12 ms_ (including parsing and normalization and the query) within the generation environment.
+
+In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
+Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
+
+
+
+
+```json
+{
+ "static-slice": {
+ ".meta": {
+ "timing": 1
+ },
+ "results": {
+ "{\"type\":\"static-slice\",\"criteria\":[\"3@x\"],\"noReconstruction\":true}": {
+ "slice": {
+ "timesHitThreshold": 0,
+ "result": [
+ 6,
+ 0,
+ 1,
+ 2
+ ],
+ "decodedCriteria": [
+ {
+ "criterion": "3@x",
+ "id": 6
+ }
+ ]
+ }
+ }
+ }
+ },
+ ".meta": {
+ "timing": 1
+ }
+}
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+You can disable [magic comments](https://github.com/flowr-analysis/flowr/wiki//Interface#slice-magic-comments) using the `noMagicComments` flag.
+This query replaces the old [`request-slice`](https://github.com/flowr-analysis/flowr/wiki//Interface#message-request-slice) message.
+
+
+
+
+Implementation Details
+
+Responsible for the execution of the Static Slice Query query is `executeStaticSliceClusterQuery` in [`./src/queries/catalog/static-slice-query/static-slice-query-executor.ts`](https://github.com/flowr-analysis/flowr/tree/main/./src/queries/catalog/static-slice-query/static-slice-query-executor.ts).
+
+
+
+
+
+
### Compound Query
@@ -1458,11 +1669,11 @@ _Results (prettified and summarized):_
Query: **call-context** (0 ms)\
╰ **visualize**\
╰ **text**: _`mean`_ (L.9), _`print`_ (L.10), _`mean`_ (L.19), _`print`_ (L.19)\
-_All queries together required ≈1 ms (1ms accuracy, total 5 ms)_
+_All queries together required ≈0 ms (1ms accuracy, total 5 ms)_
Show Detailed Results as Json
-The analysis required _4.86 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _5.15 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1498,7 +1709,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
}
},
".meta": {
- "timing": 1
+ "timing": 0
}
}
```
@@ -1532,14 +1743,14 @@ Of course, in this specific scenario, the following query would be equivalent:
_Results (prettified and summarized):_
-Query: **call-context** (0 ms)\
+Query: **call-context** (1 ms)\
╰ **visualize**\
╰ **text**: _`mean`_ (L.9), _`print`_ (L.10), _`mean`_ (L.19), _`print`_ (L.19)\
-_All queries together required ≈0 ms (1ms accuracy, total 5 ms)_
+_All queries together required ≈1 ms (1ms accuracy, total 5 ms)_
Show Detailed Results as Json
-The analysis required _4.85 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _5.18 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.
@@ -1551,7 +1762,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
{
"call-context": {
".meta": {
- "timing": 0
+ "timing": 1
},
"kinds": {
"visualize": {
@@ -1575,7 +1786,7 @@ Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Int
}
},
".meta": {
- "timing": 0
+ "timing": 1
}
}
```
@@ -1631,7 +1842,7 @@ _All queries together required ≈0 ms (1ms accuracy, total 5 ms)_
Show Detailed Results as Json
-The analysis required _4.77 ms_ (including parsing and normalization and the query) within the generation environment.
+The analysis required _4.84 ms_ (including parsing and normalization and the query) within the generation environment.
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki//Interface) wiki page for more information on how to get those.