Version 2.9.0-18.0.dev
Merge commit '71ddad82e4b628170d4362433c2f77771f887849' into dev
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 87d1ada..cd9ba19 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
"constraint, update this by running tools/generate_package_config.dart."
],
"configVersion": 2,
- "generated": "2020-05-15T15:16:14.438097",
+ "generated": "2020-06-17T09:39:51.245406",
"generator": "tools/generate_package_config.dart",
"packages": [
{
@@ -89,7 +89,7 @@
"name": "benchmark_harness",
"rootUri": "../third_party/pkg/benchmark_harness",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.9"
},
{
"name": "boolean_selector",
@@ -326,7 +326,8 @@
{
"name": "js",
"rootUri": "../pkg/js",
- "packageUri": "lib/"
+ "packageUri": "lib/",
+ "languageVersion": "2.9"
},
{
"name": "js_ast",
@@ -338,7 +339,7 @@
"name": "js_runtime",
"rootUri": "../sdk/lib/_internal/js_runtime",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.9"
},
{
"name": "json_rpc_2",
@@ -409,7 +410,7 @@
"name": "native_stack_traces",
"rootUri": "../pkg/native_stack_traces",
"packageUri": "lib/",
- "languageVersion": "2.7"
+ "languageVersion": "2.8"
},
{
"name": "nnbd_migration",
@@ -492,7 +493,7 @@
"name": "sdk_library_metadata",
"rootUri": "../sdk/lib/_internal/sdk_library_metadata",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.9"
},
{
"name": "shelf",
@@ -576,7 +577,7 @@
"name": "stream_channel",
"rootUri": "../third_party/pkg/stream_channel",
"packageUri": "lib/",
- "languageVersion": "2.0"
+ "languageVersion": "2.2"
},
{
"name": "string_scanner",
diff --git a/.gitattributes b/.gitattributes
index 3b5895d..6455c32 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -22,6 +22,11 @@
tests/dart2js_2/string_interpolation_test.dart -text
tests/dart2js_2/string_interpolation_dynamic_test.dart -text
tests/dart2js_2/literal_string_juxtaposition_test.dart -text
+tests/language/string/raw_string_test.dart -text
+tests/language/string/multiline_strings_test.dart -text
+tests/language/string/multiline_newline_cr.dart -text
+tests/language/string/multiline_newline_crlf.dart -text
+tests/language/string/multiline_newline_lf.dart -text
tests/language_2/string/raw_string_test.dart -text
tests/language_2/string/multiline_strings_test.dart -text
tests/language_2/string/multiline_newline_cr.dart -text
diff --git a/DEPS b/DEPS
index aea200d..6ebc4f9 100644
--- a/DEPS
+++ b/DEPS
@@ -48,7 +48,7 @@
"co19_2_rev": "620c1148c8b7a3d7f74afacf348c46f109eb64f2",
# The internal benchmarks to use. See go/dart-benchmarks-internal
- "benchmarks_internal_rev": "6c5cf5ca4f29f0e498a9ad51146ccb2ad3bbd2b4",
+ "benchmarks_internal_rev": "478f5a8be0bad2b1bc3c1c9cf150486ec77516e1",
"checkout_benchmarks_internal": False,
# As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
@@ -107,7 +107,7 @@
"http_retry_tag": "0.1.1",
"http_rev": "a131e563c09349f624d5421237183a06fb10552d",
"http_throttle_tag" : "1.0.2",
- "icu_rev" : "8d29692df640668ed7e4d1817715440c4e05697a",
+ "icu_rev" : "79326efe26e5440f530963704c3c0ff965b3a4ac",
"idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
"intl_tag": "0.16.1",
"jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
@@ -470,6 +470,17 @@
"dep_type": "cipd",
},
+ Var("dart_root") + "/third_party/fuchsia/sdk/linux": {
+ "packages": [
+ {
+ "package": "fuchsia/sdk/gn/linux-amd64",
+ "version": "git_revision:8d5242d4f6ff8b7634b492700e60b0fd09abefa3"
+ }
+ ],
+ "condition": 'host_os == "linux" and host_cpu == "x64"',
+ "dep_type": "cipd",
+ },
+
Var("dart_root") + "/pkg/front_end/test/fasta/types/benchmark_data": {
"packages": [
{
diff --git a/WATCHLISTS b/WATCHLISTS
index c4e7dea..a07b665 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -35,7 +35,7 @@
'filepath': (
'^pkg/dev_compiler|'
'^sdk/lib/_internal/js_dev_runtime|'
- '^tests/compiler/dartdevc_native'
+ '^tests/dartdevc'
)
},
'package_vm': {
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 4457f43..e83f614 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -196,6 +196,16 @@
is_nacl = false
is_posix = true
is_win = false
+} else if (current_os == "fuchsia") {
+ is_android = false
+ is_chromeos = false
+ is_fuchsia = true
+ is_ios = false
+ is_linux = false
+ is_mac = false
+ is_nacl = false
+ is_posix = true
+ is_win = false
}
# =============================================================================
@@ -384,6 +394,11 @@
} else if (is_mac) {
host_toolchain = "//build/toolchain/mac:clang_x64"
set_default_toolchain(host_toolchain)
+} else if (is_fuchsia) {
+ assert(host_os == "linux")
+ assert(host_cpu == "x64")
+ host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+ set_default_toolchain("//build/toolchain/fuchsia")
}
# ==============================================================================
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index b5a49ba..ee47c35 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -243,7 +243,7 @@
# 3. When using the sanitizers.
# Otherwise there is a performance hit, in particular on ia32.
if (is_android || is_asan || is_lsan || is_msan || is_tsan || is_ubsan ||
- (is_linux && current_cpu != "x86")) {
+ (is_linux && current_cpu != "x86") || is_fuchsia) {
cflags += [ "-fPIC" ]
ldflags += [ "-fPIC" ]
}
@@ -276,6 +276,8 @@
if (is_win) {
# Up-to-date toolchain MSVC doesn't support c++11 flag any longer.
cc_std = [ "/std:c++14" ]
+ } else if (is_fuchsia) {
+ cc_std = [ "-std=c++17" ]
} else {
cc_std = [ "-std=c++11" ]
}
diff --git a/build/fuchsia/sdk.gni b/build/fuchsia/sdk.gni
new file mode 100644
index 0000000..00698dc
--- /dev/null
+++ b/build/fuchsia/sdk.gni
@@ -0,0 +1,10 @@
+# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+declare_args() {
+ using_fuchsia_gn_sdk = true
+ fuchsia_sdk_root = "//third_party/fuchsia/sdk/$host_os"
+ fuchsia_sdk_path = "//third_party/fuchsia/sdk/$host_os"
+ fuchsia_toolchain_path = "//third_party/fuchsia/toolchain/$host_os"
+}
diff --git a/build/toolchain/fuchsia/BUILD.gn b/build/toolchain/fuchsia/BUILD.gn
new file mode 100644
index 0000000..2901377
--- /dev/null
+++ b/build/toolchain/fuchsia/BUILD.gn
@@ -0,0 +1,164 @@
+# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+import("//build/toolchain/ccache.gni")
+import("//build/toolchain/gcc_toolchain.gni")
+import("//build/toolchain/goma.gni")
+
+if (use_goma) {
+ assert(!use_ccache, "Goma and ccache can't be used together.")
+ compiler_prefix = "$goma_dir/gomacc "
+} else if (use_ccache) {
+ compiler_prefix = "ccache "
+} else {
+ compiler_prefix = ""
+}
+
+toolchain("fuchsia") {
+ assert(target_cpu == "x64", "We currently only support 'x64' for fuchsia.")
+ toolchain_bin =
+ rebase_path("//buildtools/$host_os-$target_cpu/clang/bin", root_out_dir)
+ fuchsia_sdk = rebase_path("//third_party/fuchsia/sdk/$host_os", root_out_dir)
+
+ # We can't do string interpolation ($ in strings) on things with dots in
+ # them. To allow us to use $cc below, for example, we create copies of
+ # these values in our scope.
+ cc = "${toolchain_bin}/clang"
+ cxx = "${toolchain_bin}/clang++"
+ ar = "${toolchain_bin}/llvm-ar"
+ ld = "${toolchain_bin}/clang++"
+ readelf = "${toolchain_bin}/llvm-readelf"
+ nm = "${toolchain_bin}/llvm-nm"
+ strip = "${toolchain_bin}/llvm-strip"
+
+ target_triple_flags = "--target=x86_64-fuchsia"
+ sysroot_flags = "--sysroot ${fuchsia_sdk}/arch/${target_cpu}/sysroot"
+ lto_flags = ""
+
+ # These library switches can apply to all tools below.
+ lib_switch = "-l"
+ lib_dir_switch = "-L"
+
+ tool("cc") {
+ depfile = "{{output}}.d"
+ command = "$compiler_prefix $cc -MD -MF $depfile $target_triple_flags $sysroot_flags $lto_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CC {{output}}"
+ outputs =
+ [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
+ }
+
+ tool("cxx") {
+ depfile = "{{output}}.d"
+ command = "$compiler_prefix $cxx -MD -MF $depfile $target_triple_flags $sysroot_flags $lto_flags {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "CXX {{output}}"
+ outputs =
+ [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
+ }
+
+ tool("asm") {
+ depfile = "{{output}}.d"
+ command = "$compiler_prefix $cc -MD -MF $depfile $target_triple_flags $sysroot_flags $lto_flags {{defines}} {{include_dirs}} {{asmflags}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
+ depsformat = "gcc"
+ description = "ASM {{output}}"
+ outputs =
+ [ "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" ]
+ }
+
+ tool("alink") {
+ rspfile = "{{output}}.rsp"
+ command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile"
+ description = "AR {{output}}"
+ rspfile_content = "{{inputs}}"
+ outputs =
+ [ "{{target_out_dir}}/{{target_output_name}}{{output_extension}}" ]
+ default_output_extension = ".a"
+ output_prefix = "lib"
+ }
+
+ tool("solink") {
+ soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so".
+ sofile = "{{root_out_dir}}/$soname" # Possibly including toolchain dir.
+ unstripped_sofile =
+ "{{root_out_dir}}/so.unstripped/$soname" # Possibly including toolchain
+ # dir.
+ rspfile = sofile + ".rsp"
+
+ # These variables are not built into GN but are helpers that implement
+ # (1) linking to produce a .so, (2) extracting the symbols from that file
+ # to a temporary file, (3) if the temporary file has differences from the
+ # existing .TOC file, overwrite it, otherwise, don't change it.
+ tocfile = sofile + ".TOC"
+ temporary_tocname = sofile + ".tmp"
+ link_command = "$compiler_prefix $ld $target_triple_flags $sysroot_flags $lto_flags -shared {{ldflags}} -o $unstripped_sofile -Wl,--build-id -Wl,-soname=$soname @$rspfile"
+ toc_command = "{ $readelf -d $unstripped_sofile | grep SONAME ; $nm -gD -f posix $unstripped_sofile | cut -f1-2 -d' '; } > $temporary_tocname"
+ replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi"
+ strip_command = "$strip -o $sofile $unstripped_sofile"
+
+ command =
+ "$link_command && $toc_command && $replace_command && $strip_command"
+ rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
+
+ description = "SOLINK $sofile"
+
+ default_output_extension = ".so"
+
+ output_prefix = "lib"
+
+ # Since the above commands only updates the .TOC file when it changes, ask
+ # Ninja to check if the timestamp actually changed to know if downstream
+ # dependencies should be recompiled.
+ restat = true
+
+ # Tell GN about the output files. It will link to the sofile but use the
+ # tocfile for dependency management.
+ outputs = [
+ sofile,
+ unstripped_sofile,
+ tocfile,
+ ]
+
+ link_output = sofile
+ depend_output = tocfile
+ }
+
+ tool("link") {
+ exename = "{{target_output_name}}{{output_extension}}"
+ outfile = "{{root_out_dir}}/$exename"
+ rspfile = "$outfile.rsp"
+ unstripped_outfile = "{{root_out_dir}}/exe.stripped/$exename"
+ command = "$compiler_prefix $ld $target_triple_flags $sysroot_flags $lto_flags {{ldflags}} -o $unstripped_outfile -Wl,--build-id -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group {{libs}} && ${strip} -o $outfile $unstripped_outfile"
+ description = "LINK $outfile"
+ rspfile_content = "{{inputs}}"
+ outputs = [
+ unstripped_outfile,
+ outfile,
+ ]
+ }
+
+ tool("stamp") {
+ command = "touch {{output}}"
+ description = "STAMP {{output}}"
+ }
+
+ tool("copy") {
+ command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
+ description = "COPY {{source}} {{output}}"
+ }
+
+ # When invoking this toolchain not as the default one, these args will be
+ # passed to the build. They are ignored when this is the default toolchain.
+ toolchain_args = {
+ current_cpu = target_cpu
+ current_os = target_os
+
+ # These values need to be passed through unchanged.
+ target_os = target_os
+ target_cpu = target_cpu
+
+ is_clang = true
+ }
+}
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 389b7e8..3f5c00c 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- 1.27.4
+ 1.28.0
</h1>
<p>
This document contains a specification of the API provided by the
@@ -228,6 +228,13 @@
That is, in some cases it may return responses with the currently available
results while it's catching up with unprocessed changes.
</p>
+<h3>Enumerations</h3>
+<p>
+ Responses from the server may include enumerations indicating the kind of a
+ specific item. The enums may be extended with new values in future versions of
+ the server so clients should ensure unknown values are handled gracefully, either
+ ignoring the item or treating it with some default/fallback handling.
+</p>
<h3>Domains</h3>
<p>
For convenience, the API is divided into domains. Each domain is specified
@@ -4170,7 +4177,7 @@
An enumeration of the kinds of folding regions.
</p>
- <dl><dt class="value">ANNOTATIONS</dt><dt class="value">CLASS_BODY</dt><dt class="value">DIRECTIVES</dt><dt class="value">DOCUMENTATION_COMMENT</dt><dt class="value">FILE_HEADER</dt><dt class="value">FUNCTION_BODY</dt><dt class="value">INVOCATION</dt><dt class="value">LITERAL</dt></dl></dd><dt class="typeDefinition"><a name="type_FoldingRegion">FoldingRegion: object</a></dt><dd>
+ <dl><dt class="value">ANNOTATIONS</dt><dt class="value">BLOCK</dt><dt class="value">CLASS_BODY</dt><dt class="value">DIRECTIVES</dt><dt class="value">DOCUMENTATION_COMMENT</dt><dt class="value">FILE_HEADER</dt><dt class="value">FUNCTION_BODY</dt><dt class="value">INVOCATION</dt><dt class="value">LITERAL</dt></dl></dd><dt class="typeDefinition"><a name="type_FoldingRegion">FoldingRegion: object</a></dt><dd>
<p>
A description of a region that can be folded.
</p>
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 6e51b61..2a888ca 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.27.4';
+const String PROTOCOL_VERSION = '1.28.0';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/src/cider/completion.dart b/pkg/analysis_server/lib/src/cider/completion.dart
index d87d611..bd1f8d5 100644
--- a/pkg/analysis_server/lib/src/cider/completion.dart
+++ b/pkg/analysis_server/lib/src/cider/completion.dart
@@ -94,7 +94,10 @@
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
);
- return await manager.computeSuggestions(completionRequest);
+ return await manager.computeSuggestions(
+ completionRequest,
+ enableUriContributor: false,
+ );
});
suggestionsTimer.stop();
diff --git a/pkg/analysis_server/lib/src/computer/computer_folding.dart b/pkg/analysis_server/lib/src/computer/computer_folding.dart
index 7f32a17..9bf7c03 100644
--- a/pkg/analysis_server/lib/src/computer/computer_folding.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_folding.dart
@@ -19,6 +19,35 @@
DartUnitFoldingComputer(this._lineInfo, this._unit);
+ void addRegionForConditionalBlock(Block block) {
+ // For class/function/method blocks, we usually include the whitespace up
+ // until the `}` in the folding region so that when collapsed they would
+ // look like:
+ //
+ // class Foo { [...] }
+ //
+ // For if statements, they may have else/elseIfs which would result in long
+ // lines like:
+ //
+ // if (cond) { [...] } else { [...] }
+ //
+ // So these types of blocks should have their folding regions end at the
+ // end of the preceeding statement.
+
+ final start = block.leftBracket.end;
+ if (block.endToken.precedingComments != null) {
+ // If there are comments before the end token, use the last of those.
+ var lastComment = block.endToken.precedingComments;
+ while (lastComment.next != null) {
+ lastComment = lastComment.next;
+ }
+ _addRegion(start, lastComment.end, FoldingKind.BLOCK);
+ } else if (block.statements.isNotEmpty) {
+ // Otherwise, use the end of the last statement.
+ _addRegion(start, block.statements.last.end, FoldingKind.BLOCK);
+ }
+ }
+
/// Returns a list of folding regions, not `null`.
List<FoldingRegion> compute() {
_addFileHeaderRegion();
@@ -149,6 +178,14 @@
}
@override
+ void visitDoStatement(DoStatement node) {
+ if (node.body is Block) {
+ _computer.addRegionForConditionalBlock(node.body);
+ }
+ super.visitDoStatement(node);
+ }
+
+ @override
void visitExportDirective(ExportDirective node) {
_computer._recordDirective(node);
super.visitExportDirective(node);
@@ -182,6 +219,17 @@
}
@override
+ void visitIfStatement(IfStatement node) {
+ if (node.thenStatement is Block) {
+ _computer.addRegionForConditionalBlock(node.thenStatement);
+ }
+ if (node.elseStatement is Block) {
+ _computer.addRegionForConditionalBlock(node.elseStatement);
+ }
+ super.visitIfStatement(node);
+ }
+
+ @override
void visitImportDirective(ImportDirective node) {
_computer._recordDirective(node);
super.visitImportDirective(node);
@@ -247,4 +295,12 @@
node.leftBracket.end, node.rightBracket.offset, FoldingKind.LITERAL);
super.visitSetOrMapLiteral(node);
}
+
+ @override
+ void visitWhileStatement(WhileStatement node) {
+ if (node.body is Block) {
+ _computer.addRegionForConditionalBlock(node.body);
+ }
+ super.visitWhileStatement(node);
+ }
}
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 1c63942..5dac07a 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -100,7 +100,12 @@
var contributorTag = 'computeSuggestions - ${manager.runtimeType}';
performance.logStartTime(contributorTag);
try {
- suggestions.addAll(await manager.computeSuggestions(request));
+ suggestions.addAll(
+ await manager.computeSuggestions(
+ request,
+ enableUriContributor: true,
+ ),
+ );
} on AbortCompletion {
suggestions.clear();
}
diff --git a/pkg/analysis_server/lib/src/domains/execution/completion.dart b/pkg/analysis_server/lib/src/domains/execution/completion.dart
index 35b320a..24b0d46 100644
--- a/pkg/analysis_server/lib/src/domains/execution/completion.dart
+++ b/pkg/analysis_server/lib/src/domains/execution/completion.dart
@@ -10,7 +10,6 @@
RuntimeCompletionExpression,
RuntimeCompletionVariable,
SourceEdit;
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
@@ -82,7 +81,7 @@
targetResult = await analysisDriver.getResult(contextPath);
});
- CompletionContributor contributor = DartCompletionManager(
+ var contributor = DartCompletionManager(
// dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(targetResult)
);
var request = CompletionRequestImpl(
@@ -91,7 +90,10 @@
false,
CompletionPerformance(),
);
- var suggestions = await contributor.computeSuggestions(request);
+ var suggestions = await contributor.computeSuggestions(
+ request,
+ enableUriContributor: true,
+ );
// Remove completions with synthetic import prefixes.
suggestions.removeWhere((s) => s.completion.startsWith('__prefix'));
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index d9c1815..5fe7fa0 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -208,15 +208,17 @@
}
try {
- CompletionContributor contributor = DartCompletionManager(
+ var contributor = DartCompletionManager(
dartdocDirectiveInfo: directiveInfo,
includedElementKinds: includedElementKinds,
includedElementNames: includedElementNames,
includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
);
- final serverSuggestions =
- await contributor.computeSuggestions(completionRequest);
+ final serverSuggestions = await contributor.computeSuggestions(
+ completionRequest,
+ enableUriContributor: true,
+ );
if (token.isCancellationRequested) {
return cancelled();
diff --git a/pkg/analysis_server/lib/src/server/error_notifier.dart b/pkg/analysis_server/lib/src/server/error_notifier.dart
index 79faa40..1b911cf 100644
--- a/pkg/analysis_server/lib/src/server/error_notifier.dart
+++ b/pkg/analysis_server/lib/src/server/error_notifier.dart
@@ -23,7 +23,7 @@
exception = exception.rootCaughtException;
// TODO(mfairhurst): Use the outermost message rather than the innermost
// exception as its own message.
- message = exception.exception;
+ message = exception.message;
}
server.sendServerErrorNotification(message, exception, stackTrace,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index de6425d..b09cfaf 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -36,7 +36,6 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/exception/exception.dart';
@@ -50,6 +49,7 @@
import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
+import 'package:meta/meta.dart';
/// [DartCompletionManager] determines if a completion request is Dart specific
/// and forwards those requests to all [DartCompletionContributor]s.
@@ -100,7 +100,9 @@
@override
Future<List<CompletionSuggestion>> computeSuggestions(
- CompletionRequest request) async {
+ CompletionRequest request, {
+ @required bool enableUriContributor,
+ }) async {
request.checkAborted();
if (!AnalysisEngine.isDartFileName(request.result.path)) {
return const <CompletionSuggestion>[];
@@ -141,7 +143,7 @@
OverrideContributor(),
StaticMemberContributor(),
TypeMemberContributor(),
- UriContributor(),
+ if (enableUriContributor) UriContributor(),
VariableNameContributor()
];
@@ -234,75 +236,35 @@
}
void _addIncludedSuggestionRelevanceTags(DartCompletionRequestImpl request) {
- var target = request.target;
-
if (request.inConstantContext && request.useNewRelevance) {
includedSuggestionRelevanceTags.add(IncludedSuggestionRelevanceTag(
'isConst', RelevanceBoost.constInConstantContext));
}
- void addTypeTag(DartType type) {
- if (type is InterfaceType) {
- var element = type.element;
- var tag = '${element.librarySource.uri}::${element.name}';
- if (element.isEnum) {
- var relevance = request.useNewRelevance
- ? RelevanceBoost.availableEnumConstant
- : DART_RELEVANCE_BOOST_AVAILABLE_ENUM;
- includedSuggestionRelevanceTags.add(
- IncludedSuggestionRelevanceTag(
- tag,
- relevance,
- ),
- );
- } else {
- var relevance = request.useNewRelevance
- ? RelevanceBoost.availableDeclaration
- : DART_RELEVANCE_BOOST_AVAILABLE_DECLARATION;
- includedSuggestionRelevanceTags.add(
- IncludedSuggestionRelevanceTag(
- tag,
- relevance,
- ),
- );
- }
- }
- }
-
- var parameter = target.parameterElement;
- if (parameter != null) {
- addTypeTag(parameter.type);
- }
-
- var containingNode = target.containingNode;
-
- if (containingNode is AssignmentExpression &&
- containingNode.operator.type == TokenType.EQ &&
- target.offset >= containingNode.operator.end) {
- addTypeTag(containingNode.leftHandSide.staticType);
- }
-
- if (containingNode is ListLiteral &&
- target.offset >= containingNode.leftBracket.end &&
- target.offset <= containingNode.rightBracket.offset) {
- var type = containingNode.staticType;
- if (type is InterfaceType) {
- var typeArguments = type.typeArguments;
- if (typeArguments.isNotEmpty) {
- addTypeTag(typeArguments[0]);
- }
- }
- }
-
- if (containingNode is VariableDeclaration &&
- containingNode.equals != null &&
- target.offset >= containingNode.equals.end) {
- var parent = containingNode.parent;
- if (parent is VariableDeclarationList) {
- var type = parent.type?.type;
- if (type is InterfaceType) {
- addTypeTag(type);
- }
+ var type = request.contextType;
+ if (type is InterfaceType) {
+ var element = type.element;
+ var tag = '${element.librarySource.uri}::${element.name}';
+ if (element.isEnum) {
+ var relevance = request.useNewRelevance
+ ? RelevanceBoost.availableEnumConstant
+ : DART_RELEVANCE_BOOST_AVAILABLE_ENUM;
+ includedSuggestionRelevanceTags.add(
+ IncludedSuggestionRelevanceTag(
+ tag,
+ relevance,
+ ),
+ );
+ } else {
+ var relevance = request.useNewRelevance
+ ? RelevanceBoost.availableDeclaration
+ : DART_RELEVANCE_BOOST_AVAILABLE_DECLARATION;
+ includedSuggestionRelevanceTags.add(
+ IncludedSuggestionRelevanceTag(
+ tag,
+ relevance,
+ ),
+ );
}
}
}
@@ -371,9 +333,8 @@
@override
DartType get contextType {
if (!_hasComputedContextType) {
- var entity = target.entity;
_contextType = featureComputer.computeContextType(
- target.containingNode, entity.offset);
+ target.containingNode, target.offset);
_hasComputedContextType = true;
}
return _contextType;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
index 6e236a5..e9857ad 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -471,6 +471,14 @@
}
@override
+ DartType visitFieldDeclaration(FieldDeclaration node) {
+ if (node.fields != null && node.fields.contains(offset)) {
+ return node.fields.accept(this);
+ }
+ return null;
+ }
+
+ @override
DartType visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
if (range
.startOffsetEndOffset(node.inKeyword.end, node.end)
@@ -706,8 +714,16 @@
}
@override
+ DartType visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+ if (node.variables != null && node.variables.contains(offset)) {
+ return node.variables.accept(this);
+ }
+ return null;
+ }
+
+ @override
DartType visitVariableDeclaration(VariableDeclaration node) {
- if (node.equals != null && node.equals.end < offset) {
+ if (node.equals != null && node.equals.end <= offset) {
var parent = node.parent;
if (parent is VariableDeclarationList) {
return parent.type?.type;
@@ -717,6 +733,18 @@
}
@override
+ DartType visitVariableDeclarationList(VariableDeclarationList node) {
+ for (var varDecl in node.variables) {
+ if (varDecl != null && varDecl.contains(offset)) {
+ if (varDecl.equals.end <= offset) {
+ return node.type?.type;
+ }
+ }
+ }
+ return null;
+ }
+
+ @override
DartType visitWhileStatement(WhileStatement node) {
if (range
.endStart(node.leftParenthesis, node.rightParenthesis)
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/make_final.dart b/pkg/analysis_server/lib/src/services/correction/dart/make_final.dart
index f1ecfa1..c35bcf8 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/make_final.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/make_final.dart
@@ -29,10 +29,12 @@
if (list != null) {
if (list.variables.length == 1) {
await builder.addFileEdit(file, (DartFileEditBuilder builder) {
- if (list.keyword == null) {
- builder.addSimpleInsertion(list.offset, 'final ');
- } else if (list.keyword.keyword == Keyword.VAR) {
+ if (list.keyword?.keyword == Keyword.VAR) {
builder.addSimpleReplacement(range.token(list.keyword), 'final');
+ } else if (list.lateKeyword != null) {
+ builder.addSimpleInsertion(list.lateKeyword.end, ' final');
+ } else if (list.keyword == null) {
+ builder.addSimpleInsertion(list.offset, 'final ');
}
});
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c398846..82bcb0d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -492,6 +492,9 @@
CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED: [
AddMissingParameter.newInstance,
],
+ CompileTimeErrorCode.IMPLEMENTS_NON_CLASS: [
+ ImportLibrary.forType,
+ ],
CompileTimeErrorCode.INVALID_ANNOTATION: [
ImportLibrary.forTopLevelVariable,
ImportLibrary.forType,
@@ -600,6 +603,10 @@
CreateConstructor.newInstance,
ConvertToNamedArguments.newInstance,
],
+ CompileTimeErrorCode.IMPLEMENTS_NON_CLASS: [
+ ChangeTo.classOrMixin,
+ CreateClass.newInstance,
+ ],
CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD: [
CreateField.newInstance,
],
@@ -618,6 +625,7 @@
],
CompileTimeErrorCode.MIXIN_OF_NON_CLASS: [
ChangeTo.classOrMixin,
+ CreateClass.newInstance,
],
CompileTimeErrorCode.NULLABLE_TYPE_IN_EXTENDS_CLAUSE: [
RemoveQuestionMark.newInstance,
diff --git a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
index b1ce6a5..c21363f 100644
--- a/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
+++ b/pkg/analysis_server/lib/src/services/correction/statement_analyzer.dart
@@ -21,7 +21,10 @@
try {
var tokens = <Token>[];
var scanner = Scanner(null, CharSequenceReader(text), null)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
while (token.type != TokenType.EOF) {
tokens.add(token);
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index bd5d17b..2a65443 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -1276,7 +1276,10 @@
try {
var tokens = <Token>[];
var scanner = Scanner(null, CharSequenceReader(s), null)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
while (token.type != TokenType.EOF) {
tokens.add(token);
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index d922b52..738501c 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -31,24 +31,6 @@
handler = EditDomainHandler(server);
}
- Future<void> test_fixExtendsNonClass() async {
- createProject();
- addTestFile('''
-class MyCompleter extends Completer<String> {}
-
-class Completer2 {}
-''');
- await waitForTasksFinished();
- doAllDeclarationsTrackerWork();
- var errorFixes = await _getFixesAt('extends Completer');
- expect(errorFixes, hasLength(1));
- var fixes = errorFixes[0].fixes;
- expect(fixes, hasLength(3));
- expect(fixes[0].message, matches('Import library'));
- expect(fixes[1].message, matches("Change to 'Completer2'"));
- expect(fixes[2].message, matches("Create class 'Completer'"));
- }
-
Future<void> test_fixUndefinedClass() async {
createProject();
addTestFile('''
diff --git a/pkg/analysis_server/test/integration/linter/lint_names_test.dart b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
index 8548ffe..f36937a 100644
--- a/pkg/analysis_server/test/integration/linter/lint_names_test.dart
+++ b/pkg/analysis_server/test/integration/linter/lint_names_test.dart
@@ -69,7 +69,10 @@
var errorListener = _ErrorListener();
var featureSet = FeatureSet.forTesting(sdkVersion: '2.2.2');
var scanner = Scanner(stringSource, reader, errorListener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var startToken = scanner.tokenize();
errorListener.throwIfErrors();
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index e1f3fcb..6764831 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -701,6 +701,7 @@
///
/// enum {
/// ANNOTATIONS
+/// BLOCK
/// CLASS_BODY
/// DIRECTIVES
/// DOCUMENTATION_COMMENT
@@ -711,6 +712,7 @@
/// }
final Matcher isFoldingKind = MatchesEnum('FoldingKind', [
'ANNOTATIONS',
+ 'BLOCK',
'CLASS_BODY',
'DIRECTIVES',
'DOCUMENTATION_COMMENT',
diff --git a/pkg/analysis_server/test/lsp/folding_test.dart b/pkg/analysis_server/test/lsp/folding_test.dart
index 49dc5ce..807a303 100644
--- a/pkg/analysis_server/test/lsp/folding_test.dart
+++ b/pkg/analysis_server/test/lsp/folding_test.dart
@@ -68,6 +68,44 @@
expect(regions, unorderedEquals(expectedRegions));
}
+ Future<void> test_doLoop() async {
+ final content = '''
+ f(int i) {
+ do {[[
+ print('with statements');]]
+ } while (i == 0)
+
+ do {[[
+ // only comments]]
+ } while (i == 0)
+
+ // empty
+ do {
+ } while (i == 0)
+
+ // no body
+ do;
+ }
+ ''';
+
+ final ranges = rangesFromMarkers(content);
+ final expectedRegions = ranges
+ .map((range) => FoldingRange(
+ range.start.line,
+ range.start.character,
+ range.end.line,
+ range.end.character,
+ null,
+ ))
+ .toList();
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ final regions = await getFoldingRegions(mainFileUri);
+ expect(regions, containsAll(expectedRegions));
+ }
+
Future<void> test_fromPlugins_dartFile() async {
final pluginAnalyzedFilePath = join(projectFolderPath, 'lib', 'foo.dart');
final pluginAnalyzedUri = Uri.file(pluginAnalyzedFilePath);
@@ -162,6 +200,40 @@
expect(regions, unorderedEquals(expectedRegions));
}
+ Future<void> test_ifElseElseIf() async {
+ final content = '''
+ f(int i) {
+ if (i == 0) {[[
+ // only
+ // comments]]
+ } else if (i == 1) {[[
+ print('statements');]]
+ } else if (i == 2) {
+ } else {[[
+ // else
+ // comments]]
+ }
+ }
+ ''';
+
+ final ranges = rangesFromMarkers(content);
+ final expectedRegions = ranges
+ .map((range) => FoldingRange(
+ range.start.line,
+ range.start.character,
+ range.end.line,
+ range.end.character,
+ null,
+ ))
+ .toList();
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ final regions = await getFoldingRegions(mainFileUri);
+ expect(regions, containsAll(expectedRegions));
+ }
+
Future<void> test_nonDartFile() async {
await initialize();
await openFile(pubspecFileUri, simplePubspecContent);
@@ -170,6 +242,44 @@
expect(regions, isEmpty);
}
+ Future<void> test_whileLoop() async {
+ final content = '''
+ f(int i) {
+ while (i == 0) {[[
+ print('with statements');]]
+ }
+
+ while (i == 0) {[[
+ // only comments]]
+ }
+
+ // empty
+ while (i == 0) {
+ }
+
+ // no body
+ while (i == 0);
+ }
+ ''';
+
+ final ranges = rangesFromMarkers(content);
+ final expectedRegions = ranges
+ .map((range) => FoldingRange(
+ range.start.line,
+ range.start.character,
+ range.end.line,
+ range.end.character,
+ null,
+ ))
+ .toList();
+
+ await initialize();
+ await openFile(mainFileUri, withoutMarkers(content));
+
+ final regions = await getFoldingRegions(mainFileUri);
+ expect(regions, containsAll(expectedRegions));
+ }
+
FoldingRange _toFoldingRange(Range range, FoldingRangeKind kind) {
return FoldingRange(
range.start.line,
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/non_type_member_relevance_test.dart b/pkg/analysis_server/test/services/completion/dart/relevance/non_type_member_relevance_test.dart
new file mode 100644
index 0000000..8c541de
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/non_type_member_relevance_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'completion_relevance.dart';
+
+void main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(NonTypeMemberRelevanceTest);
+ });
+}
+
+@reflectiveTest
+class NonTypeMemberRelevanceTest extends CompletionRelevanceTest {
+ Future<void> test_contextType_constructorInvocation_before_type() async {
+ await addTestFile('''
+class StrWrap {
+ String string;
+ StrWrap(this.string);
+}
+void foo(StrWrap s) {}
+void bar() {
+ foo(^);
+}
+''');
+
+ var constructorInvocationSuggestion =
+ suggestionWith(completion: 'StrWrap', element: ElementKind.CONSTRUCTOR);
+
+ var typeSuggestion =
+ suggestionWith(completion: 'StrWrap', element: ElementKind.CLASS);
+
+ assertOrder([constructorInvocationSuggestion, typeSuggestion]);
+ }
+
+ @failingTest
+ Future<void> test_typeParameters() async {
+ await addTestFile('''
+class Foo{}
+void foo<T>(List<T> bar) {
+ List<^> baz;
+}
+''');
+
+ assertOrder(
+ [suggestionWith(completion: 'T'), suggestionWith(completion: 'Foo')]);
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart b/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart
index 9a09a5b..372bafa 100644
--- a/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/relevance/test_all.dart
@@ -8,6 +8,7 @@
import 'deprecated_member_relevance_test.dart' as deprecated_members;
import 'instance_member_relevance_test.dart' as instance_member_relevance;
import 'named_argument_relevance_test.dart' as named_argument_relevance;
+import 'non_type_member_relevance_test.dart' as non_type_member_relevance;
import 'static_member_relevance_test.dart' as static_member_relevance;
void main() {
@@ -16,6 +17,7 @@
deprecated_members.main();
instance_member_relevance.main();
named_argument_relevance.main();
+ non_type_member_relevance.main();
static_member_relevance.main();
});
}
diff --git a/pkg/analysis_server/test/src/cider/completion_test.dart b/pkg/analysis_server/test/src/cider/completion_test.dart
index a1d3a4a..ed599c0 100644
--- a/pkg/analysis_server/test/src/cider/completion_test.dart
+++ b/pkg/analysis_server/test/src/cider/completion_test.dart
@@ -130,6 +130,14 @@
_assertHasClass(text: 'String');
}
+ Future<void> test_compute_uriContributor_disabled() async {
+ newFile('/workspace/dart/test/lib/a.dart', content: '');
+ await _compute(r'''
+import '^';
+''');
+ expect(_suggestions, isEmpty);
+ }
+
Future<void> test_filterSort_byPattern_excludeNotMatching() async {
await _compute(r'''
var a = F^;
diff --git a/pkg/analysis_server/test/src/services/completion/dart/feature_computer_test.dart b/pkg/analysis_server/test/src/services/completion/dart/feature_computer_test.dart
index 67da9e2..cd03280 100644
--- a/pkg/analysis_server/test/src/services/completion/dart/feature_computer_test.dart
+++ b/pkg/analysis_server/test/src/services/completion/dart/feature_computer_test.dart
@@ -289,6 +289,62 @@
''', 'num');
}
+ Future<void> test_fieldDeclaration_int() async {
+ await assertContextType('''
+class Foo {
+ int i=^;
+}
+''', 'int');
+ }
+
+ Future<void> test_fieldDeclaration_int_missingSemicolon() async {
+ await assertContextType('''
+class Foo {
+ int i=^
+}
+''', 'int');
+ }
+
+ Future<void> test_fieldDeclaration_int_multiple() async {
+ await assertContextType('''
+class Foo {
+ int i=1,j=2,k=^;
+}
+''', 'int');
+ }
+
+ Future<void> test_fieldDeclaration_int_multiple_whitespace() async {
+ await assertContextType('''
+class Foo {
+ int i = 1 , j = 2 , k = ^ ;
+}
+''', 'int');
+ }
+
+ Future<void> test_fieldDeclaration_int_whitespace() async {
+ await assertContextType('''
+class Foo {
+ int i = ^ ;
+}
+''', 'int');
+ }
+
+ Future<void> test_fieldDeclaration_var() async {
+ await assertContextType('''
+class Foo {
+ var i =^;
+}
+''', null);
+ }
+
+ Future<void> test_fieldDeclaration_var_whitespace() async {
+ await assertContextType('''
+class Foo {
+ var i = ^ ;
+}
+''', null);
+ }
+
Future<void> test_ifElement() async {
await assertContextType('''
void f(bool b, int e) {
@@ -444,4 +500,47 @@
}
''', null);
}
+
+ Future<void> test_topLevelVariableDeclaration_int() async {
+ await assertContextType('''
+int i=^;
+''', 'int');
+ }
+
+ Future<void> test_topLevelVariableDeclaration_int_missingSemicolon() async {
+ await assertContextType('''
+int i=^
+''', 'int');
+ }
+
+ Future<void> test_topLevelVariableDeclaration_int_multiple() async {
+ await assertContextType('''
+int i=1,j=2,k=^;
+''', 'int');
+ }
+
+ Future<void>
+ test_topLevelVariableDeclaration_int_multiple_whitespace() async {
+ await assertContextType('''
+int i = 1 , j = 2 , k = ^ ;
+''', 'int');
+ }
+
+ Future<void> test_topLevelVariableDeclaration_int_whitespace() async {
+ await assertContextType('''
+int i = ^ ;
+''', 'int');
+ }
+
+ Future<void> test_topLevelVariableDeclaration_var() async {
+ await assertContextType('''
+var i=^;
+''', null);
+ }
+
+ Future<void> test_topLevelVariableDeclaration_var_whitespace() async {
+ await assertContextType('''
+var i= ^ ;
+''', null);
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
index 2aecfe5..7bc4ba2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/change_to_test.dart
@@ -99,6 +99,19 @@
''');
}
+ Future<void> test_class_implements() async {
+ await resolveTestUnit('''
+class MyClass implements BaseClssa {}
+
+class BaseClass {}
+''');
+ await assertHasFix('''
+class MyClass implements BaseClass {}
+
+class BaseClass {}
+''');
+ }
+
Future<void> test_class_prefixed() async {
await resolveTestUnit('''
import 'dart:async' as c;
@@ -116,6 +129,19 @@
''');
}
+ Future<void> test_class_with() async {
+ await resolveTestUnit('''
+class MyClass with BaseClssa {}
+
+class BaseClass {}
+''');
+ await assertHasFix('''
+class MyClass with BaseClass {}
+
+class BaseClass {}
+''');
+ }
+
Future<void> test_function_fromImport() async {
await resolveTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_class_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_class_test.dart
index f930fe9..82181b0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_class_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_class_test.dart
@@ -60,6 +60,18 @@
await assertNoFix();
}
+ Future<void> test_implements() async {
+ await resolveTestUnit('''
+class MyClass implements BaseClass {}
+''');
+ await assertHasFix('''
+class MyClass implements BaseClass {}
+
+class BaseClass {
+}
+''');
+ }
+
Future<void> test_inLibraryOfPrefix() async {
addSource('/home/test/lib/lib.dart', r'''
class A {}
@@ -207,4 +219,16 @@
''');
assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
}
+
+ Future<void> test_with() async {
+ await resolveTestUnit('''
+class MyClass with BaseClass {}
+''');
+ await assertHasFix('''
+class MyClass with BaseClass {}
+
+class BaseClass {
+}
+''');
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/import_library_sdk_test.dart b/pkg/analysis_server/test/src/services/correction/fix/import_library_sdk_test.dart
index dd87b99..b504421 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/import_library_sdk_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/import_library_sdk_test.dart
@@ -58,6 +58,17 @@
''');
}
+ Future<void> test_withClass_implements() async {
+ await resolveTestUnit('''
+class MyCompleter implements Completer<String> {}
+''');
+ await assertHasFix('''
+import 'dart:async';
+
+class MyCompleter implements Completer<String> {}
+''');
+ }
+
Future<void> test_withClass_instanceCreation_explicitNew() async {
await resolveTestUnit('''
class C {
@@ -253,6 +264,17 @@
''');
}
+ Future<void> test_withClass_with() async {
+ await resolveTestUnit('''
+class MyCompleter with Completer<String> {}
+''');
+ await assertHasFix('''
+import 'dart:async';
+
+class MyCompleter with Completer<String> {}
+''');
+ }
+
Future<void> test_withTopLevelVariable() async {
await resolveTestUnit('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
index 8d6e2f5..e6154ba 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/make_final_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,6 +13,7 @@
void main() {
defineReflectiveSuite(() {
defineReflectiveTests(MakeFinalTest);
+ defineReflectiveTests(MakeFinalWithNNBDTest);
});
}
@@ -53,3 +55,45 @@
''');
}
}
+
+@reflectiveTest
+class MakeFinalWithNNBDTest extends FixProcessorLintTest {
+ @override
+ List<String> get experiments => [EnableString.non_nullable];
+
+ @override
+ FixKind get kind => DartFixKind.MAKE_FINAL;
+
+ @override
+ String get lintCode => LintNames.prefer_final_fields;
+
+ Future<void> test_lateField_type() async {
+ await resolveTestUnit('''
+class C {
+ late int _f = 2;
+ int get g => _f;
+}
+''');
+ await assertHasFix('''
+class C {
+ late final int _f = 2;
+ int get g => _f;
+}
+''');
+ }
+
+ Future<void> test_lateField_var() async {
+ await resolveTestUnit('''
+class C {
+ late var _f = 2;
+ int get g => _f;
+}
+''');
+ await assertHasFix('''
+class C {
+ late final _f = 2;
+ int get g => _f;
+}
+''');
+ }
+}
diff --git a/pkg/analysis_server/test/stress/completion/completion_runner.dart b/pkg/analysis_server/test/stress/completion/completion_runner.dart
index 3fae840..2fb69b3 100644
--- a/pkg/analysis_server/test/stress/completion/completion_runner.dart
+++ b/pkg/analysis_server/test/stress/completion/completion_runner.dart
@@ -101,7 +101,10 @@
timer.start();
var request =
CompletionRequestImpl(result, offset, false, performance);
- var suggestions = await contributor.computeSuggestions(request);
+ var suggestions = await contributor.computeSuggestions(
+ request,
+ enableUriContributor: true,
+ );
timer.stop();
if (!identifier.inDeclarationContext() &&
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index 559dd24..ce02311 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -218,9 +218,13 @@
/// to break the text when building edits.
List<int> _getBreakOffsets(String text) {
var breakOffsets = <int>[];
+ var featureSet = FeatureSet.forTesting(sdkVersion: '2.2.2');
var scanner = Scanner(null, CharSequenceReader(text),
error.AnalysisErrorListener.NULL_LISTENER)
- ..configureFeatures(FeatureSet.forTesting(sdkVersion: '2.2.2'));
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
// TODO(brianwilkerson) Randomize. Sometimes add zero (0) as a break point.
while (token.type != TokenType.EOF) {
diff --git a/pkg/analysis_server/test/verify_sorted_test.dart b/pkg/analysis_server/test/verify_sorted_test.dart
index d0efc72..858f7c4 100644
--- a/pkg/analysis_server/test/verify_sorted_test.dart
+++ b/pkg/analysis_server/test/verify_sorted_test.dart
@@ -20,6 +20,10 @@
buildTestsForAnalysisServer();
});
+ group('analyzer', () {
+ buildTestsForAnalyzer();
+ });
+
group('analyzer_cli', () {
buildTestsForAnalyzerCli();
});
@@ -80,6 +84,18 @@
);
}
+void buildTestsForAnalyzer() {
+ buildTests(
+ packagePath: 'analyzer',
+ excludedPaths: [
+ 'lib/src/context/packages.dart',
+ 'lib/src/dart/error/syntactic_errors.g.dart',
+ 'lib/src/summary/format.dart',
+ 'test/generated/test_all.dart',
+ ],
+ );
+}
+
void buildTestsForAnalyzerCli() {
buildTests(
packagePath: 'analyzer_cli',
diff --git a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
index 7f9cd67..f5483ea 100644
--- a/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
+++ b/pkg/analysis_server/tool/completion_metrics/completion_metrics.dart
@@ -627,8 +627,12 @@
if (declarationsTracker == null) {
// available suggestions == false
suggestions = await DartCompletionManager(
- dartdocDirectiveInfo: DartdocDirectiveInfo(), listener: listener)
- .computeSuggestions(request);
+ dartdocDirectiveInfo: DartdocDirectiveInfo(),
+ listener: listener,
+ ).computeSuggestions(
+ request,
+ enableUriContributor: true,
+ );
} else {
// available suggestions == true
var includedElementKinds = <protocol.ElementKind>{};
@@ -637,13 +641,15 @@
<protocol.IncludedSuggestionRelevanceTag>[];
var includedSuggestionSetList = <protocol.IncludedSuggestionSet>[];
suggestions = await DartCompletionManager(
- dartdocDirectiveInfo: DartdocDirectiveInfo(),
- includedElementKinds: includedElementKinds,
- includedElementNames: includedElementNames,
- includedSuggestionRelevanceTags:
- includedSuggestionRelevanceTagList,
- listener: listener)
- .computeSuggestions(request);
+ dartdocDirectiveInfo: DartdocDirectiveInfo(),
+ includedElementKinds: includedElementKinds,
+ includedElementNames: includedElementNames,
+ includedSuggestionRelevanceTags: includedSuggestionRelevanceTagList,
+ listener: listener,
+ ).computeSuggestions(
+ request,
+ enableUriContributor: true,
+ );
computeIncludedSetList(declarationsTracker, request.result,
includedSuggestionSetList, includedElementNames);
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index a96bd24..8d41b70 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -8,10 +8,10 @@
## Running the Server
-The analysis server snapshot is included in the `bin/snapshots` folder of the Dart SDK. Pass the `--lsp` flag to start the server in LSP mode:
+The analysis server snapshot is included in the `bin/snapshots` folder of the Dart SDK. Pass the `--lsp` flag to start the server in LSP mode and the `--client-id` and `--client-version` flags to identify your editor/plugin and version:
```
-dart bin/snapshots/analysis_server.dart.snapshot --lsp
+dart bin/snapshots/analysis_server.dart.snapshot --lsp --client-id my-editor.my-plugin --client-version 1.2
```
Note: In LSP the client makes the first request so there is no obvious confirmation that the server is working correctly until the client sends an `initialize` request. Unlike standard JSON RPC, [LSP requires that headers are sent](https://microsoft.github.io/language-server-protocol/specification).
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/FoldingKind.java b/pkg/analysis_server/tool/spec/generated/java/types/FoldingKind.java
index 8ae6957..be9f538 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/FoldingKind.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/FoldingKind.java
@@ -17,6 +17,8 @@
public static final String ANNOTATIONS = "ANNOTATIONS";
+ public static final String BLOCK = "BLOCK";
+
public static final String CLASS_BODY = "CLASS_BODY";
public static final String DIRECTIVES = "DIRECTIVES";
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 097bc1a..81cfb21 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
<body>
<h1>Analysis Server API Specification</h1>
<h1 style="color:#999999">Version
- <version>1.27.4</version>
+ <version>1.28.0</version>
</h1>
<p>
This document contains a specification of the API provided by the
@@ -126,6 +126,13 @@
That is, in some cases it may return responses with the currently available
results while it's catching up with unprocessed changes.
</p>
+<h3>Enumerations</h3>
+<p>
+ Responses from the server may include enumerations indicating the kind of a
+ specific item. The enums may be extended with new values in future versions of
+ the server so clients should ensure unknown values are handled gracefully, either
+ ignoring the item or treating it with some default/fallback handling.
+</p>
<h3>Domains</h3>
<p>
For convenience, the API is divided into domains. Each domain is specified
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 6e51b61..2a888ca 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
// To regenerate the file, use the script
// "pkg/analysis_server/tool/spec/generate_files".
-const String PROTOCOL_VERSION = '1.27.4';
+const String PROTOCOL_VERSION = '1.28.0';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index 3c53fd0..c38b4a3 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -125,7 +125,10 @@
var errorCollector = _ErrorCollector();
var reader = CharSequenceReader(contents);
var scanner = Scanner(source, reader, errorCollector)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
var parser = Parser(
source,
@@ -152,7 +155,10 @@
var reader = CharSequenceReader(contents);
var errorCollector = _ErrorCollector();
var scanner = Scanner(source, reader, errorCollector)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
var parser = Parser(
source,
diff --git a/pkg/analyzer/lib/dart/analysis/session.dart b/pkg/analyzer/lib/dart/analysis/session.dart
index a9ad412..89e113b 100644
--- a/pkg/analyzer/lib/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/dart/analysis/session.dart
@@ -9,9 +9,9 @@
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/uri_converter.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeSystem;
import 'package:analyzer/src/generated/source.dart';
@@ -57,6 +57,10 @@
/// a result state indicating the nature of the problem.
Future<ErrorsResult> getErrors(String path);
+ /// Return information about the file at the given absolute, normalized
+ /// [path].
+ FileResult getFile(String path);
+
/// Return a future that will complete with the library element representing
/// the library with the given [uri].
Future<LibraryElement> getLibraryByUri(String uri);
@@ -92,10 +96,6 @@
/// absolute, normalized [path].
ParsedUnitResult getParsedUnit(String path);
- /// Return information about the file at the given absolute, normalized
- /// [path].
- FileResult getFile(String path);
-
/// Return a future that will complete with information about the results of
/// resolving the file with the given absolute, normalized [path].
///
diff --git a/pkg/analyzer/lib/dart/analysis/utilities.dart b/pkg/analyzer/lib/dart/analysis/utilities.dart
index c2aec9e..2103cbb 100644
--- a/pkg/analyzer/lib/dart/analysis/utilities.dart
+++ b/pkg/analyzer/lib/dart/analysis/utilities.dart
@@ -116,7 +116,10 @@
var reader = CharSequenceReader(content);
var errorCollector = RecordingErrorListener();
var scanner = Scanner(source, reader, errorCollector)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
var parser = Parser(
source,
diff --git a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
index 5183048..b73866b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/feature_set_provider.dart
@@ -68,6 +68,10 @@
/// Each individual file might use `// @dart` to override this version, to
/// be either lower, or higher than the package language version.
Version getLanguageVersion(String path, Uri uri) {
+ if (uri.isScheme('dart')) {
+ return ExperimentStatus.currentVersion;
+ }
+
var package = _packages.packageForPath(path);
if (package != null) {
var languageVersion = package.languageVersion;
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 3339fb8a..55b247c 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -115,12 +115,21 @@
final bool isInExternalSummaries;
/**
- * The default [FeatureSet] for the file path and URI.
+ * The [FeatureSet] for all files in the analysis context.
*
- * The actual language version, and the feature set, of the file might be
- * different, if `@dart` is specified in the file header.
+ * Usually it is the feature set of the latest language version, plus
+ * possibly additional enabled experiments (from the analysis options file,
+ * or from SDK allowed experiments).
+ *
+ * This feature set is then restricted, with the [_packageLanguageVersion],
+ * or with a `@dart` language override token in the file header.
*/
- final FeatureSet _featureSet;
+ final FeatureSet _contextFeatureSet;
+
+ /**
+ * The language version for the package that contains this file.
+ */
+ final Version _packageLanguageVersion;
bool _exists;
String _content;
@@ -153,15 +162,22 @@
*/
bool hasErrorOrWarning = false;
- FileState._(this._fsState, this.path, this.uri, this.source, this._featureSet)
- : isInExternalSummaries = false;
+ FileState._(
+ this._fsState,
+ this.path,
+ this.uri,
+ this.source,
+ this._contextFeatureSet,
+ this._packageLanguageVersion,
+ ) : isInExternalSummaries = false;
FileState._external(this._fsState, this.uri)
: isInExternalSummaries = true,
path = null,
source = null,
_exists = true,
- _featureSet = null {
+ _contextFeatureSet = null,
+ _packageLanguageVersion = null {
_apiSignature = Uint8List(16);
_libraryCycle = LibraryCycle.external();
}
@@ -419,7 +435,8 @@
{
var signature = ApiSignature();
signature.addUint32List(_fsState._unlinkedSalt);
- signature.addFeatureSet(_featureSet);
+ signature.addFeatureSet(_contextFeatureSet);
+ signature.addLanguageVersion(_packageLanguageVersion);
signature.addString(_contentHash);
signature.addBool(_exists);
contentSignature = signature.toByteList();
@@ -548,7 +565,7 @@
return astFactory.compilationUnit(
beginToken: token,
endToken: token,
- featureSet: _featureSet,
+ featureSet: _contextFeatureSet,
)..lineInfo = LineInfo(const <int>[0]);
}
@@ -571,36 +588,6 @@
return _fsState.getFileForUri(absoluteUri);
}
- /// Return the language version specified in the [versionToken], or the
- /// language version from the [FeatureSetProvider].
- Version _getLanguageVersion(
- LanguageVersionToken versionToken,
- AnalysisErrorListener errorListener,
- ) {
- if (versionToken != null) {
- var latestVersion = ExperimentStatus.currentVersion;
- if (versionToken.major > latestVersion.major ||
- versionToken.major == latestVersion.major &&
- versionToken.minor > latestVersion.minor) {
- errorListener.onError(
- AnalysisError(
- source,
- versionToken.offset,
- versionToken.length,
- HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
- [latestVersion.major, latestVersion.minor],
- ),
- );
- // Fall-through, use the package language version.
- } else {
- return Version(versionToken.major, versionToken.minor, 0);
- }
- }
-
- var featureSetProvider = _fsState.featureSetProvider;
- return featureSetProvider.getLanguageVersion(path, uri);
- }
-
/**
* Invalidate any data that depends on the current unlinked data of the file,
* because [refresh] is going to recompute the unlinked data.
@@ -627,23 +614,22 @@
CharSequenceReader reader = CharSequenceReader(content);
Scanner scanner = Scanner(source, reader, errorListener)
- ..configureFeatures(_featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: _contextFeatureSet,
+ featureSet: _contextFeatureSet.restrictToVersion(
+ _packageLanguageVersion,
+ ),
+ );
Token token = PerformanceStatistics.scan.makeCurrentWhile(() {
return scanner.tokenize(reportScannerErrors: false);
});
LineInfo lineInfo = LineInfo(scanner.lineStarts);
- var languageVersion = _getLanguageVersion(
- scanner.languageVersion,
- errorListener,
- );
- var featureSet = _featureSet.restrictToVersion(languageVersion);
-
bool useFasta = analysisOptions.useFastaParser;
Parser parser = Parser(
source,
errorListener,
- featureSet: featureSet,
+ featureSet: scanner.featureSet,
useFasta: useFasta,
);
parser.enableOptionalNewAndConst = true;
@@ -653,10 +639,6 @@
try {
unit = parser.parseCompilationUnit(token);
unit.lineInfo = lineInfo;
-
- var unitImpl = unit as CompilationUnitImpl;
- unitImpl.languageVersionMajor = languageVersion.major;
- unitImpl.languageVersionMinor = languageVersion.minor;
} catch (e) {
throw StateError('''
Parser error.
@@ -666,6 +648,8 @@
''');
}
+ _setLanguageVersion(unit, scanner.languageVersion, errorListener);
+
// StringToken uses a static instance of StringCanonicalizer, so we need
// to clear it explicitly once we are done using it for this file.
StringToken.canonicalizer.clear();
@@ -687,6 +671,40 @@
return directive.uri;
}
+ /// Set the language version for the file, from the [versionToken], or from
+ /// the package language version.
+ void _setLanguageVersion(
+ CompilationUnit unit,
+ LanguageVersionToken versionToken,
+ AnalysisErrorListener errorListener,
+ ) {
+ var languageVersion = _packageLanguageVersion;
+
+ if (versionToken != null) {
+ var latestVersion = ExperimentStatus.currentVersion;
+ if (versionToken.major > latestVersion.major ||
+ versionToken.major == latestVersion.major &&
+ versionToken.minor > latestVersion.minor) {
+ errorListener.onError(
+ AnalysisError(
+ source,
+ versionToken.offset,
+ versionToken.length,
+ HintCode.INVALID_LANGUAGE_VERSION_OVERRIDE_GREATER,
+ [latestVersion.major, latestVersion.minor],
+ ),
+ );
+ // Fall-through, use the package language version.
+ } else {
+ languageVersion = Version(versionToken.major, versionToken.minor, 0);
+ }
+ }
+
+ var unitImpl = unit as CompilationUnitImpl;
+ unitImpl.languageVersionMajor = languageVersion.major;
+ unitImpl.languageVersionMinor = languageVersion.minor;
+ }
+
static UnlinkedUnit2Builder serializeAstUnlinked2(CompilationUnit unit) {
var exports = <UnlinkedNamespaceDirectiveBuilder>[];
var imports = <UnlinkedNamespaceDirectiveBuilder>[];
@@ -895,7 +913,8 @@
FileState get unresolvedFile {
if (_unresolvedFile == null) {
var featureSet = FeatureSet.fromEnableFlags([]);
- _unresolvedFile = FileState._(this, null, null, null, featureSet);
+ _unresolvedFile = FileState._(
+ this, null, null, null, featureSet, ExperimentStatus.currentVersion);
_unresolvedFile.refresh();
}
return _unresolvedFile;
@@ -924,7 +943,10 @@
// Create a new file.
FileSource uriSource = FileSource(resource, uri);
FeatureSet featureSet = featureSetProvider.getFeatureSet(path, uri);
- file = FileState._(this, path, uri, uriSource, featureSet);
+ Version packageLanguageVersion =
+ featureSetProvider.getLanguageVersion(path, uri);
+ file = FileState._(
+ this, path, uri, uriSource, featureSet, packageLanguageVersion);
_uriToFile[uri] = file;
_addFileWithPath(path, file);
_pathToCanonicalFile[path] = file;
@@ -966,7 +988,10 @@
File resource = _resourceProvider.getFile(path);
FileSource source = FileSource(resource, uri);
FeatureSet featureSet = featureSetProvider.getFeatureSet(path, uri);
- file = FileState._(this, path, uri, source, featureSet);
+ Version packageLanguageVersion =
+ featureSetProvider.getLanguageVersion(path, uri);
+ file = FileState._(
+ this, path, uri, source, featureSet, packageLanguageVersion);
_uriToFile[uri] = file;
_addFileWithPath(path, file);
file.refresh(allowCached: true);
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 48fd360..66699d4 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -10,13 +10,6 @@
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/builder.dart';
-import 'package:analyzer/src/error/best_practices_verifier.dart';
-import 'package:analyzer/src/error/dart2js_verifier.dart';
-import 'package:analyzer/src/error/dead_code_verifier.dart';
-import 'package:analyzer/src/error/language_version_override_verifier.dart';
-import 'package:analyzer/src/error/override_verifier.dart';
-import 'package:analyzer/src/error/todo_finder.dart';
-import 'package:analyzer/src/error/unused_local_elements_verifier.dart';
import 'package:analyzer/src/dart/analysis/file_state.dart';
import 'package:analyzer/src/dart/analysis/testing_data.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
@@ -32,9 +25,16 @@
import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
import 'package:analyzer/src/dart/resolver/legacy_type_asserter.dart';
import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
+import 'package:analyzer/src/error/best_practices_verifier.dart';
import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/error/dart2js_verifier.dart';
+import 'package:analyzer/src/error/dead_code_verifier.dart';
import 'package:analyzer/src/error/imports_verifier.dart';
import 'package:analyzer/src/error/inheritance_override.dart';
+import 'package:analyzer/src/error/language_version_override_verifier.dart';
+import 'package:analyzer/src/error/override_verifier.dart';
+import 'package:analyzer/src/error/todo_finder.dart';
+import 'package:analyzer/src/error/unused_local_elements_verifier.dart';
import 'package:analyzer/src/generated/declaration_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error_verifier.dart';
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index b1077be..54ec8b9 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -12,13 +12,10 @@
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/error/listener.dart';
import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/fasta/token_utils.dart' as util show findPrevious;
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
import 'package:analyzer/src/generated/engine.dart';
@@ -2355,44 +2352,6 @@
}
}
-/// An error listener that only records whether any constant related errors have
-/// been reported.
-class ConstantAnalysisErrorListener extends AnalysisErrorListener {
- /// A flag indicating whether any constant related errors have been reported
- /// to this listener.
- bool hasConstError = false;
-
- @override
- void onError(AnalysisError error) {
- ErrorCode errorCode = error.errorCode;
- if (errorCode is CompileTimeErrorCode) {
- switch (errorCode) {
- case CompileTimeErrorCode
- .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
- case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL:
- case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT:
- case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING:
- case CompileTimeErrorCode.CONST_EVAL_TYPE_INT:
- case CompileTimeErrorCode.CONST_EVAL_TYPE_NUM:
- case CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION:
- case CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE:
- case CompileTimeErrorCode.CONST_WITH_NON_CONST:
- case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
- case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:
- case CompileTimeErrorCode.INVALID_CONSTANT:
- case CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL:
- case CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL:
- case CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL:
- case CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT:
- case CompileTimeErrorCode.NON_CONSTANT_MAP_KEY:
- case CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE:
- case CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT:
- hasConstError = true;
- }
- }
- }
-}
-
/// A constructor declaration.
///
/// constructorDeclaration ::=
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 7641697..325c71a 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -112,7 +112,9 @@
void visitConstructorDeclaration(ConstructorDeclaration node) {
if (node.constKeyword != null) {
_validateConstructorInitializers(node);
- _validateFieldInitializers(node.parent, node);
+ if (node.factoryKeyword == null) {
+ _validateFieldInitializers(node.parent, node);
+ }
}
_validateDefaultValues(node.parameters);
super.visitConstructorDeclaration(node);
@@ -130,6 +132,8 @@
TypeName typeName = node.constructorName.type;
_checkForConstWithTypeParameters(typeName);
+ node.argumentList.accept(this);
+
// We need to evaluate the constant to see if any errors occur during its
// evaluation.
ConstructorElement constructor = node.constructorName.staticElement;
diff --git a/pkg/analyzer/lib/src/dart/error/lint_codes.dart b/pkg/analyzer/lib/src/dart/error/lint_codes.dart
index 22c0965..313c98e 100644
--- a/pkg/analyzer/lib/src/dart/error/lint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/lint_codes.dart
@@ -20,9 +20,6 @@
int get hashCode => uniqueName.hashCode;
@override
- bool operator ==(other) => uniqueName == other.uniqueName;
-
- @override
ErrorType get type => ErrorType.LINT;
/// Overridden so that [LintCode] and its subclasses share the same uniqueName
@@ -33,6 +30,9 @@
@override
String get url => 'https://dart-lang.github.io/linter/lints/$name.html';
+
+ @override
+ bool operator ==(other) => uniqueName == other.uniqueName;
}
/// Defines security-related best practice recommendations.
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index 29c35f2..54f9035 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -30,6 +30,7 @@
import 'package:analyzer/src/error/imports_verifier.dart';
import 'package:analyzer/src/error/inheritance_override.dart';
import 'package:analyzer/src/error/override_verifier.dart';
+import 'package:analyzer/src/error/todo_finder.dart';
import 'package:analyzer/src/error/unused_local_elements_verifier.dart';
import 'package:analyzer/src/generated/declaration_resolver.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -45,7 +46,6 @@
import 'package:analyzer/src/task/strong/checker.dart';
import 'package:analyzer/src/workspace/workspace.dart';
import 'package:pub_semver/pub_semver.dart';
-import 'package:analyzer/src/error/todo_finder.dart';
var timerLibraryAnalyzer = Stopwatch();
var timerLibraryAnalyzerConst = Stopwatch();
@@ -369,23 +369,6 @@
}
}
- WorkspacePackage _getPackage(CompilationUnit unit) {
- final libraryPath = _library.source.fullName;
- Workspace workspace =
- unit.declaredElement.session?.analysisContext?.workspace;
-
- // If there is no driver setup (as in test environments), we need to create
- // a workspace ourselves.
- // todo (pq): fix tests or otherwise de-dup this logic shared w/ resolver.
- if (workspace == null) {
- final builder = ContextBuilder(
- _resourceProvider, null /* sdkManager */, null /* contentCache */);
- workspace = ContextBuilder.createWorkspace(
- _resourceProvider, libraryPath, builder);
- }
- return workspace?.findPackageFor(libraryPath);
- }
-
void _computeVerifyErrors(FileState file, CompilationUnit unit) {
if (file.source == null) {
return;
@@ -477,6 +460,34 @@
}
/**
+ * Catch all exceptions from the `getFileContent` function.
+ */
+ String _getFileContent(String path) {
+ try {
+ return getFileContent(path);
+ } catch (_) {
+ return '';
+ }
+ }
+
+ WorkspacePackage _getPackage(CompilationUnit unit) {
+ final libraryPath = _library.source.fullName;
+ Workspace workspace =
+ unit.declaredElement.session?.analysisContext?.workspace;
+
+ // If there is no driver setup (as in test environments), we need to create
+ // a workspace ourselves.
+ // todo (pq): fix tests or otherwise de-dup this logic shared w/ resolver.
+ if (workspace == null) {
+ final builder = ContextBuilder(
+ _resourceProvider, null /* sdkManager */, null /* contentCache */);
+ workspace = ContextBuilder.createWorkspace(
+ _resourceProvider, libraryPath, builder);
+ }
+ return workspace?.findPackageFor(libraryPath);
+ }
+
+ /**
* Return the name of the library that the given part is declared to be a
* part of, or `null` if the part does not contain a part-of directive.
*/
@@ -793,17 +804,6 @@
}
/**
- * Catch all exceptions from the `getFileContent` function.
- */
- String _getFileContent(String path) {
- try {
- return getFileContent(path);
- } catch (_) {
- return '';
- }
- }
-
- /**
* Return `true` if the given [source] refers to a file that is assumed to be
* generated.
*/
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index 566ffa9..f4b50dd 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -127,7 +127,10 @@
CharSequenceReader reader = CharSequenceReader(content);
Scanner scanner = Scanner(source, reader, errorListener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token token = PerformanceStatistics.scan.makeCurrentWhile(() {
return scanner.tokenize(reportScannerErrors: false);
});
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 0d2bb29..74d6026 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -76,6 +76,25 @@
_LibraryContext libraryContext;
+ FileResolver(
+ PerformanceLog logger,
+ ResourceProvider resourceProvider,
+ @deprecated ByteStore byteStore,
+ SourceFactory sourceFactory,
+ String Function(String path) getFileDigest,
+ void Function(List<String> paths) prefetchFiles, {
+ @required Workspace workspace,
+ Duration libraryContextResetTimeout = const Duration(seconds: 60),
+ }) : this.from(
+ logger: logger,
+ resourceProvider: resourceProvider,
+ sourceFactory: sourceFactory,
+ getFileDigest: getFileDigest,
+ prefetchFiles: prefetchFiles,
+ workspace: workspace,
+ libraryContextResetTimeout: libraryContextResetTimeout,
+ );
+
FileResolver.from({
@required PerformanceLog logger,
@required ResourceProvider resourceProvider,
@@ -99,25 +118,6 @@
);
}
- FileResolver(
- PerformanceLog logger,
- ResourceProvider resourceProvider,
- @deprecated ByteStore byteStore,
- SourceFactory sourceFactory,
- String Function(String path) getFileDigest,
- void Function(List<String> paths) prefetchFiles, {
- @required Workspace workspace,
- Duration libraryContextResetTimeout = const Duration(seconds: 60),
- }) : this.from(
- logger: logger,
- resourceProvider: resourceProvider,
- sourceFactory: sourceFactory,
- getFileDigest: getFileDigest,
- prefetchFiles: prefetchFiles,
- workspace: workspace,
- libraryContextResetTimeout: libraryContextResetTimeout,
- );
-
FeatureSet get defaultFeatureSet => FeatureSet.fromEnableFlags([]);
/// Update the resolver to reflect the fact that the file with the given
diff --git a/pkg/analyzer/lib/src/dart/resolver/variance.dart b/pkg/analyzer/lib/src/dart/resolver/variance.dart
index e9565be..34962c9 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variance.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variance.dart
@@ -72,6 +72,20 @@
return unrelated;
}
+ /// Return the variance associated with the string representation of variance.
+ factory Variance.fromKeywordString(String varianceString) {
+ if (varianceString == "in") {
+ return contravariant;
+ } else if (varianceString == "inout") {
+ return invariant;
+ } else if (varianceString == "out") {
+ return covariant;
+ } else if (varianceString == "unrelated") {
+ return unrelated;
+ }
+ throw ArgumentError('Invalid keyword string for variance: $varianceString');
+ }
+
/// Initialize a newly created variance to have the given [encoding].
const Variance._(this._encoding);
@@ -90,37 +104,6 @@
throw ArgumentError('Invalid encoding for variance: $encoding');
}
- /// Return the variance associated with the string representation of variance.
- factory Variance.fromKeywordString(String varianceString) {
- if (varianceString == "in") {
- return contravariant;
- } else if (varianceString == "inout") {
- return invariant;
- } else if (varianceString == "out") {
- return covariant;
- } else if (varianceString == "unrelated") {
- return unrelated;
- }
- throw ArgumentError('Invalid keyword string for variance: $varianceString');
- }
-
- /// Returns the associated keyword lexeme.
- String toKeywordString() {
- switch (this) {
- case contravariant:
- return 'in';
- case invariant:
- return 'inout';
- case covariant:
- return 'out';
- case unrelated:
- return '';
- default:
- throw ArgumentError(
- 'Missing keyword lexeme representation for variance: $this');
- }
- }
-
/// Return `true` if this represents the case when `X` occurs free in `T`, and
/// `U <: V` implies `[V/X]T <: [U/X]T`.
bool get isContravariant => this == contravariant;
@@ -174,18 +157,6 @@
return this == other ? covariant : contravariant;
}
- /// Variance values form a lattice where unrelated is the top, invariant
- /// is the bottom, and covariant and contravariant are incomparable.
- /// [meet] calculates the meet of two elements of such lattice. It can be
- /// used, for example, to calculate the variance of a typedef type parameter
- /// if it's encountered on the RHS of the typedef multiple times.
- ///
- /// unrelated
- /// covariant contravariant
- /// invariant
- Variance meet(Variance other) =>
- Variance._fromEncoding(_encoding | other._encoding);
-
/// Returns true if this variance is greater than (above) or equal to the
/// [other] variance in the partial order induced by the variance lattice.
///
@@ -204,4 +175,33 @@
return other.isInvariant;
}
}
+
+ /// Variance values form a lattice where unrelated is the top, invariant
+ /// is the bottom, and covariant and contravariant are incomparable.
+ /// [meet] calculates the meet of two elements of such lattice. It can be
+ /// used, for example, to calculate the variance of a typedef type parameter
+ /// if it's encountered on the RHS of the typedef multiple times.
+ ///
+ /// unrelated
+ /// covariant contravariant
+ /// invariant
+ Variance meet(Variance other) =>
+ Variance._fromEncoding(_encoding | other._encoding);
+
+ /// Returns the associated keyword lexeme.
+ String toKeywordString() {
+ switch (this) {
+ case contravariant:
+ return 'in';
+ case invariant:
+ return 'inout';
+ case covariant:
+ return 'out';
+ case unrelated:
+ return '';
+ default:
+ throw ArgumentError(
+ 'Missing keyword lexeme representation for variance: $this');
+ }
+ }
}
diff --git a/pkg/analyzer/lib/src/dart/scanner/scanner.dart b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
index 859db3f..5003402 100644
--- a/pkg/analyzer/lib/src/dart/scanner/scanner.dart
+++ b/pkg/analyzer/lib/src/dart/scanner/scanner.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:meta/meta.dart';
import 'package:pub_semver/pub_semver.dart';
export 'package:analyzer/src/dart/error/syntactic_errors.dart';
@@ -47,6 +48,13 @@
final AnalysisErrorListener _errorListener;
/**
+ * If the file has [fasta.LanguageVersionToken], it is allowed to use the
+ * language version greater than the one specified in the package config.
+ * So, we need to know the full feature set for the context.
+ */
+ FeatureSet _featureSetForOverriding;
+
+ /**
* The flag specifying whether documentation comments should be parsed.
*/
bool _preserveComments = true;
@@ -124,7 +132,11 @@
/// TODO(paulberry): stop exposing `enableGtGtGt` and `enableNonNullable` so
/// that callers are forced to use this API. Note that this would be a
/// breaking change.
- void configureFeatures(FeatureSet featureSet) {
+ void configureFeatures({
+ @required FeatureSet featureSetForOverriding,
+ @required FeatureSet featureSet,
+ }) {
+ this._featureSetForOverriding = featureSetForOverriding;
this._featureSet = featureSet;
enableGtGtGt = featureSet.isEnabled(Feature.triple_shift);
enableNonNullable = featureSet.isEnabled(Feature.non_nullable);
@@ -200,8 +212,9 @@
if (languageVersion.major >= 0 && languageVersion.minor >= 0) {
_languageVersion = languageVersion;
if (_featureSet != null) {
- _featureSet = _featureSet.restrictToVersion(
- Version(languageVersion.major, languageVersion.minor, 0));
+ _featureSet = _featureSetForOverriding.restrictToVersion(
+ Version(languageVersion.major, languageVersion.minor, 0),
+ );
scanner.configuration = buildConfig(_featureSet);
}
}
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index db8fafb..a9378b7 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -175,6 +175,9 @@
}
@override
+ void beginAsOperatorType(Token asOperator) {}
+
+ @override
void beginCascade(Token token) {
assert(optional('..', token) || optional('?..', token));
debugEvent("beginCascade");
@@ -257,6 +260,9 @@
}
@override
+ void beginIsOperatorType(Token asOperator) {}
+
+ @override
void beginLiteralString(Token literalString) {
assert(identical(literalString.kind, STRING_TOKEN));
debugEvent("beginLiteralString");
@@ -540,6 +546,11 @@
}
@override
+ void endAsOperatorType(Token asOperator) {
+ debugEvent("AsOperatorType");
+ }
+
+ @override
void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis,
Token comma, Token semicolon) {
assert(optional('assert', assertKeyword));
@@ -1682,6 +1693,11 @@
}
@override
+ void endIsOperatorType(Token asOperator) {
+ debugEvent("IsOperatorType");
+ }
+
+ @override
void endLabeledStatement(int labelCount) {
debugEvent("LabeledStatement");
@@ -2293,14 +2309,6 @@
}
@override
- void beginAsOperatorType(Token asOperator) {}
-
- @override
- void endAsOperatorType(Token asOperator) {
- debugEvent("AsOperatorType");
- }
-
- @override
void handleAsOperator(Token asOperator) {
assert(optional('as', asOperator));
debugEvent("AsOperator");
@@ -2864,14 +2872,6 @@
}
@override
- void beginIsOperatorType(Token asOperator) {}
-
- @override
- void endIsOperatorType(Token asOperator) {
- debugEvent("IsOperatorType");
- }
-
- @override
void handleIsOperator(Token isOperator, Token not) {
assert(optional('is', isOperator));
assert(optionalOrNull('!', not));
diff --git a/pkg/analyzer/lib/src/file_system/file_system.dart b/pkg/analyzer/lib/src/file_system/file_system.dart
index 28bd8b2..a6f128f 100644
--- a/pkg/analyzer/lib/src/file_system/file_system.dart
+++ b/pkg/analyzer/lib/src/file_system/file_system.dart
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/util/uri.dart';
/**
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 1e0e343..17069da 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1845,29 +1845,6 @@
}
}
- void _checkForConflictingGenerics(NamedCompilationUnitMember node) {
- var element = node.declaredElement as ClassElement;
-
- var analysisSession = _currentLibrary.session as AnalysisSessionImpl;
- var errors = analysisSession.classHierarchy.errors(element);
-
- for (var error in errors) {
- if (error is IncompatibleInterfacesClassHierarchyError) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
- node,
- [
- _enclosingClass.name,
- error.first.getDisplayString(withNullability: true),
- error.second.getDisplayString(withNullability: true),
- ],
- );
- } else {
- throw UnimplementedError('${error.runtimeType}');
- }
- }
- }
-
/**
* Verify all conflicts between type variable and enclosing class.
* TODO(scheglov)
@@ -1924,6 +1901,29 @@
}
}
+ void _checkForConflictingGenerics(NamedCompilationUnitMember node) {
+ var element = node.declaredElement as ClassElement;
+
+ var analysisSession = _currentLibrary.session as AnalysisSessionImpl;
+ var errors = analysisSession.classHierarchy.errors(element);
+
+ for (var error in errors) {
+ if (error is IncompatibleInterfacesClassHierarchyError) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
+ node,
+ [
+ _enclosingClass.name,
+ error.first.getDisplayString(withNullability: true),
+ error.second.getDisplayString(withNullability: true),
+ ],
+ );
+ } else {
+ throw UnimplementedError('${error.runtimeType}');
+ }
+ }
+ }
+
/// Verify that if the given [constructor] declaration is 'const' then there
/// are no invocations of non-'const' super constructors, and that there are
/// no instance variables mixed in.
@@ -5395,12 +5395,10 @@
return false;
}
- // For `C?.foo()` the type of `C` is not set, it is not an expression.
+ // For `foo?.bar`, `foo` must be an identifier with a value.
if (node is Identifier) {
var element = node.staticElement;
- if (element is ClassElement || element is ExtensionElement) {
- return false;
- }
+ return element is PropertyAccessorElement || element is VariableElement;
}
return true;
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index a0d763d..f5f1b19 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -163,6 +163,9 @@
element.name == 'DynamicLibraryExtension' &&
element.library.name == 'dart.ffi';
+ bool _isHandle(Element element) =>
+ element.name == 'Handle' && element.library.name == 'dart.ffi';
+
/// Returns `true` iff [nativeType] is a `ffi.NativeFunction<???>` type.
bool _isNativeFunctionInterfaceType(DartType nativeType) {
if (nativeType is InterfaceType) {
@@ -175,6 +178,10 @@
return false;
}
+ bool _isNativeFunctionPointerExtension(Element element) =>
+ element.name == 'NativeFunctionPointer' &&
+ element.library.name == 'dart.ffi';
+
/// Returns `true` iff [nativeType] is a `ffi.NativeType` type.
bool _isNativeTypeInterfaceType(DartType nativeType) {
if (nativeType is InterfaceType) {
@@ -190,13 +197,6 @@
bool _isPointer(Element element) =>
element.name == 'Pointer' && element.library.name == 'dart.ffi';
- bool _isHandle(Element element) =>
- element.name == 'Handle' && element.library.name == 'dart.ffi';
-
- bool _isNativeFunctionPointerExtension(Element element) =>
- element.name == 'NativeFunctionPointer' &&
- element.library.name == 'dart.ffi';
-
/// Returns `true` iff [nativeType] is a `ffi.Pointer<???>` type.
bool _isPointerInterfaceType(DartType nativeType) {
if (nativeType is InterfaceType) {
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index dd2cc51..b57d7ea 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -1608,7 +1608,10 @@
BooleanErrorListener listener = BooleanErrorListener();
Scanner scanner = Scanner(
null, SubSequenceReader(referenceSource, sourceOffset), listener)
- ..configureFeatures(_featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: _featureSet,
+ featureSet: _featureSet,
+ );
scanner.setSourceStart(1, 1);
Token firstToken = scanner.tokenize();
if (listener.errorReported) {
diff --git a/pkg/analyzer/lib/src/generated/utilities_general.dart b/pkg/analyzer/lib/src/generated/utilities_general.dart
index a3d4531..3008a77 100644
--- a/pkg/analyzer/lib/src/generated/utilities_general.dart
+++ b/pkg/analyzer/lib/src/generated/utilities_general.dart
@@ -68,6 +68,17 @@
/// same operations as the performance critical variant, but allocates an extra
/// object.
class JenkinsSmiHash {
+ int _hash = 0;
+
+ /// Finalizes the hash and return the resulting hashcode.
+ @override
+ int get hashCode => finish(_hash);
+
+ /// Accumulates the object [o] into the hash.
+ void add(Object o) {
+ _hash = combine(_hash, o.hashCode);
+ }
+
/// Accumulates the hash code [value] into the running hash [hash].
static int combine(int hash, int value) {
hash = 0x1fffffff & (hash + value);
@@ -91,17 +102,6 @@
/// Combines together four hash codes.
static int hash4(a, b, c, d) =>
finish(combine(combine(combine(combine(0, a), b), c), d));
-
- int _hash = 0;
-
- /// Accumulates the object [o] into the hash.
- void add(Object o) {
- _hash = combine(_hash, o.hashCode);
- }
-
- /// Finalizes the hash and return the resulting hashcode.
- @override
- int get hashCode => finish(_hash);
}
/**
diff --git a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
index 8ad9cc0..517c647 100644
--- a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
+++ b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
@@ -38,6 +38,11 @@
/// Whether this info object defines any ignores.
bool get hasIgnores => _ignoreMap.isNotEmpty || _ignoreForFileSet.isNotEmpty;
+ /// Test whether this [errorCode] is ignored at the given [line].
+ bool ignoredAt(String errorCode, int line) =>
+ _ignoreForFileSet.contains(errorCode) ||
+ _ignoreMap[line]?.contains(errorCode) == true;
+
/// Ignore these [errorCodes] at [line].
void _addAll(int line, Iterable<String> errorCodes) {
_ignoreMap.putIfAbsent(line, () => <String>[]).addAll(errorCodes);
@@ -48,11 +53,6 @@
_ignoreForFileSet.addAll(errorCodes);
}
- /// Test whether this [errorCode] is ignored at the given [line].
- bool ignoredAt(String errorCode, int line) =>
- _ignoreForFileSet.contains(errorCode) ||
- _ignoreMap[line]?.contains(errorCode) == true;
-
/// Calculate ignores for the given [content] with line [info].
static IgnoreInfo calculateIgnores(String content, LineInfo info) {
Iterable<Match> matches = _IGNORE_MATCHER.allMatches(content);
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 86ecb8a..17392cf 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -15,7 +15,6 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart' as file_system;
-import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
@@ -25,6 +24,7 @@
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/error/lint_codes.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart'
show
AnalysisErrorInfo,
@@ -464,7 +464,7 @@
(analysisOptions as AnalysisOptionsImpl).experimentStatus,
);
- var listener = ConstantAnalysisErrorListener();
+ var listener = _ConstantAnalysisErrorListener();
var errorReporter = ErrorReporter(
listener,
unitElement.source,
@@ -804,6 +804,47 @@
contents: sourceFile.readAsStringSync(), sourcePath: sourceFile.path);
}
+/// An error listener that only records whether any constant related errors have
+/// been reported.
+class _ConstantAnalysisErrorListener extends AnalysisErrorListener {
+ /// A flag indicating whether any constant related errors have been reported
+ /// to this listener.
+ bool hasConstError = false;
+
+ @override
+ void onError(AnalysisError error) {
+ ErrorCode errorCode = error.errorCode;
+ if (errorCode is CompileTimeErrorCode) {
+ switch (errorCode) {
+ case CompileTimeErrorCode
+ .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST:
+ case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL:
+ case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_INT:
+ case CompileTimeErrorCode.CONST_EVAL_TYPE_BOOL_NUM_STRING:
+ case CompileTimeErrorCode.CONST_EVAL_TYPE_INT:
+ case CompileTimeErrorCode.CONST_EVAL_TYPE_NUM:
+ case CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION:
+ case CompileTimeErrorCode.CONST_EVAL_THROWS_IDBZE:
+ case CompileTimeErrorCode
+ .CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS:
+ case CompileTimeErrorCode.CONST_SET_ELEMENT_TYPE_IMPLEMENTS_EQUALS:
+ case CompileTimeErrorCode.CONST_WITH_NON_CONST:
+ case CompileTimeErrorCode.CONST_WITH_NON_CONSTANT_ARGUMENT:
+ case CompileTimeErrorCode.CONST_WITH_TYPE_PARAMETERS:
+ case CompileTimeErrorCode.INVALID_CONSTANT:
+ case CompileTimeErrorCode.MISSING_CONST_IN_LIST_LITERAL:
+ case CompileTimeErrorCode.MISSING_CONST_IN_MAP_LITERAL:
+ case CompileTimeErrorCode.MISSING_CONST_IN_SET_LITERAL:
+ case CompileTimeErrorCode.NON_CONSTANT_LIST_ELEMENT:
+ case CompileTimeErrorCode.NON_CONSTANT_MAP_KEY:
+ case CompileTimeErrorCode.NON_CONSTANT_MAP_VALUE:
+ case CompileTimeErrorCode.NON_CONSTANT_SET_ELEMENT:
+ hasConstError = true;
+ }
+ }
+ }
+}
+
class _LintCode extends LintCode {
static final registry = <String, LintCode>{};
diff --git a/pkg/analyzer/lib/src/manifest/manifest_validator.dart b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
index afb06f9..d7927e5 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_validator.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_validator.dart
@@ -24,7 +24,7 @@
*/
ManifestValidator(this.source);
- /*
+ /**
* Validate the [contents] of the Android Manifest file.
*/
List<AnalysisError> validate(String contents, bool checkManifest) {
@@ -54,7 +54,111 @@
return recorder.errors;
}
- /*
+ List<Element> _findActivityElements(Element manifest) {
+ var applications = manifest?.getElementsByTagName(APPLICATION_TAG);
+ var applicationElement = (applications != null && applications.isNotEmpty)
+ ? applications.first
+ : null;
+ var activities =
+ applicationElement?.getElementsByTagName(ACTIVITY_TAG) ?? [];
+ return activities;
+ }
+
+ bool _hasFeatureCamera(List<Element> features) =>
+ features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA);
+
+ bool _hasFeatureCameraAutoFocus(List<Element> features) =>
+ features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA_AUTOFOCUS);
+
+ /**
+ * Report an error for the given node.
+ */
+ void _reportErrorForNode(
+ ErrorReporter reporter, Node node, dynamic key, ErrorCode errorCode,
+ [List<Object> arguments]) {
+ FileSpan span =
+ key == null ? node.sourceSpan : node.attributeValueSpans[key];
+ reporter.reportErrorForOffset(
+ errorCode, span.start.offset, span.length, arguments);
+ }
+
+ /**
+ * Validate the 'activity' tags.
+ */
+ _validateActivities(List<Element> activites, ErrorReporter reporter) {
+ activites.forEach((activity) {
+ var attributes = activity.attributes;
+ if (attributes.containsKey(ATTRIBUTE_SCREEN_ORIENTATION)) {
+ if (UNSUPPORTED_ORIENTATIONS
+ .contains(attributes[ATTRIBUTE_SCREEN_ORIENTATION])) {
+ _reportErrorForNode(reporter, activity, ATTRIBUTE_SCREEN_ORIENTATION,
+ ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY);
+ }
+ }
+ if (attributes.containsKey(ATTRIBUTE_RESIZEABLE_ACTIVITY)) {
+ if (attributes[ATTRIBUTE_RESIZEABLE_ACTIVITY] == 'false') {
+ _reportErrorForNode(reporter, activity, ATTRIBUTE_RESIZEABLE_ACTIVITY,
+ ManifestWarningCode.NON_RESIZABLE_ACTIVITY);
+ }
+ }
+ });
+ }
+
+ /**
+ * Validate the `uses-feature` tags.
+ */
+ _validateFeatures(List<Element> features, ErrorReporter reporter) {
+ var unsupported = features
+ .where((element) => UNSUPPORTED_HARDWARE_FEATURES
+ .contains(element.attributes[ANDROID_NAME]))
+ .toList();
+ unsupported.forEach((element) {
+ if (!element.attributes.containsKey(ANDROID_REQUIRED)) {
+ _reportErrorForNode(
+ reporter,
+ element,
+ ANDROID_NAME,
+ ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE,
+ [element.attributes[ANDROID_NAME]]);
+ } else if (element.attributes[ANDROID_REQUIRED] == 'true') {
+ _reportErrorForNode(
+ reporter,
+ element,
+ ANDROID_NAME,
+ ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE,
+ [element.attributes[ANDROID_NAME]]);
+ }
+ });
+ }
+
+ /**
+ * Validate the `uses-permission` tags.
+ */
+ _validatePermissions(List<Element> permissions, List<Element> features,
+ ErrorReporter reporter) {
+ permissions.forEach((permission) {
+ if (permission.attributes[ANDROID_NAME] == ANDROID_PERMISSION_CAMERA) {
+ if (!_hasFeatureCamera(features) ||
+ !_hasFeatureCameraAutoFocus(features)) {
+ _reportErrorForNode(reporter, permission, ANDROID_NAME,
+ ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE);
+ }
+ } else {
+ var featureName =
+ getImpliedUnsupportedHardware(permission.attributes[ANDROID_NAME]);
+ if (featureName != null) {
+ _reportErrorForNode(
+ reporter,
+ permission,
+ ANDROID_NAME,
+ ManifestWarningCode.PERMISSION_IMPLIES_UNSUPPORTED_HARDWARE,
+ [featureName]);
+ }
+ }
+ });
+ }
+
+ /**
* Validate the presence/absence of the touchscreen feature tag.
*/
_validateTouchScreenFeature(
@@ -84,108 +188,4 @@
reporter, manifest, null, ManifestWarningCode.NO_TOUCHSCREEN_FEATURE);
}
}
-
- /*
- * Validate the `uses-feature` tags.
- */
- _validateFeatures(List<Element> features, ErrorReporter reporter) {
- var unsupported = features
- .where((element) => UNSUPPORTED_HARDWARE_FEATURES
- .contains(element.attributes[ANDROID_NAME]))
- .toList();
- unsupported.forEach((element) {
- if (!element.attributes.containsKey(ANDROID_REQUIRED)) {
- _reportErrorForNode(
- reporter,
- element,
- ANDROID_NAME,
- ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE,
- [element.attributes[ANDROID_NAME]]);
- } else if (element.attributes[ANDROID_REQUIRED] == 'true') {
- _reportErrorForNode(
- reporter,
- element,
- ANDROID_NAME,
- ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE,
- [element.attributes[ANDROID_NAME]]);
- }
- });
- }
-
- /*
- * Validate the `uses-permission` tags.
- */
- _validatePermissions(List<Element> permissions, List<Element> features,
- ErrorReporter reporter) {
- permissions.forEach((permission) {
- if (permission.attributes[ANDROID_NAME] == ANDROID_PERMISSION_CAMERA) {
- if (!_hasFeatureCamera(features) ||
- !_hasFeatureCameraAutoFocus(features)) {
- _reportErrorForNode(reporter, permission, ANDROID_NAME,
- ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE);
- }
- } else {
- var featureName =
- getImpliedUnsupportedHardware(permission.attributes[ANDROID_NAME]);
- if (featureName != null) {
- _reportErrorForNode(
- reporter,
- permission,
- ANDROID_NAME,
- ManifestWarningCode.PERMISSION_IMPLIES_UNSUPPORTED_HARDWARE,
- [featureName]);
- }
- }
- });
- }
-
- /*
- * Validate the 'activity' tags.
- */
- _validateActivities(List<Element> activites, ErrorReporter reporter) {
- activites.forEach((activity) {
- var attributes = activity.attributes;
- if (attributes.containsKey(ATTRIBUTE_SCREEN_ORIENTATION)) {
- if (UNSUPPORTED_ORIENTATIONS
- .contains(attributes[ATTRIBUTE_SCREEN_ORIENTATION])) {
- _reportErrorForNode(reporter, activity, ATTRIBUTE_SCREEN_ORIENTATION,
- ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY);
- }
- }
- if (attributes.containsKey(ATTRIBUTE_RESIZEABLE_ACTIVITY)) {
- if (attributes[ATTRIBUTE_RESIZEABLE_ACTIVITY] == 'false') {
- _reportErrorForNode(reporter, activity, ATTRIBUTE_RESIZEABLE_ACTIVITY,
- ManifestWarningCode.NON_RESIZABLE_ACTIVITY);
- }
- }
- });
- }
-
- List<Element> _findActivityElements(Element manifest) {
- var applications = manifest?.getElementsByTagName(APPLICATION_TAG);
- var applicationElement = (applications != null && applications.isNotEmpty)
- ? applications.first
- : null;
- var activities =
- applicationElement?.getElementsByTagName(ACTIVITY_TAG) ?? [];
- return activities;
- }
-
- bool _hasFeatureCamera(List<Element> features) =>
- features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA);
-
- bool _hasFeatureCameraAutoFocus(List<Element> features) =>
- features.any((f) => f.localName == HARDWARE_FEATURE_CAMERA_AUTOFOCUS);
-
- /**
- * Report an error for the given node.
- */
- void _reportErrorForNode(
- ErrorReporter reporter, Node node, dynamic key, ErrorCode errorCode,
- [List<Object> arguments]) {
- FileSpan span =
- key == null ? node.sourceSpan : node.attributeValueSpans[key];
- reporter.reportErrorForOffset(
- errorCode, span.start.offset, span.length, arguments);
- }
}
diff --git a/pkg/analyzer/lib/src/manifest/manifest_values.dart b/pkg/analyzer/lib/src/manifest/manifest_values.dart
index f44a4ba..ddc3bfa 100644
--- a/pkg/analyzer/lib/src/manifest/manifest_values.dart
+++ b/pkg/analyzer/lib/src/manifest/manifest_values.dart
@@ -7,37 +7,33 @@
*
*/
-const String MANIFEST_TAG = 'manifest';
-
-const String USES_PERMISSION_TAG = 'uses-permission';
-
-const String USES_FEATURE_TAG = 'uses-feature';
-
-const String APPLICATION_TAG = 'application';
-
const String ACTIVITY_TAG = 'activity';
const String ANDROID_NAME = 'android:name';
+const String ANDROID_PERMISSION_CAMERA = 'android.permission.CAMERA';
+
const String ANDROID_REQUIRED = 'android:required';
+const String APPLICATION_TAG = 'application';
+
+const String ATTRIBUTE_RESIZEABLE_ACTIVITY = 'android:resizeableactivity';
+
+const String ATTRIBUTE_SCREEN_ORIENTATION = 'android:screenorientation';
+
// The parser does not maintain camelcase for attributes
// Use 'resizeableactivity' instead of 'resizeableActivity'
-const String ATTRIBUTE_RESIZEABLE_ACTIVITY = 'android:resizeableactivity';
-
-// Use 'screenorientation' instead of 'screenOrientation'
-const String ATTRIBUTE_SCREEN_ORIENTATION = 'android:screenorientation';
-
const String HARDWARE_FEATURE_CAMERA = 'android.hardware.camera';
-const String HARDWARE_FEATURE_TOUCHSCREEN = 'android.hardware.touchscreen';
-
+// Use 'screenorientation' instead of 'screenOrientation'
const String HARDWARE_FEATURE_CAMERA_AUTOFOCUS =
'android.hardware.camera.autofocus';
const String HARDWARE_FEATURE_TELEPHONY = 'android.hardware.telephony';
-const String ANDROID_PERMISSION_CAMERA = 'android.permission.CAMERA';
+const String HARDWARE_FEATURE_TOUCHSCREEN = 'android.hardware.touchscreen';
+
+const String MANIFEST_TAG = 'manifest';
const UNSUPPORTED_HARDWARE_FEATURES = <String>[
HARDWARE_FEATURE_CAMERA,
@@ -81,6 +77,21 @@
'android.software.sip.voip',
];
+const UNSUPPORTED_ORIENTATIONS = <String>[
+ 'landscape',
+ 'portrait',
+ 'reverseLandscape',
+ 'reversePortrait',
+ 'sensorLandscape',
+ 'sensorPortrait',
+ 'userLandscape',
+ 'userPortrait'
+];
+
+const String USES_FEATURE_TAG = 'uses-feature';
+
+const String USES_PERMISSION_TAG = 'uses-permission';
+
String getImpliedUnsupportedHardware(String permission) {
switch (permission) {
case ANDROID_PERMISSION_CAMERA:
@@ -111,14 +122,3 @@
return null;
}
}
-
-const UNSUPPORTED_ORIENTATIONS = <String>[
- 'landscape',
- 'portrait',
- 'reverseLandscape',
- 'reversePortrait',
- 'sensorLandscape',
- 'sensorPortrait',
- 'userLandscape',
- 'userPortrait'
-];
diff --git a/pkg/analyzer/lib/src/summary/api_signature.dart b/pkg/analyzer/lib/src/summary/api_signature.dart
index 552c464..bfa5a20 100644
--- a/pkg/analyzer/lib/src/summary/api_signature.dart
+++ b/pkg/analyzer/lib/src/summary/api_signature.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart';
+import 'package:pub_semver/pub_semver.dart';
/**
* An instance of [ApiSignature] collects data in the form of primitive types
@@ -110,6 +111,14 @@
}
/**
+ * Collect a language version.
+ */
+ void addLanguageVersion(Version version) {
+ addInt(version.major);
+ addInt(version.minor);
+ }
+
+ /**
* Collect a string.
*/
void addString(String s) {
diff --git a/pkg/analyzer/lib/src/summary/summary_file_builder.dart b/pkg/analyzer/lib/src/summary/summary_file_builder.dart
index 476987e..477500b 100644
--- a/pkg/analyzer/lib/src/summary/summary_file_builder.dart
+++ b/pkg/analyzer/lib/src/summary/summary_file_builder.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'dart:collection';
-
import 'package:_fe_analyzer_shared/src/sdk/allowed_experiments.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/utilities.dart';
@@ -13,7 +11,6 @@
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/sdk/sdk.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/summarize_elements.dart';
@@ -21,48 +18,45 @@
import 'package:analyzer/src/summary2/linked_element_factory.dart' as summary2;
import 'package:analyzer/src/summary2/reference.dart' as summary2;
import 'package:meta/meta.dart';
+import 'package:yaml/yaml.dart';
+/// Build summary for SDK the at the given [sdkPath].
+///
+/// If [embedderYamlPath] is provided, then libraries from this file are
+/// appended to the libraries of the specified SDK.
List<int> buildSdkSummary({
@required ResourceProvider resourceProvider,
@required String sdkPath,
+ String embedderYamlPath,
}) {
- //
- // Prepare SDK.
- //
- FolderBasedDartSdk sdk =
- FolderBasedDartSdk(resourceProvider, resourceProvider.getFolder(sdkPath));
+ var sdk = FolderBasedDartSdk(
+ resourceProvider,
+ resourceProvider.getFolder(sdkPath),
+ );
sdk.useSummary = false;
sdk.analysisOptions = AnalysisOptionsImpl();
- //
- // Prepare 'dart:' URIs to serialize.
- //
- Set<String> uriSet =
- sdk.sdkLibraries.map((SdkLibrary library) => library.shortName).toSet();
- // TODO(scheglov) Why do we need it?
- uriSet.add('dart:html_common/html_common_dart2js.dart');
-
- Set<Source> librarySources = HashSet<Source>();
- for (String uri in uriSet) {
- var source = sdk.mapDartUri(uri);
- // TODO(scheglov) Fix the previous TODO and remove this check.
- if (source != null) {
- librarySources.add(source);
+ // Append libraries from the embedder.
+ if (embedderYamlPath != null) {
+ var file = resourceProvider.getFile(embedderYamlPath);
+ var content = file.readAsStringSync();
+ var map = loadYaml(content) as YamlMap;
+ var embedderSdk = EmbedderSdk(resourceProvider, {file.parent: map});
+ for (var library in embedderSdk.sdkLibraries) {
+ var uriStr = library.shortName;
+ if (sdk.libraryMap.getLibrary(uriStr) == null) {
+ sdk.libraryMap.setLibrary(uriStr, library);
+ }
}
}
- String allowedExperimentsJson;
- try {
- allowedExperimentsJson = sdk.directory
- .getChildAssumingFolder('lib')
- .getChildAssumingFolder('_internal')
- .getChildAssumingFile('allowed_experiments.json')
- .readAsStringSync();
- } catch (_) {}
+ var librarySources = sdk.sdkLibraries.map((e) {
+ return sdk.mapDartUri(e.shortName);
+ }).toList();
return _Builder(
sdk.context,
- allowedExperimentsJson,
+ sdk.allowedExperimentsJson,
librarySources,
).build();
}
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 0082065..5bbcce9 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -8,6 +8,7 @@
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/dart/resolver/scope.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -22,13 +23,6 @@
import 'package:analyzer/src/task/strong_mode.dart';
import 'package:meta/meta.dart';
-DartType _dynamicIfNull(DartType type) {
- if (type == null || type.isBottom || type.isDartCoreNull) {
- return DynamicTypeImpl.instance;
- }
- return type;
-}
-
AstNode _getLinkedNode(Element element) {
return (element as ElementImpl).linkedNode;
}
@@ -372,6 +366,7 @@
class _VariableInferenceNode extends _InferenceNode {
final _InferenceWalker _walker;
final CompilationUnitElement _unitElement;
+ final TypeSystemImpl _typeSystem;
final Scope _scope;
final VariableDeclaration _node;
@@ -383,7 +378,7 @@
this._unitElement,
this._scope,
this._node,
- );
+ ) : _typeSystem = _unitElement.library.typeSystem;
@override
String get displayName {
@@ -433,7 +428,7 @@
if (LazyAst.getType(_node) == null) {
var initializerType = _node.initializer.staticType;
- initializerType = _dynamicIfNull(initializerType);
+ initializerType = _refineType(initializerType);
LazyAst.setType(_node, initializerType);
}
@@ -460,6 +455,21 @@
isEvaluated = true;
}
+ DartType _refineType(DartType type) {
+ if (type == null || type.isDartCoreNull) {
+ return DynamicTypeImpl.instance;
+ }
+
+ if (_typeSystem.isNonNullableByDefault) {
+ return nonNullifyType(_typeSystem, type);
+ } else {
+ if (type.isBottom) {
+ return DynamicTypeImpl.instance;
+ }
+ return type;
+ }
+ }
+
void _resolveInitializer({@required bool forDependencies}) {
var astResolver = AstResolver(_walker._linker, _unitElement, _scope);
astResolver.resolve(
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index c1afdb9..ddaf18a 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -408,6 +408,43 @@
LinterOptionsValidator() : super('linter', const ['rules']);
}
+/// Validates `analyzer` optional-checks value configuration options.
+class OptionalChecksValueValidator extends OptionsValidator {
+ ErrorBuilder builder = ErrorBuilder(AnalyzerOptions.optionalChecksOptions);
+ ErrorBuilder trueOrFalseBuilder = TrueOrFalseValueErrorBuilder();
+
+ @override
+ void validate(ErrorReporter reporter, YamlMap options) {
+ var analyzer = getValue(options, AnalyzerOptions.analyzer);
+ if (analyzer is YamlMap) {
+ var v = getValue(analyzer, AnalyzerOptions.optionalChecks);
+ if (v is YamlScalar) {
+ var value = toLowerCase(v.value);
+ if (value != AnalyzerOptions.chromeOsManifestChecks) {
+ builder.reportError(
+ reporter, AnalyzerOptions.chromeOsManifestChecks, v);
+ }
+ } else if (v is YamlMap) {
+ v.nodes.forEach((k, v) {
+ String key, value;
+ if (k is YamlScalar) {
+ key = k.value?.toString();
+ if (key != AnalyzerOptions.chromeOsManifestChecks) {
+ builder.reportError(
+ reporter, AnalyzerOptions.chromeOsManifestChecks, k);
+ } else {
+ value = toLowerCase(v.value);
+ if (!AnalyzerOptions.trueOrFalse.contains(value)) {
+ trueOrFalseBuilder.reportError(reporter, key, v);
+ }
+ }
+ }
+ });
+ }
+ }
+ }
+}
+
/// Validates options defined in an analysis options file.
class OptionsFileValidator {
/// The source being validated.
@@ -485,43 +522,6 @@
}
}
-/// Validates `analyzer` optional-checks value configuration options.
-class OptionalChecksValueValidator extends OptionsValidator {
- ErrorBuilder builder = ErrorBuilder(AnalyzerOptions.optionalChecksOptions);
- ErrorBuilder trueOrFalseBuilder = TrueOrFalseValueErrorBuilder();
-
- @override
- void validate(ErrorReporter reporter, YamlMap options) {
- var analyzer = getValue(options, AnalyzerOptions.analyzer);
- if (analyzer is YamlMap) {
- var v = getValue(analyzer, AnalyzerOptions.optionalChecks);
- if (v is YamlScalar) {
- var value = toLowerCase(v.value);
- if (value != AnalyzerOptions.chromeOsManifestChecks) {
- builder.reportError(
- reporter, AnalyzerOptions.chromeOsManifestChecks, v);
- }
- } else if (v is YamlMap) {
- v.nodes.forEach((k, v) {
- String key, value;
- if (k is YamlScalar) {
- key = k.value?.toString();
- if (key != AnalyzerOptions.chromeOsManifestChecks) {
- builder.reportError(
- reporter, AnalyzerOptions.chromeOsManifestChecks, k);
- } else {
- value = toLowerCase(v.value);
- if (!AnalyzerOptions.trueOrFalse.contains(value)) {
- trueOrFalseBuilder.reportError(reporter, key, v);
- }
- }
- }
- });
- }
- }
- }
-}
-
/// Validates `analyzer` top-level options.
class TopLevelAnalyzerOptionsValidator extends TopLevelOptionValidator {
TopLevelAnalyzerOptionsValidator()
@@ -689,6 +689,31 @@
}
}
+ void _applyOptionalChecks(AnalysisOptionsImpl options, YamlNode config) {
+ if (config is YamlMap) {
+ config.nodes.forEach((k, v) {
+ if (k is YamlScalar && v is YamlScalar) {
+ _applyOptionalChecksOption(options, k.value?.toString(), v.value);
+ }
+ });
+ }
+ if (config is YamlScalar) {
+ if (config.value?.toString() == AnalyzerOptions.chromeOsManifestChecks) {
+ options.chromeOsManifestChecks = true;
+ }
+ }
+ }
+
+ void _applyOptionalChecksOption(
+ AnalysisOptionsImpl options, String feature, Object value) {
+ bool boolValue = toBool(value);
+ if (boolValue != null) {
+ if (feature == AnalyzerOptions.chromeOsManifestChecks) {
+ options.chromeOsManifestChecks = boolValue;
+ }
+ }
+ }
+
void _applyProcessors(AnalysisOptionsImpl options, YamlNode codes) {
ErrorConfig config = ErrorConfig(codes);
options.errorProcessors = config.processors;
@@ -717,31 +742,6 @@
}
}
- void _applyOptionalChecksOption(
- AnalysisOptionsImpl options, String feature, Object value) {
- bool boolValue = toBool(value);
- if (boolValue != null) {
- if (feature == AnalyzerOptions.chromeOsManifestChecks) {
- options.chromeOsManifestChecks = boolValue;
- }
- }
- }
-
- void _applyOptionalChecks(AnalysisOptionsImpl options, YamlNode config) {
- if (config is YamlMap) {
- config.nodes.forEach((k, v) {
- if (k is YamlScalar && v is YamlScalar) {
- _applyOptionalChecksOption(options, k.value?.toString(), v.value);
- }
- });
- }
- if (config is YamlScalar) {
- if (config.value?.toString() == AnalyzerOptions.chromeOsManifestChecks) {
- options.chromeOsManifestChecks = true;
- }
- }
- }
-
String _toString(YamlNode node) {
if (node is YamlScalar) {
var value = node.value;
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index 441661e..308183e 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_demotion.dart';
import 'package:analyzer/src/generated/type_system.dart';
import 'package:analyzer/src/summary/format.dart';
import 'package:analyzer/src/summary/idl.dart';
@@ -159,7 +160,9 @@
name: getterName,
);
if (combinedGetter != null) {
- accessor.returnType = combinedGetter.returnType;
+ var returnType = combinedGetter.returnType;
+ returnType = nonNullifyType(typeSystem, returnType);
+ accessor.returnType = returnType;
}
}
@@ -175,7 +178,9 @@
name: setterName,
);
if (combinedSetter != null) {
- accessor.returnType = combinedSetter.parameters[0].type;
+ var returnType = combinedSetter.parameters[0].type;
+ returnType = nonNullifyType(typeSystem, returnType);
+ accessor.returnType = returnType;
}
}
@@ -209,7 +214,9 @@
name: getterName,
);
if (combinedGetter != null) {
- parameter.type = combinedGetter.returnType;
+ var type = combinedGetter.returnType;
+ type = nonNullifyType(typeSystem, type);
+ parameter.type = type;
}
return;
}
@@ -230,7 +237,9 @@
name: setterName,
);
if (combinedSetter != null) {
- parameter.type = combinedSetter.parameters[0].type;
+ var type = combinedSetter.parameters[0].type;
+ type = nonNullifyType(typeSystem, type);
+ parameter.type = type;
}
return;
}
@@ -262,7 +271,9 @@
name: getterName,
);
if (combinedGetter != null) {
- field.type = combinedGetter.returnType;
+ var type = combinedGetter.returnType;
+ type = nonNullifyType(typeSystem, type);
+ field.type = type;
}
return;
}
@@ -279,7 +290,9 @@
name: setterName,
);
if (combinedSetter != null) {
- field.type = combinedSetter.parameters[0].type;
+ var type = combinedSetter.parameters[0].type;
+ type = nonNullifyType(typeSystem, type);
+ field.type = type;
}
return;
}
@@ -296,7 +309,9 @@
name: getterName,
);
if (combinedGetter != null) {
- field.type = combinedGetter.returnType;
+ var type = combinedGetter.returnType;
+ type = nonNullifyType(typeSystem, type);
+ field.type = type;
}
return;
}
@@ -329,7 +344,9 @@
}
if (getterType == setterType) {
- field.type = getterType ?? _dynamicType;
+ var type = getterType ?? _dynamicType;
+ type = nonNullifyType(typeSystem, type);
+ field.type = type;
} else {
LazyAst.setTypeInferenceError(
field.linkedNode,
@@ -500,7 +517,9 @@
//
if (element.hasImplicitReturnType && element.displayName != '[]=') {
if (combinedSignatureType != null) {
- element.returnType = combinedSignatureType.returnType;
+ var returnType = combinedSignatureType.returnType;
+ returnType = nonNullifyType(typeSystem, returnType);
+ element.returnType = returnType;
} else {
element.returnType = DynamicTypeImpl.instance;
}
@@ -549,7 +568,9 @@
combinedSignatureType.parameters,
);
if (matchingParameter != null) {
- parameter.type = matchingParameter.type;
+ var type = matchingParameter.type;
+ type = nonNullifyType(typeSystem, type);
+ parameter.type = type;
} else {
parameter.type = DynamicTypeImpl.instance;
}
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 490e703..0ca7c3f 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -381,7 +381,7 @@
Iterable<R> map<R>(R f(E e));
- List<E> toList();
+ List<E> toList({bool growable = true});
Set<E> toSet();
diff --git a/pkg/analyzer/lib/src/util/ast_data_extractor.dart b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
index eb603e4..8682c65 100644
--- a/pkg/analyzer/lib/src/util/ast_data_extractor.dart
+++ b/pkg/analyzer/lib/src/util/ast_data_extractor.dart
@@ -23,6 +23,14 @@
NodeId computeDefaultNodeId(AstNode node) =>
NodeId(_nodeOffset(node), IdKind.node);
+ T computeElementValue(Id id, Element element) => null;
+
+ void computeForClass(Declaration node, Id id) {
+ if (id == null) return;
+ T value = computeNodeValue(id, node);
+ registerValue(uri, node.offset, id, value, node);
+ }
+
void computeForCollectionElement(CollectionElement node, NodeId id) {
if (id == null) return;
T value = computeNodeValue(id, node);
@@ -35,12 +43,6 @@
registerValue(uri, 0, id, value, library);
}
- void computeForClass(Declaration node, Id id) {
- if (id == null) return;
- T value = computeNodeValue(id, node);
- registerValue(uri, node.offset, id, value, node);
- }
-
void computeForMember(Declaration node, Id id) {
if (id == null) return;
T value = computeNodeValue(id, node);
@@ -58,7 +60,10 @@
/// If `null` is returned, [node] has no associated data.
T computeNodeValue(Id id, AstNode node);
- T computeElementValue(Id id, Element element) => null;
+ Id createClassId(Declaration node) {
+ var element = node.declaredElement;
+ return ClassId(element.name);
+ }
Id createLibraryId(LibraryElement node) {
Uri uri = node.source.uri;
@@ -69,11 +74,6 @@
return LibraryId(uri);
}
- Id createClassId(Declaration node) {
- var element = node.declaredElement;
- return ClassId(element.name);
- }
-
Id createMemberId(Declaration node) {
var element = node.declaredElement;
if (element.enclosingElement is CompilationUnitElement) {
@@ -110,13 +110,6 @@
}
@override
- visitCompilationUnit(CompilationUnit node) {
- var library = node.declaredElement.library;
- computeForLibrary(library, createLibraryId(library));
- return super.visitCompilationUnit(node);
- }
-
- @override
visitClassDeclaration(ClassDeclaration node) {
computeForClass(node, createClassId(node));
return super.visitClassDeclaration(node);
@@ -129,6 +122,13 @@
}
@override
+ visitCompilationUnit(CompilationUnit node) {
+ var library = node.declaredElement.library;
+ computeForLibrary(library, createLibraryId(library));
+ return super.visitCompilationUnit(node);
+ }
+
+ @override
visitConstructorDeclaration(ConstructorDeclaration node) {
computeForMember(node, createMemberId(node));
return super.visitConstructorDeclaration(node);
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index 9e8c8a9..c243a08 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -736,7 +736,10 @@
var source =
StringSource(contents, 'PreviousTokenTest_findPrevious.dart');
var scanner = Scanner.fasta(source, listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token tokens = scanner.tokenize();
_unit = Parser(
source,
@@ -788,7 +791,10 @@
GatheringErrorListener listener = GatheringErrorListener(checkRanges: true);
var source = StringSource('missing', 'PreviousTokenTest_missing.dart');
var scanner = Scanner.fasta(source, listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token missing = scanner.tokenize();
expect(statement.findPrevious(missing), null);
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index 4b94467..8b509ce 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -308,19 +308,6 @@
expect(folder.exists, isTrue);
}
- @override
- test_pathContext() {
- if (path.style == path.Style.windows) {
- // On Windows the path context is replaced by one whose current directory
- // is the root of the 'C' drive.
- path.Context context = provider.pathContext;
- expect(context.style, path.Style.windows);
- expect(context.current, 'C:\\');
- } else {
- super.test_pathContext();
- }
- }
-
test_deleteFile_notExisting() {
File file = getFile(exists: false);
@@ -384,6 +371,19 @@
expect(() => provider.newFolder('not/absolute'), throwsArgumentError);
}
+ @override
+ test_pathContext() {
+ if (path.style == path.Style.windows) {
+ // On Windows the path context is replaced by one whose current directory
+ // is the root of the 'C' drive.
+ path.Context context = provider.pathContext;
+ expect(context.style, path.Style.windows);
+ expect(context.current, 'C:\\');
+ } else {
+ super.test_pathContext();
+ }
+ }
+
test_watch_createFile() {
String rootPath = provider.convertPath('/my/path');
provider.newFolder(rootPath);
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index 33dda57..6840ac0 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -185,36 +185,6 @@
''');
}
- test_constConstructorWithFieldInitializedByNonConst() async {
- await assertErrorsInCode(r'''
-class A {
- final int i = f();
- const A();
-}
-int f() {
- return 3;
-}
-''', [
- error(
- CompileTimeErrorCode
- .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
- 33,
- 10),
- ]);
- }
-
- test_constConstructorWithFieldInitializedByNonConst_static() async {
- await assertNoErrorsInCode(r'''
-class A {
- static final int i = f();
- const A();
-}
-int f() {
- return 3;
-}
-''');
- }
-
test_constConstructorWithNonConstSuper_explicit() async {
await assertErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/generated/elements_types_mixin.dart b/pkg/analyzer/test/generated/elements_types_mixin.dart
index 9d932a3..34bcb47 100644
--- a/pkg/analyzer/test/generated/elements_types_mixin.dart
+++ b/pkg/analyzer/test/generated/elements_types_mixin.dart
@@ -17,8 +17,6 @@
import 'package:meta/meta.dart';
mixin ElementsTypesMixin {
- LibraryElementImpl get testLibrary => null;
-
InterfaceType get boolNone {
var element = typeProvider.boolElement;
return interfaceTypeNone(element);
@@ -149,6 +147,8 @@
return interfaceTypeStar(element);
}
+ LibraryElementImpl get testLibrary => null;
+
TypeProvider get typeProvider;
VoidTypeImpl get voidNone => VoidTypeImpl.instance;
diff --git a/pkg/analyzer/test/generated/parser_fasta_listener.dart b/pkg/analyzer/test/generated/parser_fasta_listener.dart
index a1caa91..8fc3828 100644
--- a/pkg/analyzer/test/generated/parser_fasta_listener.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_listener.dart
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
import 'package:_fe_analyzer_shared/src/messages/codes.dart' show MessageCode;
-import 'package:_fe_analyzer_shared/src/parser/parser.dart';
import 'package:_fe_analyzer_shared/src/parser/forwarding_listener.dart';
+import 'package:_fe_analyzer_shared/src/parser/parser.dart';
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:test/test.dart';
@@ -181,18 +181,18 @@
}
@override
- void beginExtensionDeclarationPrelude(Token extensionKeyword) {
- super.beginExtensionDeclarationPrelude(extensionKeyword);
- begin('ExtensionDeclarationPrelude');
- }
-
- @override
void beginExtensionDeclaration(Token extensionKeyword, Token name) {
super.beginExtensionDeclaration(extensionKeyword, name);
begin('ExtensionDeclaration');
}
@override
+ void beginExtensionDeclarationPrelude(Token extensionKeyword) {
+ super.beginExtensionDeclarationPrelude(extensionKeyword);
+ begin('ExtensionDeclarationPrelude');
+ }
+
+ @override
void beginFactoryMethod(
Token lastConsumed, Token externalToken, Token constToken) {
super.beginFactoryMethod(lastConsumed, externalToken, constToken);
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index f37d25e..7a612f2 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -134,7 +134,10 @@
String source = "var\r\ni\n=\n1;\n";
GatheringErrorListener listener = GatheringErrorListener();
Scanner scanner = Scanner(null, CharSequenceReader(source), listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
expect(token.lexeme, 'var');
var lineStarts = scanner.lineStarts;
@@ -148,7 +151,10 @@
String source = '<!-- @Component(';
GatheringErrorListener listener = GatheringErrorListener();
Scanner scanner = Scanner(null, CharSequenceReader(source), listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token token = scanner.tokenize(reportScannerErrors: false);
expect(token, TypeMatcher<UnmatchedToken>());
token = token.next;
@@ -180,7 +186,10 @@
GatheringErrorListener listener,
) {
Scanner scanner = Scanner(null, CharSequenceReader(source), listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token result = scanner.tokenize();
listener.setLineInfo(TestSource(), scanner.lineStarts);
return result;
@@ -196,7 +205,10 @@
var defaultFeatureSet = FeatureSet.fromEnableFlags([]);
expect(defaultFeatureSet.isEnabled(Feature.extension_methods), isTrue);
- scanner.configureFeatures(FeatureSet.forTesting());
+ scanner.configureFeatures(
+ featureSetForOverriding: FeatureSet.forTesting(),
+ featureSet: FeatureSet.forTesting(),
+ );
scanner.tokenize();
var featureSet = scanner.featureSet;
@@ -207,7 +219,11 @@
var scanner = _createScanner(r'''
// @dart = 99999999999999999999999999999999.0
''');
- scanner.configureFeatures(FeatureSet.forTesting());
+ var featureSet = FeatureSet.forTesting();
+ scanner.configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
scanner.tokenize();
// Don't check features, but should not crash.
}
@@ -216,7 +232,11 @@
var scanner = _createScanner(r'''
// @dart = 2.99999999999999999999999999999999
''');
- scanner.configureFeatures(FeatureSet.forTesting());
+ var featureSet = FeatureSet.forTesting();
+ scanner.configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
scanner.tokenize();
// Don't check features, but should not crash.
}
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index 028096c..ad8cc0b 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -11,6 +11,32 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
+/// A description of a message that is expected to be reported with an error.
+class ExpectedContextMessage {
+ /// The path of the file with which the message is associated.
+ final String filePath;
+
+ /// The offset of the beginning of the error's region.
+ final int offset;
+
+ /// The offset of the beginning of the error's region.
+ final int length;
+
+ /// The message text for the error.
+ final String text;
+
+ ExpectedContextMessage(this.filePath, this.offset, this.length, {this.text});
+
+ /// Return `true` if the [message] matches this description of what it's
+ /// expected to be.
+ bool matches(DiagnosticMessage message) {
+ return message.filePath == filePath &&
+ message.offset == offset &&
+ message.length == length &&
+ (text == null || message.message == text);
+ }
+}
+
/// A description of an error that is expected to be reported.
class ExpectedError {
/// An empty array of error descriptors used when no errors are expected.
@@ -77,32 +103,6 @@
}
}
-/// A description of a message that is expected to be reported with an error.
-class ExpectedContextMessage {
- /// The path of the file with which the message is associated.
- final String filePath;
-
- /// The offset of the beginning of the error's region.
- final int offset;
-
- /// The offset of the beginning of the error's region.
- final int length;
-
- /// The message text for the error.
- final String text;
-
- ExpectedContextMessage(this.filePath, this.offset, this.length, {this.text});
-
- /// Return `true` if the [message] matches this description of what it's
- /// expected to be.
- bool matches(DiagnosticMessage message) {
- return message.filePath == filePath &&
- message.offset == offset &&
- message.length == length &&
- (text == null || message.message == text);
- }
-}
-
/// An error listener that collects all of the errors passed to it for later
/// examination.
class GatheringErrorListener implements AnalysisErrorListener {
diff --git a/pkg/analyzer/test/generated/utilities_test.dart b/pkg/analyzer/test/generated/utilities_test.dart
index fddb087..e916b69 100644
--- a/pkg/analyzer/test/generated/utilities_test.dart
+++ b/pkg/analyzer/test/generated/utilities_test.dart
@@ -1182,7 +1182,10 @@
CharSequenceReader reader = CharSequenceReader(code);
var featureSet = FeatureSet.forTesting(sdkVersion: '2.2.2');
Scanner scanner = Scanner(null, reader, listener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token token = scanner.tokenize();
Parser parser = Parser(
NonExistingSource.unknown,
diff --git a/pkg/analyzer/test/id_tests/inheritance_test.dart b/pkg/analyzer/test/id_tests/inheritance_test.dart
index 2dcf6b7..3233740 100644
--- a/pkg/analyzer/test/id_tests/inheritance_test.dart
+++ b/pkg/analyzer/test/id_tests/inheritance_test.dart
@@ -37,6 +37,22 @@
});
}
+String supertypeToString(InterfaceType type) {
+ var sb = StringBuffer();
+ sb.write(type.element.name);
+ if (type.typeArguments.isNotEmpty) {
+ sb.write('<');
+ var comma = '';
+ for (var typeArgument in type.typeArguments) {
+ sb.write(comma);
+ sb.write(typeArgument.getDisplayString(withNullability: true));
+ comma = ', ';
+ }
+ sb.write('>');
+ }
+ return sb.toString();
+}
+
class _InheritanceDataComputer extends DataComputer<String> {
const _InheritanceDataComputer();
@@ -44,13 +60,6 @@
DataInterpreter<String> get dataValidator => const StringDataInterpreter();
@override
- void computeUnitData(TestingData testingData, CompilationUnit unit,
- Map<Id, ActualData<String>> actualMap) {
- _InheritanceDataExtractor(unit.declaredElement.source.uri, actualMap)
- .run(unit);
- }
-
- @override
bool get supportsErrors => true;
@override
@@ -58,6 +67,13 @@
List<AnalysisError> errors) {
return errors.map((e) => e.errorCode).join(',');
}
+
+ @override
+ void computeUnitData(TestingData testingData, CompilationUnit unit,
+ Map<Id, ActualData<String>> actualMap) {
+ _InheritanceDataExtractor(unit.declaredElement.source.uri, actualMap)
+ .run(unit);
+ }
}
class _InheritanceDataExtractor extends AstDataExtractor<String> {
@@ -133,19 +149,3 @@
return null;
}
}
-
-String supertypeToString(InterfaceType type) {
- var sb = StringBuffer();
- sb.write(type.element.name);
- if (type.typeArguments.isNotEmpty) {
- sb.write('<');
- var comma = '';
- for (var typeArgument in type.typeArguments) {
- sb.write(comma);
- sb.write(typeArgument.getDisplayString(withNullability: true));
- comma = ', ';
- }
- sb.write('>');
- }
- return sb.toString();
-}
diff --git a/pkg/analyzer/test/src/dart/ast/ast_test.dart b/pkg/analyzer/test/src/dart/ast/ast_test.dart
index e9d3ce2..c5c2345 100644
--- a/pkg/analyzer/test/src/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/ast_test.dart
@@ -31,6 +31,15 @@
testUnit = parseCompilationUnit(source);
}
+ test_languageVersionComment_firstComment() {
+ parse('''
+// @dart=2.6
+void main() {}
+''');
+ expect(
+ testUnit.languageVersionToken, testUnit.beginToken.precedingComments);
+ }
+
test_languageVersionComment_none() {
parse('''
void main() {}
@@ -46,15 +55,6 @@
expect(testUnit.languageVersionToken, null);
}
- test_languageVersionComment_firstComment() {
- parse('''
-// @dart=2.6
-void main() {}
-''');
- expect(
- testUnit.languageVersionToken, testUnit.beginToken.precedingComments);
- }
-
test_languageVersionComment_secondComment() {
parse('''
// A normal comment.
diff --git a/pkg/analyzer/test/src/dart/ast/parse_base.dart b/pkg/analyzer/test/src/dart/ast/parse_base.dart
index 1583c73..d280721 100644
--- a/pkg/analyzer/test/src/dart/ast/parse_base.dart
+++ b/pkg/analyzer/test/src/dart/ast/parse_base.dart
@@ -28,7 +28,10 @@
var reader = CharSequenceReader(content);
var scanner = Scanner(source, reader, errorListener)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
var token = scanner.tokenize();
featureSet = scanner.featureSet;
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 39c1c33..311aed8 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -2690,6 +2690,18 @@
AstTestFactory.typeName4("C", [AstTestFactory.typeName4("D")], true));
}
+ void test_visitTypeParameter_variance_contravariant() {
+ _assertSource("in E", AstTestFactory.typeParameter3("E", "in"));
+ }
+
+ void test_visitTypeParameter_variance_covariant() {
+ _assertSource("out E", AstTestFactory.typeParameter3("E", "out"));
+ }
+
+ void test_visitTypeParameter_variance_invariant() {
+ _assertSource("inout E", AstTestFactory.typeParameter3("E", "inout"));
+ }
+
void test_visitTypeParameter_withExtends() {
_assertSource("E extends C",
AstTestFactory.typeParameter2("E", AstTestFactory.typeName4("C")));
@@ -2706,18 +2718,6 @@
_assertSource("E", AstTestFactory.typeParameter("E"));
}
- void test_visitTypeParameter_variance_covariant() {
- _assertSource("out E", AstTestFactory.typeParameter3("E", "out"));
- }
-
- void test_visitTypeParameter_variance_contravariant() {
- _assertSource("in E", AstTestFactory.typeParameter3("E", "in"));
- }
-
- void test_visitTypeParameter_variance_invariant() {
- _assertSource("inout E", AstTestFactory.typeParameter3("E", "inout"));
- }
-
void test_visitTypeParameterList_multiple() {
_assertSource("<E, F>", AstTestFactory.typeParameterList(["E", "F"]));
}
diff --git a/pkg/analyzer/test/src/dart/element/type_visitor_test.dart b/pkg/analyzer/test/src/dart/element/type_visitor_test.dart
index 0d27256..7043e7f 100644
--- a/pkg/analyzer/test/src/dart/element/type_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_visitor_test.dart
@@ -31,17 +31,6 @@
visitor.assertVisitedType(intNone);
}
- void test_functionType_typeFormal_noBound() {
- final T = this.typeParameter('T');
- final type = functionType(
- returnType: dynamicType,
- typeFormals: [T],
- parameters: [],
- nullabilitySuffix: NullabilitySuffix.none);
- expect(DartTypeVisitor.visit(type, visitor), true);
- visitor.assertVisitedType(dynamicType);
- }
-
void test_functionType_complex() {
final T = typeParameter('T', bound: intNone);
final K = typeParameter('K', bound: stringNone);
@@ -98,6 +87,17 @@
visitor.assertVisitedTypes([dynamicType, intNone]);
}
+ void test_functionType_typeFormal_noBound() {
+ final T = this.typeParameter('T');
+ final type = functionType(
+ returnType: dynamicType,
+ typeFormals: [T],
+ parameters: [],
+ nullabilitySuffix: NullabilitySuffix.none);
+ expect(DartTypeVisitor.visit(type, visitor), true);
+ visitor.assertVisitedType(dynamicType);
+ }
+
void test_interfaceType_typeParameter() {
final type = typeProvider.listType2(intNone);
expect(DartTypeVisitor.visit(type, visitor), true);
@@ -110,14 +110,6 @@
visitor.assertVisitedTypes([intNone, stringNone]);
}
- void test_stopVisiting_typeParameters() {
- final type = typeProvider.mapType2(intNone, stringNone);
- visitor.stopOnType = intNone;
- expect(DartTypeVisitor.visit(type, visitor), false);
- visitor.assertVisitedType(intNone);
- visitor.assertNotVisitedType(stringNone);
- }
-
void test_interfaceType_typeParameters_nested() {
final innerList = typeProvider.listType2(intNone);
final outerList = typeProvider.listType2(innerList);
@@ -176,27 +168,26 @@
expect(DartTypeVisitor.visit(outerType, visitor), false);
visitor.assertNotVisitedType(stringNone);
}
+
+ void test_stopVisiting_typeParameters() {
+ final type = typeProvider.mapType2(intNone, stringNone);
+ visitor.stopOnType = intNone;
+ expect(DartTypeVisitor.visit(type, visitor), false);
+ visitor.assertVisitedType(intNone);
+ visitor.assertNotVisitedType(stringNone);
+ }
}
class _MockRecursiveVisitor extends RecursiveTypeVisitor {
final visitedTypes = <DartType>{};
DartType stopOnType;
- @override
- bool visitInterfaceType(InterfaceType type) {
- visitedTypes.add(type);
- if (type == stopOnType) {
- return false;
- }
- return super.visitInterfaceType(type);
+ void assertNotVisitedType(DartType type) {
+ expect(visitedTypes, isNot(contains(type)));
}
- @override
- bool defaultDartType(DartType type) {
- expect(type, isNotNull);
- visitedTypes.add(type);
- return type != stopOnType;
- }
+ void assertNotVisitedTypes(Iterable<DartType> types) =>
+ types.forEach(assertNotVisitedType);
void assertVisitedType(DartType type) {
expect(visitedTypes, contains(type));
@@ -205,10 +196,19 @@
void assertVisitedTypes(Iterable<DartType> types) =>
types.forEach(assertVisitedType);
- void assertNotVisitedTypes(Iterable<DartType> types) =>
- types.forEach(assertNotVisitedType);
+ @override
+ bool defaultDartType(DartType type) {
+ expect(type, isNotNull);
+ visitedTypes.add(type);
+ return type != stopOnType;
+ }
- void assertNotVisitedType(DartType type) {
- expect(visitedTypes, isNot(contains(type)));
+ @override
+ bool visitInterfaceType(InterfaceType type) {
+ visitedTypes.add(type);
+ if (type == stopOnType) {
+ return false;
+ }
+ return super.visitInterfaceType(type);
}
}
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index fabe510..de3b2ed 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -63,6 +63,32 @@
_assertRefreshedFiles([aPath, cPath]);
}
+ test_changeFile_resolution() async {
+ newFile(aPath, content: r'''
+class A {}
+''');
+
+ newFile(bPath, content: r'''
+import 'a.dart';
+A a;
+B b;
+''');
+
+ result = fileResolver.resolve(bPath);
+ assertErrorsInResolvedUnit(result, [
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 22, 1),
+ ]);
+
+ newFile(aPath, content: r'''
+class A {}
+class B {}
+''');
+ fileResolver.changeFile(aPath);
+
+ result = fileResolver.resolve(bPath);
+ assertErrorsInResolvedUnit(result, []);
+ }
+
test_changePartFile_refreshedFiles() async {
newFile(aPath, content: r'''
part 'b.dart';
@@ -95,32 +121,6 @@
_assertRefreshedFiles([aPath, bPath, cPath]);
}
- test_changeFile_resolution() async {
- newFile(aPath, content: r'''
-class A {}
-''');
-
- newFile(bPath, content: r'''
-import 'a.dart';
-A a;
-B b;
-''');
-
- result = fileResolver.resolve(bPath);
- assertErrorsInResolvedUnit(result, [
- error(CompileTimeErrorCode.UNDEFINED_CLASS, 22, 1),
- ]);
-
- newFile(aPath, content: r'''
-class A {}
-class B {}
-''');
- fileResolver.changeFile(aPath);
-
- result = fileResolver.resolve(bPath);
- assertErrorsInResolvedUnit(result, []);
- }
-
void _assertRefreshedFiles(List<String> expected, {bool withSdk = false}) {
var expectedPlusSdk = expected.toSet();
@@ -324,6 +324,25 @@
]);
}
+ test_resolve_part_of() async {
+ newFile('/workspace/dart/test/lib/a.dart', content: r'''
+part 'test.dart';
+
+class A {
+ int m;
+}
+''');
+
+ await assertNoErrorsInCode(r'''
+part of 'a.dart';
+
+void func() {
+ var a = A();
+ print(a.m);
+}
+''');
+ }
+
test_reuse_compatibleOptions() async {
var aPath = '/workspace/dart/aaa/lib/a.dart';
var aResult = await assertErrorsInFile(aPath, r'''
@@ -383,25 +402,6 @@
]);
}
- test_resolve_part_of() async {
- newFile('/workspace/dart/test/lib/a.dart', content: r'''
-part 'test.dart';
-
-class A {
- int m;
-}
-''');
-
- await assertNoErrorsInCode(r'''
-part of 'a.dart';
-
-void func() {
- var a = A();
- print(a.m);
-}
-''');
- }
-
test_unknown_uri() async {
await assertErrorsInCode(r'''
import 'foo:bar';
diff --git a/pkg/analyzer/test/src/dart/resolution/field_test.dart b/pkg/analyzer/test/src/dart/resolution/field_test.dart
new file mode 100644
index 0000000..274d030
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/field_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../constant/potentially_constant_test.dart';
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(FieldTest);
+ defineReflectiveTests(FieldWithNullSafetyTest);
+ });
+}
+
+@reflectiveTest
+class FieldTest extends DriverResolutionTest {
+ test_type_inferred_int() async {
+ await resolveTestCode('''
+class A {
+ var f = 0;
+}
+''');
+ assertType(findElement.field('f').type, 'int');
+ }
+
+ test_type_inferred_Never() async {
+ await resolveTestCode('''
+class A {
+ var f = throw 42;
+}
+''');
+ assertType(
+ findElement.field('f').type,
+ typeStringByNullability(
+ nullable: 'Never',
+ legacy: 'dynamic',
+ ),
+ );
+ }
+
+ test_type_inferred_noInitializer() async {
+ await resolveTestCode('''
+class A {
+ var f;
+}
+''');
+ assertType(findElement.field('f').type, 'dynamic');
+ }
+
+ test_type_inferred_null() async {
+ await resolveTestCode('''
+class A {
+ var f = null;
+}
+''');
+ assertType(findElement.field('f').type, 'dynamic');
+ }
+}
+
+@reflectiveTest
+class FieldWithNullSafetyTest extends FieldTest with WithNullSafetyMixin {
+ test_type_inferred_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+var a = 0;
+''');
+
+ await assertNoErrorsInCode('''
+import 'a.dart';
+
+class A {
+ var f = a;
+}
+''');
+
+ assertType(findElement.field('f').type, 'int');
+ }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart b/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
index ba751e4..42b09ff 100644
--- a/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/instance_member_inference_class_test.dart
@@ -925,6 +925,122 @@
@override
bool get typeToStringWithNullability => true;
+ test_field_multiple_gettersSetters_final_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int get foo;
+}
+abstract class B {
+ set foo(num _);
+}
+''');
+
+ await resolveTestCode('''
+import 'a.dart';
+
+class X implements A, B {
+ final foo;
+}
+''');
+ var foo = findElement.field('foo', of: 'X');
+ _assertFieldType(foo, 'int');
+ }
+
+ test_field_multiple_gettersSetters_notFinal_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int get foo;
+}
+abstract class B {
+ set foo(int _);
+}
+''');
+
+ await resolveTestCode('''
+import 'a.dart';
+
+class X implements A, B {
+ var foo;
+}
+''');
+ var foo = findElement.field('foo', of: 'X');
+ _assertFieldType(foo, 'int');
+ }
+
+ test_field_single_getter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int get foo;
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ var foo;
+}
+''');
+ var foo = findElement.field('foo', of: 'B');
+ _assertFieldType(foo, 'int');
+ }
+
+ test_field_single_setter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ set foo(int _);
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ var foo;
+}
+''');
+ var foo = findElement.field('foo', of: 'B');
+ _assertFieldType(foo, 'int');
+ }
+
+ test_getter_single_getter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int get foo;
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ get foo;
+}
+''');
+ var foo = findElement.getter('foo', of: 'B');
+ _assertGetterType(foo, 'int');
+ }
+
+ test_getter_single_setter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ set foo(int _);
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ get foo;
+}
+''');
+ var foo = findElement.getter('foo', of: 'B');
+ _assertGetterType(foo, 'int');
+ }
+
test_method_parameter_required_multiple_different_merge() async {
await resolveTestCode('''
class A {
@@ -943,6 +1059,24 @@
assertType(p.type, 'Object?');
}
+ test_method_parameter_required_single_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+class A {
+ void foo(int p) {}
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+class B implements A {
+ void foo(p) {}
+}
+''');
+ var p = findElement.method('foo', of: 'B').parameters[0];
+ assertType(p.type, 'int');
+ }
+
test_method_return_multiple_different_merge() async {
await resolveTestCode('''
class A {
@@ -960,4 +1094,58 @@
var foo = findElement.method('foo', of: 'C');
assertType(foo.returnType, 'Object?');
}
+
+ test_method_return_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int foo();
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ foo();
+}
+''');
+ var foo = findElement.method('foo', of: 'B');
+ assertType(foo.returnType, 'int');
+ }
+
+ test_setter_single_getter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ int get foo;
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ set foo(_);
+}
+''');
+ var foo = findElement.setter('foo', of: 'B');
+ _assertSetterType(foo, 'int');
+ }
+
+ test_setter_single_setter_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+abstract class A {
+ set foo(int _);
+}
+''');
+ await resolveTestCode('''
+import 'a.dart';
+
+abstract class B implements A {
+ set foo(_);
+}
+''');
+ var foo = findElement.setter('foo', of: 'B');
+ _assertSetterType(foo, 'int');
+ }
}
diff --git a/pkg/analyzer/test/src/dart/resolution/language_version_test.dart b/pkg/analyzer/test/src/dart/resolution/language_version_test.dart
index 70b7de1..685009e 100644
--- a/pkg/analyzer/test/src/dart/resolution/language_version_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/language_version_test.dart
@@ -5,6 +5,8 @@
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/src/context/packages.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -13,8 +15,9 @@
main() {
defineReflectiveSuite(() {
- defineReflectiveTests(NullSafetyUsingAllowedExperimentsTest);
defineReflectiveTests(NullSafetyExperimentGlobalTest);
+ defineReflectiveTests(NullSafetyUsingAllowedExperimentsTest);
+ defineReflectiveTests(PackageConfigAndLanguageOverrideTest);
});
}
@@ -30,7 +33,7 @@
bool get typeToStringWithNullability => true;
test_jsonConfig_legacyContext_nonNullDependency() async {
- newFile('/test/.dart_tool/package_config.json', content: '''
+ _configureTestWithJsonConfig('''
{
"configVersion": 2,
"packages": [
@@ -48,7 +51,6 @@
]
}
''');
- _configureTestWithJsonConfig();
newFile('/aaa/lib/a.dart', content: r'''
int a = 0;
@@ -68,7 +70,7 @@
}
test_jsonConfig_nonNullContext_legacyDependency() async {
- newFile('/test/.dart_tool/package_config.json', content: '''
+ _configureTestWithJsonConfig('''
{
"configVersion": 2,
"packages": [
@@ -86,7 +88,6 @@
]
}
''');
- _configureTestWithJsonConfig();
newFile('/aaa/lib/a.dart', content: r'''
int a = 0;
@@ -101,8 +102,11 @@
var z = PI;
''');
assertType(findElement.topVar('x').type, 'int');
- assertType(findElement.topVar('y').type, 'int*');
+ assertType(findElement.topVar('y').type, 'int');
assertType(findElement.topVar('z').type, 'double');
+
+ var importFind = findElement.importFind('package:aaa/a.dart');
+ assertType(importFind.topVar('a').type, 'int*');
}
}
@@ -114,7 +118,7 @@
test_jsonConfig_disable() async {
_configureAllowedExperimentsTestNullSafety();
- newFile('/test/.dart_tool/package_config.json', content: '''
+ _configureTestWithJsonConfig('''
{
"configVersion": 2,
"packages": [
@@ -127,7 +131,6 @@
]
}
''');
- _configureTestWithJsonConfig();
await assertNoErrorsInCode('''
var x = 0;
@@ -146,7 +149,7 @@
test_jsonConfig_enable() async {
_configureAllowedExperimentsTestNullSafety();
- newFile('/test/.dart_tool/package_config.json', content: '''
+ _configureTestWithJsonConfig('''
{
"configVersion": 2,
"packages": [
@@ -158,7 +161,6 @@
]
}
''');
- _configureTestWithJsonConfig();
await assertNoErrorsInCode('''
var x = 0;
@@ -206,8 +208,59 @@
}
}
+@reflectiveTest
+class PackageConfigAndLanguageOverrideTest extends _FeaturesTest {
+ test_jsonConfigDisablesExtensions() async {
+ _configureTestWithJsonConfig('''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "test",
+ "rootUri": "../",
+ "packageUri": "lib/",
+ "languageVersion": "2.3"
+ }
+ ]
+}
+''');
+
+ await assertErrorsInCode('''
+extension E on int {}
+''', [
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 0, 9),
+ error(ParserErrorCode.EXPERIMENT_NOT_ENABLED, 0, 9),
+ error(CompileTimeErrorCode.UNDEFINED_CLASS, 12, 2),
+ error(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 15, 3),
+ ]);
+ }
+
+ test_jsonConfigDisablesExtensions_languageOverrideEnables() async {
+ _configureTestWithJsonConfig('''
+{
+ "configVersion": 2,
+ "packages": [
+ {
+ "name": "test",
+ "rootUri": "../",
+ "packageUri": "lib/",
+ "languageVersion": "2.3"
+ }
+ ]
+}
+''');
+
+ await assertNoErrorsInCode('''
+// @dart = 2.6
+extension E on int {}
+''');
+ }
+}
+
class _FeaturesTest extends DriverResolutionTest {
- void _configureTestWithJsonConfig() {
+ void _configureTestWithJsonConfig(String content) {
+ newFile('/test/.dart_tool/package_config.json', content: content);
+
driver.configure(
packages: findPackagesFrom(
resourceProvider,
diff --git a/pkg/analyzer/test/src/dart/resolution/test_all.dart b/pkg/analyzer/test/src/dart/resolution/test_all.dart
index 2918265..33cdc60 100644
--- a/pkg/analyzer/test/src/dart/resolution/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/test_all.dart
@@ -17,6 +17,7 @@
import 'export_test.dart' as export_;
import 'extension_method_test.dart' as extension_method;
import 'extension_override_test.dart' as extension_override;
+import 'field_test.dart' as field;
import 'for_element_test.dart' as for_element;
import 'for_statement_test.dart' as for_in;
import 'function_expression_invocation_test.dart'
@@ -49,6 +50,7 @@
import 'prefixed_identifier_test.dart' as prefixed_identifier;
import 'property_access_test.dart' as property_access;
import 'simple_identifier_test.dart' as simple_identifier;
+import 'top_level_variable_test.dart' as top_level_variable;
import 'top_type_inference_test.dart' as top_type_inference;
import 'try_statement_test.dart' as try_statement;
import 'type_inference/test_all.dart' as type_inference;
@@ -70,6 +72,7 @@
export_.main();
extension_method.main();
extension_override.main();
+ field.main();
for_element.main();
for_in.main();
function_expression_invocation.main();
@@ -99,6 +102,7 @@
prefixed_identifier.main();
property_access.main();
simple_identifier.main();
+ top_level_variable.main();
top_type_inference.main();
try_statement.main();
type_name.main();
diff --git a/pkg/analyzer/test/src/dart/resolution/top_level_variable_test.dart b/pkg/analyzer/test/src/dart/resolution/top_level_variable_test.dart
new file mode 100644
index 0000000..8640cb0
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/top_level_variable_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../constant/potentially_constant_test.dart';
+import 'driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(TopLevelVariableTest);
+ defineReflectiveTests(TopLevelVariableWithNullSafetyTest);
+ });
+}
+
+@reflectiveTest
+class TopLevelVariableTest extends DriverResolutionTest {
+ test_type_inferred_int() async {
+ await resolveTestCode('''
+var v = 0;
+''');
+ assertType(findElement.topVar('v').type, 'int');
+ }
+
+ test_type_inferred_Never() async {
+ await resolveTestCode('''
+var v = throw 42;
+''');
+ assertType(
+ findElement.topVar('v').type,
+ typeStringByNullability(
+ nullable: 'Never',
+ legacy: 'dynamic',
+ ),
+ );
+ }
+
+ test_type_inferred_noInitializer() async {
+ await resolveTestCode('''
+var v;
+''');
+ assertType(findElement.topVar('v').type, 'dynamic');
+ }
+
+ test_type_inferred_null() async {
+ await resolveTestCode('''
+var v = null;
+''');
+ assertType(findElement.topVar('v').type, 'dynamic');
+ }
+}
+
+@reflectiveTest
+class TopLevelVariableWithNullSafetyTest extends TopLevelVariableTest
+ with WithNullSafetyMixin {
+ test_type_inferred_nonNullify() async {
+ newFile('/test/lib/a.dart', content: r'''
+// @dart = 2.7
+var a = 0;
+''');
+
+ await assertNoErrorsInCode('''
+import 'a.dart';
+
+var v = a;
+''');
+
+ assertType(findElement.topVar('v').type, 'int');
+ }
+}
diff --git a/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart b/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
index a7f7a58..e796527 100644
--- a/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
+++ b/pkg/analyzer/test/src/dartdoc/dartdoc_directive_info_test.dart
@@ -16,6 +16,16 @@
class DartdocDirectiveInfoTest {
DartdocDirectiveInfo info = DartdocDirectiveInfo();
+ test_processDartdoc_animation_directive() {
+ String result = info.processDartdoc('''
+/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4}
+''');
+ expect(
+ result,
+ '[flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4]'
+ '(https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4)');
+ }
+
test_processDartdoc_macro_defined() {
info.extractTemplate('''
/**
@@ -97,14 +107,4 @@
expect(result,
'{@youtube 560x315 https://www.youtube.com/watch?v=2uaoEDOgk_I}');
}
-
- test_processDartdoc_animation_directive() {
- String result = info.processDartdoc('''
-/// {@animation 464 192 https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4}
-''');
- expect(
- result,
- '[flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4]'
- '(https://flutter.github.io/assets-for-api-docs/assets/animation/curve_bounce_in.mp4)');
- }
}
diff --git a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
index 2cc6cb6..3fd011e 100644
--- a/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/argument_type_not_assignable_test.dart
@@ -394,6 +394,24 @@
[EnableString.non_nullable],
);
+ test_binary_eqEq_covariantParameterType() async {
+ await assertErrorsInCode(r'''
+class A {
+ bool operator==(covariant A other) => false;
+}
+
+main(A a, A? aq) {
+ a == 0;
+ aq == 1;
+ aq == aq;
+ aq == null;
+}
+''', [
+ error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 86, 1),
+ error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 97, 1),
+ ]);
+ }
+
test_downcast() async {
await assertErrorsInCode(r'''
m() {
@@ -419,24 +437,6 @@
]);
}
- test_binary_eqEq_covariantParameterType() async {
- await assertErrorsInCode(r'''
-class A {
- bool operator==(covariant A other) => false;
-}
-
-main(A a, A? aq) {
- a == 0;
- aq == 1;
- aq == aq;
- aq == null;
-}
-''', [
- error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 86, 1),
- error(StaticWarningCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 97, 1),
- ]);
- }
-
test_dynamicCast() async {
await assertNoErrorsInCode(r'''
m() {
diff --git a/pkg/analyzer/test/src/diagnostics/assert_in_redirecting_constructor_test.dart b/pkg/analyzer/test/src/diagnostics/assert_in_redirecting_constructor_test.dart
index 76c31a4..240ede4 100644
--- a/pkg/analyzer/test/src/diagnostics/assert_in_redirecting_constructor_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assert_in_redirecting_constructor_test.dart
@@ -25,14 +25,14 @@
''', [error(CompileTimeErrorCode.ASSERT_IN_REDIRECTING_CONSTRUCTOR, 34, 13)]);
}
- test_redirectionBeforeAssert() async {
- await assertErrorsInCode(r'''
+ test_justAssert() async {
+ await assertNoErrorsInCode(r'''
class A {}
class B {
- B(int x) : this.name(), assert(x > 0);
+ B(int x) : assert(x > 0);
B.name() {}
}
-''', [error(CompileTimeErrorCode.ASSERT_IN_REDIRECTING_CONSTRUCTOR, 47, 13)]);
+''');
}
test_justRedirection() async {
@@ -45,13 +45,13 @@
''');
}
- test_justAssert() async {
- await assertNoErrorsInCode(r'''
+ test_redirectionBeforeAssert() async {
+ await assertErrorsInCode(r'''
class A {}
class B {
- B(int x) : assert(x > 0);
+ B(int x) : this.name(), assert(x > 0);
B.name() {}
}
-''');
+''', [error(CompileTimeErrorCode.ASSERT_IN_REDIRECTING_CONSTRUCTOR, 47, 13)]);
}
}
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
index a9022b5..7187511 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
@@ -51,17 +51,6 @@
]);
}
- test_localVariable_plusEq() async {
- await assertErrorsInCode('''
-f() {
- const x = 0;
- x += 1;
-}''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 14, 1),
- error(StaticWarningCode.ASSIGNMENT_TO_CONST, 23, 1),
- ]);
- }
-
test_localVariable_inForEach() async {
await assertErrorsInCode('''
f() {
@@ -73,4 +62,15 @@
error(StaticWarningCode.ASSIGNMENT_TO_CONST, 28, 1),
]);
}
+
+ test_localVariable_plusEq() async {
+ await assertErrorsInCode('''
+f() {
+ const x = 0;
+ x += 1;
+}''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 14, 1),
+ error(StaticWarningCode.ASSIGNMENT_TO_CONST, 23, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
index 1b585d9..cc747dd 100644
--- a/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/async_keyword_used_as_identifier_test.dart
@@ -16,6 +16,18 @@
@reflectiveTest
class AsyncKeywordUsedAsIdentifierTest extends DriverResolutionTest {
+ test_async_async() async {
+ await assertErrorsInCode(r'''
+class A {
+ m() async {
+ int async;
+ }
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 32, 5),
+ ]);
+ }
+
test_await_async() async {
await assertErrorsInCode('''
f() async {
@@ -81,16 +93,4 @@
error(HintCode.UNUSED_LOCAL_VARIABLE, 18, 5),
]);
}
-
- test_async_async() async {
- await assertErrorsInCode(r'''
-class A {
- m() async {
- int async;
- }
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 32, 5),
- ]);
- }
}
diff --git a/pkg/analyzer/test/src/diagnostics/const_constructor_with_field_initialized_by_non_const_test.dart b/pkg/analyzer/test/src/diagnostics/const_constructor_with_field_initialized_by_non_const_test.dart
new file mode 100644
index 0000000..8ac4dfe
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/const_constructor_with_field_initialized_by_non_const_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+ defineReflectiveSuite(() {
+ defineReflectiveTests(ConstConstructorWithFieldInitializedByNonConstTest);
+ });
+}
+
+@reflectiveTest
+class ConstConstructorWithFieldInitializedByNonConstTest
+ extends DriverResolutionTest {
+ test_factoryConstructor() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ final List<int> list = f();
+ const factory A() = B;
+}
+class B implements A {
+ final List<int> list = const [];
+ const B();
+}
+List<int> f() {
+ return [3];
+}
+''');
+ }
+
+ test_instanceField() async {
+ await assertErrorsInCode(r'''
+class A {
+ final int i = f();
+ const A();
+}
+int f() {
+ return 3;
+}
+''', [
+ error(
+ CompileTimeErrorCode
+ .CONST_CONSTRUCTOR_WITH_FIELD_INITIALIZED_BY_NON_CONST,
+ 33,
+ 10),
+ ]);
+ }
+
+ test_staticField() async {
+ await assertNoErrorsInCode(r'''
+class A {
+ static final int i = f();
+ const A();
+}
+int f() {
+ return 3;
+}
+''');
+ }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/const_map_key_expression_type_implements_equals_test.dart b/pkg/analyzer/test/src/diagnostics/const_map_key_expression_type_implements_equals_test.dart
index f30871d..ee3066f 100644
--- a/pkg/analyzer/test/src/diagnostics/const_map_key_expression_type_implements_equals_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_map_key_expression_type_implements_equals_test.dart
@@ -107,6 +107,29 @@
]);
}
+ test_nestedIn_instanceCreation() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+
+ bool operator ==(other) => false;
+}
+
+class B {
+ const B(_);
+}
+
+main() {
+ const B({A(): 0});
+}
+''', [
+ error(
+ CompileTimeErrorCode.CONST_MAP_KEY_EXPRESSION_TYPE_IMPLEMENTS_EQUALS,
+ 110,
+ 3),
+ ]);
+ }
+
test_super() async {
await assertErrorsInCode(r'''
class A {
diff --git a/pkg/analyzer/test/src/diagnostics/const_set_element_type_implements_equals_test.dart b/pkg/analyzer/test/src/diagnostics/const_set_element_type_implements_equals_test.dart
index 14c649c..62ca512 100644
--- a/pkg/analyzer/test/src/diagnostics/const_set_element_type_implements_equals_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_set_element_type_implements_equals_test.dart
@@ -92,6 +92,27 @@
]);
}
+ test_nestedIn_instanceCreation() async {
+ await assertErrorsInCode(r'''
+class A {
+ const A();
+
+ bool operator ==(other) => false;
+}
+
+class B {
+ const B(_);
+}
+
+main() {
+ const B({A()});
+}
+''', [
+ error(CompileTimeErrorCode.CONST_SET_ELEMENT_TYPE_IMPLEMENTS_EQUALS, 110,
+ 3),
+ ]);
+ }
+
test_spread_list() async {
await assertErrorsInCode(
r'''
diff --git a/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart b/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
index 385b408..eb1ddf7 100644
--- a/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/for_in_of_invalid_element_type_test.dart
@@ -42,6 +42,19 @@
]);
}
+ test_bad_type_bound() async {
+ await assertErrorsInCode('''
+class Foo<T extends Iterable<int>> {
+ void method(T iterable) {
+ for (String i in iterable) {}
+ }
+}
+''', [
+ error(HintCode.UNUSED_LOCAL_VARIABLE, 81, 1),
+ error(StaticTypeWarningCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 86, 8),
+ ]);
+ }
+
test_declaredVariableWrongType() async {
await assertErrorsInCode('''
f() {
@@ -64,17 +77,4 @@
error(StaticTypeWarningCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 27, 10),
]);
}
-
- test_bad_type_bound() async {
- await assertErrorsInCode('''
-class Foo<T extends Iterable<int>> {
- void method(T iterable) {
- for (String i in iterable) {}
- }
-}
-''', [
- error(HintCode.UNUSED_LOCAL_VARIABLE, 81, 1),
- error(StaticTypeWarningCode.FOR_IN_OF_INVALID_ELEMENT_TYPE, 86, 8),
- ]);
- }
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_null_aware_operator_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_null_aware_operator_test.dart
index 1d72a87..d36cb8f 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_null_aware_operator_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_null_aware_operator_test.dart
@@ -97,6 +97,24 @@
''');
}
+ /// Here we test that analysis does not crash while checking whether to
+ /// report [StaticWarningCode.INVALID_NULL_AWARE_OPERATOR]. But we also
+ /// report another error.
+ test_getter_prefix() async {
+ newFile('/test/lib/a.dart', content: r'''
+int x = 0;
+''');
+ await assertErrorsInCode('''
+import 'a.dart' as p;
+
+f() {
+ p?.x;
+}
+''', [
+ error(CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, 31, 1),
+ ]);
+ }
+
test_index_legacy() async {
newFile('/test/lib/a.dart', content: r'''
// @dart = 2.5
@@ -287,4 +305,22 @@
}
''');
}
+
+ /// Here we test that analysis does not crash while checking whether to
+ /// report [StaticWarningCode.INVALID_NULL_AWARE_OPERATOR]. But we also
+ /// report another error.
+ test_setter_prefix() async {
+ newFile('/test/lib/a.dart', content: r'''
+int x = 0;
+''');
+ await assertErrorsInCode('''
+import 'a.dart' as p;
+
+f() {
+ p?.x = 0;
+}
+''', [
+ error(CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, 31, 1),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
index 5782b42..71ba74c 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_required_optional_positional_param_test.dart
@@ -33,16 +33,6 @@
]);
}
- test_positionalParameter_withDefault() async {
- await assertErrorsInCode(r'''
-import 'package:meta/meta.dart';
-
-m([@required a = 1]) => null;
-''', [
- error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 15),
- ]);
- }
-
test_positionalParameter_noDefault_asSecond() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -53,6 +43,16 @@
]);
}
+ test_positionalParameter_withDefault() async {
+ await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+m([@required a = 1]) => null;
+''', [
+ error(HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM, 37, 15),
+ ]);
+ }
+
test_positionalParameter_withDefault_withTwo() async {
await assertErrorsInCode(r'''
import 'package:meta/meta.dart';
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
index b9d949c..b37129a 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_deferred_class_test.dart
@@ -15,20 +15,6 @@
@reflectiveTest
class MixinDeferredClassTest extends DriverResolutionTest {
- test_mixin_deferred_class() async {
- newFile('/test/lib/lib1.dart', content: '''
-library lib1;
-class A {}
-''');
- await assertErrorsInCode('''
-library root;
-import 'lib1.dart' deferred as a;
-class B extends Object with a.A {}
-''', [
- error(CompileTimeErrorCode.MIXIN_DEFERRED_CLASS, 76, 3),
- ]);
- }
-
test_classTypeAlias() async {
newFile('/test/lib/lib1.dart', content: '''
library lib1;
@@ -43,4 +29,18 @@
error(CompileTimeErrorCode.MIXIN_DEFERRED_CLASS, 76, 3),
]);
}
+
+ test_mixin_deferred_class() async {
+ newFile('/test/lib/lib1.dart', content: '''
+library lib1;
+class A {}
+''');
+ await assertErrorsInCode('''
+library root;
+import 'lib1.dart' deferred as a;
+class B extends Object with a.A {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_DEFERRED_CLASS, 76, 3),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/mixin_of_non_class_test.dart b/pkg/analyzer/test/src/diagnostics/mixin_of_non_class_test.dart
index 6013ac5..937abac 100644
--- a/pkg/analyzer/test/src/diagnostics/mixin_of_non_class_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/mixin_of_non_class_test.dart
@@ -18,18 +18,6 @@
@reflectiveTest
class MixinOfNonClassTest extends DriverResolutionTest {
- @failingTest
- test_non_class() async {
- // TODO(brianwilkerson) Compare with MIXIN_WITH_NON_CLASS_SUPERCLASS.
- // TODO(brianwilkerson) Fix the offset and length.
- await assertErrorsInCode(r'''
-var A;
-class B extends Object mixin A {}
-''', [
- error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 0, 0),
- ]);
- }
-
test_class() async {
await assertErrorsInCode(r'''
int A = 7;
@@ -48,6 +36,18 @@
]);
}
+ @failingTest
+ test_non_class() async {
+ // TODO(brianwilkerson) Compare with MIXIN_WITH_NON_CLASS_SUPERCLASS.
+ // TODO(brianwilkerson) Fix the offset and length.
+ await assertErrorsInCode(r'''
+var A;
+class B extends Object mixin A {}
+''', [
+ error(CompileTimeErrorCode.MIXIN_OF_NON_CLASS, 0, 0),
+ ]);
+ }
+
test_typeAlias() async {
await assertErrorsInCode(r'''
class A {}
diff --git a/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart b/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
index 5887b6e..d93fced 100644
--- a/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/must_call_super_test.dart
@@ -55,20 +55,6 @@
]);
}
- test_fromExtendingClass_abstractInSuperclass() async {
- await assertNoErrorsInCode(r'''
-import 'package:meta/meta.dart';
-abstract class A {
- @mustCallSuper
- void a();
-}
-class B extends A {
- @override
- void a() {}
-}
-''');
- }
-
test_fromExtendingClass_abstractInSubclass() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
@@ -83,6 +69,20 @@
''');
}
+ test_fromExtendingClass_abstractInSuperclass() async {
+ await assertNoErrorsInCode(r'''
+import 'package:meta/meta.dart';
+abstract class A {
+ @mustCallSuper
+ void a();
+}
+class B extends A {
+ @override
+ void a() {}
+}
+''');
+ }
+
test_fromInterface() async {
await assertNoErrorsInCode(r'''
import 'package:meta/meta.dart';
diff --git a/pkg/analyzer/test/src/diagnostics/private_optional_parameter_test.dart b/pkg/analyzer/test/src/diagnostics/private_optional_parameter_test.dart
index 6c11828..6a6812c 100644
--- a/pkg/analyzer/test/src/diagnostics/private_optional_parameter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/private_optional_parameter_test.dart
@@ -15,14 +15,6 @@
@reflectiveTest
class PrivateOptionalParameterTest extends DriverResolutionTest {
- test_private() async {
- await assertErrorsInCode('''
-f({var _p}) {}
-''', [
- error(CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, 3, 6),
- ]);
- }
-
test_fieldFormal() async {
await assertErrorsInCode(r'''
class A {
@@ -35,6 +27,14 @@
]);
}
+ test_private() async {
+ await assertErrorsInCode('''
+f({var _p}) {}
+''', [
+ error(CompileTimeErrorCode.PRIVATE_OPTIONAL_PARAMETER, 3, 6),
+ ]);
+ }
+
test_withDefaultValue() async {
await assertErrorsInCode('''
f({_p : 0}) {}
diff --git a/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart b/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
index fd3bd1b..a42d2d6 100644
--- a/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/rethrow_outside_catch_test.dart
@@ -15,16 +15,6 @@
@reflectiveTest
class RethrowOutsideCatchTest extends DriverResolutionTest {
- test_withoutCatch() async {
- await assertErrorsInCode(r'''
-f() {
- rethrow;
-}
-''', [
- error(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, 8, 7),
- ]);
- }
-
test_insideCatch() async {
await assertNoErrorsInCode(r'''
class A {
@@ -34,4 +24,14 @@
}
''');
}
+
+ test_withoutCatch() async {
+ await assertErrorsInCode(r'''
+f() {
+ rethrow;
+}
+''', [
+ error(CompileTimeErrorCode.RETHROW_OUTSIDE_CATCH, 8, 7),
+ ]);
+ }
}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 9fb2370..8beac00 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -56,6 +56,8 @@
as conflicting_type_variable_and_member;
import 'const_constructor_param_type_mismatch_test.dart'
as const_constructor_param_type_mismatch;
+import 'const_constructor_with_field_initialized_by_non_const_test.dart'
+ as const_constructor_with_field_initialized_by_non_const;
import 'const_constructor_with_mixin_with_field_test.dart'
as const_constructor_with_mixin_with_field;
import 'const_eval_throws_exception_test.dart' as const_eval_throws_exception;
@@ -571,6 +573,7 @@
conflicting_type_variable_and_container.main();
conflicting_type_variable_and_member.main();
const_constructor_param_type_mismatch.main();
+ const_constructor_with_field_initialized_by_non_const.main();
const_constructor_with_mixin_with_field.main();
const_eval_throws_exception.main();
const_map_key_expression_type_implements_equals.main();
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
index 7e5fd48..20a5cd5 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
@@ -30,30 +30,6 @@
]);
}
- test_synthetic_whenExpression_defined() async {
- await assertErrorsInCode(r'''
-print(x) {}
-main() {
- print(is String);
-}
-''', [
- error(ParserErrorCode.MISSING_IDENTIFIER, 29, 2),
- ]);
- }
-
- test_synthetic_whenMethodName_defined() async {
- await assertErrorsInCode(r'''
-print(x) {}
-main(int p) {
- p.();
-}
-''', [
- error(ParserErrorCode.MISSING_IDENTIFIER, 30, 1),
- error(StaticTypeWarningCode.UNDEFINED_GETTER, 30, 1),
- error(ParserErrorCode.MISSING_IDENTIFIER, 31, 1),
- ]);
- }
-
test_for() async {
await assertErrorsInCode('''
f(var l) {
@@ -174,6 +150,30 @@
error(StaticWarningCode.UNDEFINED_IDENTIFIER, 54, 4),
]);
}
+
+ test_synthetic_whenExpression_defined() async {
+ await assertErrorsInCode(r'''
+print(x) {}
+main() {
+ print(is String);
+}
+''', [
+ error(ParserErrorCode.MISSING_IDENTIFIER, 29, 2),
+ ]);
+ }
+
+ test_synthetic_whenMethodName_defined() async {
+ await assertErrorsInCode(r'''
+print(x) {}
+main(int p) {
+ p.();
+}
+''', [
+ error(ParserErrorCode.MISSING_IDENTIFIER, 30, 1),
+ error(StaticTypeWarningCode.UNDEFINED_GETTER, 30, 1),
+ error(ParserErrorCode.MISSING_IDENTIFIER, 31, 1),
+ ]);
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/test/src/fasta/token_utils_test.dart b/pkg/analyzer/test/src/fasta/token_utils_test.dart
index 5f138e8..8db705a 100644
--- a/pkg/analyzer/test/src/fasta/token_utils_test.dart
+++ b/pkg/analyzer/test/src/fasta/token_utils_test.dart
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'package:analyzer/src/fasta/token_utils.dart';
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
+import 'package:analyzer/src/fasta/token_utils.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 2f12e46..01364df 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -191,6 +191,24 @@
assertCanBeConst("B(A(", false);
}
+ void test_false_mapKeyType_implementsEqual() async {
+ await resolve('''
+class A {
+ const A();
+ bool operator ==(other) => false;
+}
+
+class B {
+ const B(_);
+}
+
+main() {
+ B({A(): 0});
+}
+''');
+ assertCanBeConst("B({", false);
+ }
+
void test_false_nonConstConstructor() async {
await resolve('''
class A {}
@@ -199,6 +217,24 @@
assertCanBeConst("A(", false);
}
+ void test_false_setElementType_implementsEqual() async {
+ await resolve('''
+class A {
+ const A();
+ bool operator ==(other) => false;
+}
+
+class B {
+ const B(_);
+}
+
+main() {
+ B({A()});
+}
+''');
+ assertCanBeConst("B({", false);
+ }
+
void test_false_typeParameter() async {
await resolve('''
class A<T> {
diff --git a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
index a7d53c6..064d487 100644
--- a/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
+++ b/pkg/analyzer/test/src/manifest/manifest_validator_test.dart
@@ -47,31 +47,14 @@
validator = ManifestValidator(source);
}
- test_hardwareNotSupported_error() {
+ test_cameraPermissions_error() {
assertErrors('''
<manifest
- xmlns:android="http://schemas.android.com/apk/res/android">
+ xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
- <uses-feature android:name="android.software.home_screen" />
+ <uses-permission android:name="android.permission.CAMERA" />
</manifest>
-''', [ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE]);
- }
-
- test_noTouchScreen_error() {
- assertErrors('''
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android">
-</manifest>
-''', [ManifestWarningCode.NO_TOUCHSCREEN_FEATURE]);
- }
-
- test_touchScreenNotSupported_error() {
- assertErrors('''
-<manifest
- xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-feature android:name="android.hardware.touchscreen" android:required="true"/>
-</manifest>
-''', [ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE]);
+''', [ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE]);
}
test_featureNotSupported_error() {
@@ -83,29 +66,35 @@
''', [ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE]);
}
- test_cameraPermissions_error() {
+ test_hardwareNotSupported_error() {
assertErrors('''
<manifest
- xmlns:android="http://schemas.android.com/apk/res/android">
+ xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
- <uses-permission android:name="android.permission.CAMERA" />
+ <uses-feature android:name="android.software.home_screen" />
</manifest>
-''', [ManifestWarningCode.CAMERA_PERMISSIONS_INCOMPATIBLE]);
+''', [ManifestWarningCode.UNSUPPORTED_CHROME_OS_HARDWARE]);
}
- test_screenOrientation_error() {
+ test_no_errors() {
assertErrors('''
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
- <application android:label="@string/app_name">
- <activity android:name="testActivity"
- android:screenOrientation="landscape"
- android:exported="false">
- </activity>
- </application>
+ <activity android:name="testActivity"
+ android:resizeableActivity="true"
+ android:exported="false">
+ </activity>
</manifest>
-''', [ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY]);
+''', []);
+ }
+
+ test_noTouchScreen_error() {
+ assertErrors('''
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
+''', [ManifestWarningCode.NO_TOUCHSCREEN_FEATURE]);
}
test_resizeableactivity_error() {
@@ -123,16 +112,27 @@
''', [ManifestWarningCode.NON_RESIZABLE_ACTIVITY]);
}
- test_no_errors() {
+ test_screenOrientation_error() {
assertErrors('''
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
- <activity android:name="testActivity"
- android:resizeableActivity="true"
- android:exported="false">
- </activity>
+ <application android:label="@string/app_name">
+ <activity android:name="testActivity"
+ android:screenOrientation="landscape"
+ android:exported="false">
+ </activity>
+ </application>
</manifest>
-''', []);
+''', [ManifestWarningCode.SETTING_ORIENTATION_ON_ACTIVITY]);
+ }
+
+ test_touchScreenNotSupported_error() {
+ assertErrors('''
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <uses-feature android:name="android.hardware.touchscreen" android:required="true"/>
+</manifest>
+''', [ManifestWarningCode.UNSUPPORTED_CHROME_OS_FEATURE]);
}
}
diff --git a/pkg/analyzer/test/src/options/options_rule_validator_test.dart b/pkg/analyzer/test/src/options/options_rule_validator_test.dart
index 2de43ac..9586500 100644
--- a/pkg/analyzer/test/src/options/options_rule_validator_test.dart
+++ b/pkg/analyzer/test/src/options/options_rule_validator_test.dart
@@ -90,12 +90,6 @@
}
}
-class StableLint extends LintRule {
- StableLint()
- : super(
- name: 'stable_lint', group: Group.style, maturity: Maturity.stable);
-}
-
class RuleNeg extends LintRule {
RuleNeg() : super(name: 'rule_neg', group: Group.style);
@override
@@ -107,3 +101,9 @@
@override
List<String> get incompatibleRules => ['rule_neg'];
}
+
+class StableLint extends LintRule {
+ StableLint()
+ : super(
+ name: 'stable_lint', group: Group.style, maturity: Maturity.stable);
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 6513033..8836488 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -6258,6 +6258,50 @@
''');
}
+ test_field_type_inferred_Never() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary(r'''
+class C {
+ var a = throw 42;
+}
+''');
+
+ checkElementText(
+ library,
+ r'''
+class C {
+ Never a;
+}
+''',
+ annotateNullability: true);
+ }
+
+ test_field_type_inferred_nonNullify() async {
+ featureSet = enableNnbd;
+
+ addSource('/a.dart', '''
+// @dart = 2.7
+var a = 0;
+''');
+
+ var library = await checkLibrary(r'''
+import 'a.dart';
+class C {
+ var b = a;
+}
+''');
+
+ checkElementText(
+ library,
+ r'''
+import 'a.dart';
+class C {
+ int b;
+}
+''',
+ annotateNullability: true);
+ }
+
test_field_typed() async {
var library = await checkLibrary('class C { int x = 0; }');
checkElementText(library, r'''
@@ -11561,6 +11605,52 @@
''');
}
+ test_variable_type_inferred_Never() async {
+ featureSet = enableNnbd;
+ var library = await checkLibrary(r'''
+var a = throw 42;
+''');
+
+ checkElementText(
+ library,
+ r'''
+Never a;
+''',
+ annotateNullability: true);
+ }
+
+ test_variable_type_inferred_noInitializer() async {
+ var library = await checkLibrary(r'''
+var a;
+''');
+
+ checkElementText(library, r'''
+dynamic a;
+''');
+ }
+
+ test_variable_type_inferred_nonNullify() async {
+ featureSet = enableNnbd;
+
+ addSource('/a.dart', '''
+// @dart = 2.7
+var a = 0;
+''');
+
+ var library = await checkLibrary(r'''
+import 'a.dart';
+var b = a;
+''');
+
+ checkElementText(
+ library,
+ r'''
+import 'a.dart';
+int b;
+''',
+ annotateNullability: true);
+ }
+
test_variableInitializer_contextType_after_astRewrite() async {
var library = await checkLibrary(r'''
class A<T> {
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index 5bd873f..ef149a1 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -23,7 +23,10 @@
featureSet ??= FeatureSet.forTesting(sdkVersion: '2.3.0');
CharSequenceReader reader = CharSequenceReader(text);
Scanner scanner = Scanner(null, reader, AnalysisErrorListener.NULL_LISTENER)
- ..configureFeatures(featureSet);
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ );
Token token = scanner.tokenize();
// Pass the feature set from the scanner to the parser
// because the scanner may have detected a language version comment
diff --git a/pkg/analyzer/test/util/id_testing_helper.dart b/pkg/analyzer/test/util/id_testing_helper.dart
index 645ddfd..be77c72 100644
--- a/pkg/analyzer/test/util/id_testing_helper.dart
+++ b/pkg/analyzer/test/util/id_testing_helper.dart
@@ -321,13 +321,6 @@
DataInterpreter<T> get dataValidator;
- /// Function that computes a data mapping for [unit].
- ///
- /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans
- /// for the data origin.
- void computeUnitData(TestingData testingData, CompilationUnit unit,
- Map<Id, ActualData<T>> actualMap);
-
/// Returns `true` if this data computer supports tests with compile-time
/// errors.
///
@@ -339,6 +332,13 @@
T computeErrorData(TestConfig config, TestingData testingData, Id id,
List<AnalysisError> errors) =>
null;
+
+ /// Function that computes a data mapping for [unit].
+ ///
+ /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans
+ /// for the data origin.
+ void computeUnitData(TestingData testingData, CompilationUnit unit,
+ Map<Id, ActualData<T>> actualMap);
}
class TestConfig {
diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart
index f68108a..c8d5635 100644
--- a/pkg/analyzer/tool/summary/mini_ast.dart
+++ b/pkg/analyzer/tool/summary/mini_ast.dart
@@ -146,29 +146,6 @@
}
}
-/// "Mini AST" representation of a named expression.
-class NamedExpression extends Expression {
- final String name;
- final Token colon;
- final Expression expression;
-
- NamedExpression(this.name, this.colon, this.expression);
-}
-
-/// "Mini AST" representation of a named expression.
-class PrefixedIdentifier extends Expression {
- final String prefix;
- final Token operator;
- final String identifier;
-
- PrefixedIdentifier(this.prefix, this.operator, this.identifier);
-
- @override
- String toCode() {
- return '$prefix.$identifier';
- }
-}
-
/// "Mini AST" representation of a method declaration.
class MethodDeclaration extends ClassMember {
final bool isGetter;
@@ -193,11 +170,6 @@
Uri get uri => null;
@override
- dynamic internalProblem(Message message, int charOffset, Uri uri) {
- throw UnsupportedError(message.message);
- }
-
- @override
void addProblem(Message message, int charOffset, int length,
{bool wasHandled = false, List<LocatedMessage> context}) {
internalProblem(message, charOffset, uri);
@@ -225,31 +197,22 @@
}
@override
- void endClassOrMixinBody(
- DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
- debugEvent("ClassOrMixinBody");
- push(popList(memberCount,
- List<ClassMember>.filled(memberCount, null, growable: true)));
- }
+ void endBinaryExpression(Token token) {
+ debugEvent("BinaryExpression");
- @override
- void handleClassWithClause(Token withKeyword) {
- debugEvent("ClassWithClause");
- }
-
- @override
- void handleClassNoWithClause() {
- debugEvent("NoClassWithClause");
- }
-
- @override
- void handleNamedMixinApplicationWithClause(Token withKeyword) {
- debugEvent("NamedMixinApplicationWithClause");
- }
-
- @override
- void handleRecoverClassHeader() {
- pop(); // superclass
+ if (identical('.', token.stringValue)) {
+ var rightOperand = pop();
+ var leftOperand = pop();
+ if (leftOperand is String && !leftOperand.contains('.')) {
+ push(PrefixedIdentifier(leftOperand, token, rightOperand));
+ } else {
+ push(UnknownExpression());
+ }
+ } else {
+ pop(); // RHS
+ pop(); // LHS
+ push(UnknownExpression());
+ }
}
@override
@@ -266,6 +229,42 @@
}
@override
+ void endClassFactoryMethod(
+ Token beginToken, Token factoryKeyword, Token endToken) {
+ debugEvent("ClassFactoryMethod");
+ pop(); // Body
+ pop(); // Type variables
+ String name = pop();
+ List<Annotation> metadata = popTypedList();
+ Comment comment = pop();
+ push(ConstructorDeclaration(comment, metadata, name));
+ }
+
+ @override
+ void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+ Token beginInitializers, Token endToken) {
+ debugEvent("Method");
+ pop(); // Body
+ pop(); // Initializers
+ pop(); // Formal parameters
+ pop(); // Type variables
+ String name = pop();
+ TypeName returnType = pop();
+ List<Annotation> metadata = popTypedList();
+ Comment comment = pop();
+ push(MethodDeclaration(
+ comment, metadata, getOrSet?.lexeme == 'get', name, returnType));
+ }
+
+ @override
+ void endClassOrMixinBody(
+ DeclarationKind kind, int memberCount, Token beginToken, Token endToken) {
+ debugEvent("ClassOrMixinBody");
+ push(popList(memberCount,
+ List<ClassMember>.filled(memberCount, null, growable: true)));
+ }
+
+ @override
void endCombinators(int count) {
debugEvent("Combinators");
}
@@ -295,18 +294,6 @@
}
@override
- void endClassFactoryMethod(
- Token beginToken, Token factoryKeyword, Token endToken) {
- debugEvent("ClassFactoryMethod");
- pop(); // Body
- pop(); // Type variables
- String name = pop();
- List<Annotation> metadata = popTypedList();
- Comment comment = pop();
- push(ConstructorDeclaration(comment, metadata, name));
- }
-
- @override
void endFieldInitializer(Token assignment, Token token) {
debugEvent("FieldInitializer");
pop(); // Expression
@@ -335,18 +322,6 @@
}
@override
- void handleIdentifierList(int count) {
- debugEvent("IdentifierList");
- push(popList(count, List<dynamic>.filled(count, null, growable: true)));
- }
-
- @override
- void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
- debugEvent("ImportPrefix");
- pushIfNull(asKeyword, NullValue.Prefix);
- }
-
- @override
void endImport(Token importKeyword, Token semicolon) {
debugEvent("Import");
pop(NullValue.Prefix); // Prefix identifier
@@ -356,12 +331,6 @@
}
@override
- void handleRecoverImport(Token semicolon) {
- debugEvent("RecoverImport");
- pop(NullValue.Prefix); // Prefix identifier
- }
-
- @override
void endLibraryName(Token libraryKeyword, Token semicolon) {
debugEvent("LibraryName");
pop(); // Library name
@@ -377,20 +346,6 @@
}
@override
- void handleNativeClause(Token nativeToken, bool hasName) {
- debugEvent("NativeClause");
- if (hasName) {
- pop(); // Pop the native name which is a StringLiteral.
- }
- }
-
- @override
- void handleInvalidMember(Token endToken) {
- debugEvent("InvalidMember");
- pop(); // metadata star
- }
-
- @override
void endMember() {
debugEvent("Member");
}
@@ -415,67 +370,12 @@
}
@override
- void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
- Token beginInitializers, Token endToken) {
- debugEvent("Method");
- pop(); // Body
- pop(); // Initializers
- pop(); // Formal parameters
- pop(); // Type variables
- String name = pop();
- TypeName returnType = pop();
- List<Annotation> metadata = popTypedList();
- Comment comment = pop();
- push(MethodDeclaration(
- comment, metadata, getOrSet?.lexeme == 'get', name, returnType));
- }
-
- @override
- void handleSend(Token beginToken, Token endToken) {
- debugEvent("Send");
-
- var arguments = pop();
- pop(); // Type arguments
- if (arguments != null) {
- pop(); // Receiver
- push(UnknownExpression());
- } else {
- // Property get.
- }
- }
-
- @override
void endShow(Token showKeyword) {
debugEvent("Show");
pop(); // Shown names
}
@override
- void handleNamedArgument(Token colon) {
- var expression = pop();
- var name = pop();
- push(NamedExpression(name, colon, expression));
- }
-
- @override
- void handleLiteralList(
- int count, Token leftBracket, Token constKeyword, Token rightBracket) {
- debugEvent("LiteralList");
-
- var elements = List<Object>(count);
- popList(count, elements);
- pop(); // type arguments
-
- push(
- ListLiteral(
- leftBracket,
- List<Expression>.from(elements),
- rightBracket,
- ),
- );
- }
-
- @override
void endTopLevelFields(
Token externalToken,
Token staticToken,
@@ -501,33 +401,18 @@
}
@override
- void handleInvalidTypeArguments(Token token) {
- debugEvent("InvalidTypeArguments");
- pop(NullValue.TypeArguments);
- }
-
- @override
void handleAsyncModifier(Token asyncToken, Token starToken) {
debugEvent("AsyncModifier");
}
@override
- void endBinaryExpression(Token token) {
- debugEvent("BinaryExpression");
+ void handleClassNoWithClause() {
+ debugEvent("NoClassWithClause");
+ }
- if (identical('.', token.stringValue)) {
- var rightOperand = pop();
- var leftOperand = pop();
- if (leftOperand is String && !leftOperand.contains('.')) {
- push(PrefixedIdentifier(leftOperand, token, rightOperand));
- } else {
- push(UnknownExpression());
- }
- } else {
- pop(); // RHS
- pop(); // LHS
- push(UnknownExpression());
- }
+ @override
+ void handleClassWithClause(Token withKeyword) {
+ debugEvent("ClassWithClause");
}
@override
@@ -542,17 +427,6 @@
}
@override
- void handleNativeFunctionBodyIgnored(Token nativeToken, Token semicolon) {
- debugEvent("NativeFunctionBodyIgnored");
- }
-
- @override
- void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
- debugEvent("NativeFunctionBodySkipped");
- push(NullValue.FunctionBody);
- }
-
- @override
void handleIdentifier(Token token, IdentifierContext context) {
if (context == IdentifierContext.enumValueDeclaration) {
List<Annotation> metadata = popTypedList();
@@ -564,24 +438,102 @@
}
@override
+ void handleIdentifierList(int count) {
+ debugEvent("IdentifierList");
+ push(popList(count, List<dynamic>.filled(count, null, growable: true)));
+ }
+
+ @override
+ void handleImportPrefix(Token deferredKeyword, Token asKeyword) {
+ debugEvent("ImportPrefix");
+ pushIfNull(asKeyword, NullValue.Prefix);
+ }
+
+ @override
+ void handleInvalidMember(Token endToken) {
+ debugEvent("InvalidMember");
+ pop(); // metadata star
+ }
+
+ @override
void handleInvalidTopLevelDeclaration(Token endToken) {
debugEvent("InvalidTopLevelDeclaration");
pop(); // metadata star
}
@override
+ void handleInvalidTypeArguments(Token token) {
+ debugEvent("InvalidTypeArguments");
+ pop(NullValue.TypeArguments);
+ }
+
+ @override
void handleLiteralInt(Token token) {
debugEvent("LiteralInt");
push(IntegerLiteral(int.parse(token.lexeme)));
}
@override
+ void handleLiteralList(
+ int count, Token leftBracket, Token constKeyword, Token rightBracket) {
+ debugEvent("LiteralList");
+
+ var elements = List<Object>(count);
+ popList(count, elements);
+ pop(); // type arguments
+
+ push(
+ ListLiteral(
+ leftBracket,
+ List<Expression>.from(elements),
+ rightBracket,
+ ),
+ );
+ }
+
+ @override
void handleLiteralNull(Token token) {
debugEvent("LiteralNull");
push(UnknownExpression());
}
@override
+ void handleNamedArgument(Token colon) {
+ var expression = pop();
+ var name = pop();
+ push(NamedExpression(name, colon, expression));
+ }
+
+ @override
+ void handleNamedMixinApplicationWithClause(Token withKeyword) {
+ debugEvent("NamedMixinApplicationWithClause");
+ }
+
+ @override
+ void handleNativeClause(Token nativeToken, bool hasName) {
+ debugEvent("NativeClause");
+ if (hasName) {
+ pop(); // Pop the native name which is a StringLiteral.
+ }
+ }
+
+ @override
+ void handleNativeFunctionBodyIgnored(Token nativeToken, Token semicolon) {
+ debugEvent("NativeFunctionBodyIgnored");
+ }
+
+ @override
+ void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
+ debugEvent("NativeFunctionBodySkipped");
+ push(NullValue.FunctionBody);
+ }
+
+ @override
+ void handleNonNullAssertExpression(Token bang) {
+ reportNonNullAssertExpressionNotEnabled(bang);
+ }
+
+ @override
void handleQualified(Token period) {
debugEvent("Qualified");
String suffix = pop();
@@ -590,6 +542,31 @@
}
@override
+ void handleRecoverClassHeader() {
+ pop(); // superclass
+ }
+
+ @override
+ void handleRecoverImport(Token semicolon) {
+ debugEvent("RecoverImport");
+ pop(NullValue.Prefix); // Prefix identifier
+ }
+
+ @override
+ void handleSend(Token beginToken, Token endToken) {
+ debugEvent("Send");
+
+ var arguments = pop();
+ pop(); // Type arguments
+ if (arguments != null) {
+ pop(); // Receiver
+ push(UnknownExpression());
+ } else {
+ // Property get.
+ }
+ }
+
+ @override
void handleType(Token beginToken, Token questionMark) {
debugEvent("Type");
reportErrorIfNullableType(questionMark);
@@ -599,8 +576,13 @@
}
@override
- void handleNonNullAssertExpression(Token bang) {
- reportNonNullAssertExpressionNotEnabled(bang);
+ dynamic internalProblem(Message message, int charOffset, Uri uri) {
+ throw UnsupportedError(message.message);
+ }
+
+ List popList(int n, List list) {
+ if (n == 0) return null;
+ return stack.popList(n, list, null);
}
/// Calls [pop] and creates a list with the appropriate type parameter `T`
@@ -610,11 +592,6 @@
return list != null ? List<T>.from(list) : null;
}
- List popList(int n, List list) {
- if (n == 0) return null;
- return stack.popList(n, list, null);
- }
-
void reportErrorIfNullableType(Token questionMark) {
if (questionMark != null) {
assert(optional('?', questionMark));
@@ -670,6 +647,29 @@
Token parseInvalidBlock(Token token) => skipBlock(token);
}
+/// "Mini AST" representation of a named expression.
+class NamedExpression extends Expression {
+ final String name;
+ final Token colon;
+ final Expression expression;
+
+ NamedExpression(this.name, this.colon, this.expression);
+}
+
+/// "Mini AST" representation of a named expression.
+class PrefixedIdentifier extends Expression {
+ final String prefix;
+ final Token operator;
+ final String identifier;
+
+ PrefixedIdentifier(this.prefix, this.operator, this.identifier);
+
+ @override
+ String toCode() {
+ return '$prefix.$identifier';
+ }
+}
+
/// "Mini AST" representation of a string literal.
class StringLiteral extends Expression {
final String stringValue;
diff --git a/pkg/analyzer/tool/update_id_tests.dart b/pkg/analyzer/tool/update_id_tests.dart
index 2f1b93a..4f7a5d6 100644
--- a/pkg/analyzer/tool/update_id_tests.dart
+++ b/pkg/analyzer/tool/update_id_tests.dart
@@ -4,6 +4,10 @@
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart' as id;
+main() async {
+ await id.updateAllTests(idTests);
+}
+
const List<String> idTests = <String>[
'pkg/analyzer/test/id_tests/assigned_variables_test.dart',
'pkg/analyzer/test/id_tests/constant_test.dart',
@@ -14,7 +18,3 @@
'pkg/analyzer/test/id_tests/reachability_test.dart',
'pkg/analyzer/test/id_tests/type_promotion_test.dart',
];
-
-main() async {
- await id.updateAllTests(idTests);
-}
diff --git a/pkg/analyzer_cli/tool/perf.dart b/pkg/analyzer_cli/tool/perf.dart
index c2fbccd..45131c1 100644
--- a/pkg/analyzer_cli/tool/perf.dart
+++ b/pkg/analyzer_cli/tool/perf.dart
@@ -220,7 +220,10 @@
// first converting to String?
var scanner = Scanner(
source, CharSequenceReader(contents), AnalysisErrorListener.NULL_LISTENER)
- ..configureFeatures(featureSet)
+ ..configureFeatures(
+ featureSetForOverriding: featureSet,
+ featureSet: featureSet,
+ )
..preserveComments = false;
var token = scanner.tokenize();
scanTimer.stop();
diff --git a/pkg/analyzer_plugin/doc/api.html b/pkg/analyzer_plugin/doc/api.html
index 2390ce2..a95d2c0 100644
--- a/pkg/analyzer_plugin/doc/api.html
+++ b/pkg/analyzer_plugin/doc/api.html
@@ -1306,7 +1306,7 @@
An enumeration of the kinds of folding regions.
</p>
- <dl><dt class="value">ANNOTATIONS</dt><dt class="value">CLASS_BODY</dt><dt class="value">DIRECTIVES</dt><dt class="value">DOCUMENTATION_COMMENT</dt><dt class="value">FILE_HEADER</dt><dt class="value">FUNCTION_BODY</dt><dt class="value">INVOCATION</dt><dt class="value">LITERAL</dt></dl></dd><dt class="typeDefinition"><a name="type_FoldingRegion">FoldingRegion: object</a></dt><dd>
+ <dl><dt class="value">ANNOTATIONS</dt><dt class="value">BLOCK</dt><dt class="value">CLASS_BODY</dt><dt class="value">DIRECTIVES</dt><dt class="value">DOCUMENTATION_COMMENT</dt><dt class="value">FILE_HEADER</dt><dt class="value">FUNCTION_BODY</dt><dt class="value">INVOCATION</dt><dt class="value">LITERAL</dt></dl></dd><dt class="typeDefinition"><a name="type_FoldingRegion">FoldingRegion: object</a></dt><dd>
<p>
A description of a region that can be folded.
</p>
diff --git a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
index 732bb90..1179121 100644
--- a/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
+++ b/pkg/analyzer_plugin/lib/protocol/protocol_common.dart
@@ -1894,6 +1894,7 @@
///
/// enum {
/// ANNOTATIONS
+/// BLOCK
/// CLASS_BODY
/// DIRECTIVES
/// DOCUMENTATION_COMMENT
@@ -1907,6 +1908,8 @@
class FoldingKind implements Enum {
static const FoldingKind ANNOTATIONS = FoldingKind._('ANNOTATIONS');
+ static const FoldingKind BLOCK = FoldingKind._('BLOCK');
+
static const FoldingKind CLASS_BODY = FoldingKind._('CLASS_BODY');
static const FoldingKind DIRECTIVES = FoldingKind._('DIRECTIVES');
@@ -1925,6 +1928,7 @@
/// A list containing all of the enum values that are defined.
static const List<FoldingKind> VALUES = <FoldingKind>[
ANNOTATIONS,
+ BLOCK,
CLASS_BODY,
DIRECTIVES,
DOCUMENTATION_COMMENT,
@@ -1943,6 +1947,8 @@
switch (name) {
case 'ANNOTATIONS':
return ANNOTATIONS;
+ case 'BLOCK':
+ return BLOCK;
case 'CLASS_BODY':
return CLASS_BODY;
case 'DIRECTIVES':
diff --git a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
index 8cebc74..2ca8d47 100644
--- a/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
+++ b/pkg/analyzer_plugin/test/integration/support/protocol_matchers.dart
@@ -301,6 +301,7 @@
///
/// enum {
/// ANNOTATIONS
+/// BLOCK
/// CLASS_BODY
/// DIRECTIVES
/// DOCUMENTATION_COMMENT
@@ -311,6 +312,7 @@
/// }
final Matcher isFoldingKind = MatchesEnum('FoldingKind', [
'ANNOTATIONS',
+ 'BLOCK',
'CLASS_BODY',
'DIRECTIVES',
'DOCUMENTATION_COMMENT',
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index 812c449..df9067d 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -569,6 +569,7 @@
</p>
<enum>
<value><code>ANNOTATIONS</code></value>
+ <value><code>BLOCK</code></value>
<value><code>CLASS_BODY</code></value>
<value><code>DIRECTIVES</code></value>
<value><code>DOCUMENTATION_COMMENT</code></value>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 0b8f922..6e0d183 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -351,8 +351,6 @@
ClassEntity get constSetLiteralClass;
- ClassEntity get typeVariableClass;
-
ClassEntity get jsInvocationMirrorClass;
ClassEntity get requiredSentinelClass;
@@ -381,8 +379,6 @@
/// The class for native annotations defined in dart:_js_helper.
ClassEntity get nativeAnnotationClass;
- ConstructorEntity get typeVariableConstructor;
-
FunctionEntity get assertTest;
FunctionEntity get assertThrow;
@@ -442,14 +438,6 @@
FunctionEntity get traceFromException;
- FunctionEntity get setRuntimeTypeInfo;
-
- FunctionEntity get getRuntimeTypeInfo;
-
- FunctionEntity get computeSignature;
-
- FunctionEntity get getRuntimeTypeArguments;
-
FunctionEntity get checkDeferredIsLoaded;
FunctionEntity get throwNoSuchMethod;
@@ -472,10 +460,10 @@
FunctionEntity getInstantiateFunction(int typeArgumentCount);
- FunctionEntity get instantiatedGenericFunctionType;
-
// From dart:_rti
+ FunctionEntity get setRuntimeTypeInfo;
+
FunctionEntity get findType;
FunctionEntity get instanceType;
FunctionEntity get arrayInstanceType;
@@ -1575,11 +1563,6 @@
ClassEntity get constSetLiteralClass =>
_constSetLiteralClass ??= unmodifiableSetClass;
- ClassEntity _typeVariableClass;
- @override
- ClassEntity get typeVariableClass =>
- _typeVariableClass ??= _findHelperClass('TypeVariable');
-
ClassEntity _pragmaClass;
@override
ClassEntity get pragmaClass =>
@@ -1649,11 +1632,6 @@
ClassEntity get nativeAnnotationClass =>
_nativeAnnotationClass ??= _findHelperClass('Native');
- ConstructorEntity _typeVariableConstructor;
- @override
- ConstructorEntity get typeVariableConstructor => _typeVariableConstructor ??=
- _env.lookupConstructor(typeVariableClass, '');
-
FunctionEntity _assertTest;
@override
FunctionEntity get assertTest =>
@@ -1796,22 +1774,6 @@
_findHelperFunction('getTraceFromException');
@override
- FunctionEntity get setRuntimeTypeInfo =>
- _findHelperFunction('setRuntimeTypeInfo');
-
- @override
- FunctionEntity get getRuntimeTypeInfo =>
- _findHelperFunction('getRuntimeTypeInfo');
-
- @override
- FunctionEntity get computeSignature =>
- _findHelperFunction('computeSignature');
-
- @override
- FunctionEntity get getRuntimeTypeArguments =>
- _findHelperFunction('getRuntimeTypeArguments');
-
- @override
FunctionEntity get checkDeferredIsLoaded =>
_findHelperFunction('checkDeferredIsLoaded');
@@ -1878,10 +1840,6 @@
}
@override
- FunctionEntity get instantiatedGenericFunctionType =>
- _findHelperFunction('instantiatedGenericFunctionType');
-
- @override
bool isInstantiationClass(ClassEntity cls) {
return cls.library == _jsHelperLibrary &&
cls.name != 'Instantiation' &&
@@ -1895,6 +1853,11 @@
FunctionEntity _findRtiFunction(String name) =>
_findLibraryMember(rtiLibrary, name);
+ FunctionEntity _setRuntimeTypeInfo;
+ @override
+ FunctionEntity get setRuntimeTypeInfo =>
+ _setRuntimeTypeInfo ??= _findRtiFunction('setRuntimeTypeInfo');
+
FunctionEntity _findType;
@override
FunctionEntity get findType => _findType ??= _findRtiFunction('findType');
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index a5b5f8a..d17db87 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -19,7 +19,6 @@
import 'annotations.dart';
import 'checked_mode_helpers.dart';
import 'namer.dart';
-import 'runtime_types.dart';
import 'runtime_types_codegen.dart';
import 'runtime_types_new.dart';
@@ -306,10 +305,8 @@
abstract class CodegenInputs {
CheckedModeHelpers get checkedModeHelpers;
RuntimeTypesSubstitutions get rtiSubstitutions;
- RuntimeTypesEncoder get rtiEncoder;
RecipeEncoder get rtiRecipeEncoder;
Tracer get tracer;
- RuntimeTypeTags get rtiTags;
FixedNames get fixedNames;
}
@@ -321,20 +318,14 @@
final RuntimeTypesSubstitutions rtiSubstitutions;
@override
- final RuntimeTypesEncoder rtiEncoder;
-
- @override
final RecipeEncoder rtiRecipeEncoder;
@override
final Tracer tracer;
@override
- final RuntimeTypeTags rtiTags;
-
- @override
final FixedNames fixedNames;
- CodegenInputsImpl(this.rtiSubstitutions, this.rtiEncoder,
- this.rtiRecipeEncoder, this.tracer, this.rtiTags, this.fixedNames);
+ CodegenInputsImpl(this.rtiSubstitutions, this.rtiRecipeEncoder, this.tracer,
+ this.fixedNames);
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 65ed146..6fd3844 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -109,9 +109,6 @@
BackendImpact get computeSignature {
return _computeSignature ??= new BackendImpact(globalUses: [
_commonElements.setRuntimeTypeInfo,
- _commonElements.getRuntimeTypeInfo,
- _commonElements.computeSignature,
- _commonElements.getRuntimeTypeArguments,
], otherImpacts: [
listValues
]);
@@ -454,7 +451,6 @@
BackendImpact get typeVariableExpression {
return _typeVariableExpression ??= new BackendImpact(staticUses: [
_commonElements.setRuntimeTypeInfo,
- _commonElements.getRuntimeTypeInfo,
_commonElements.createRuntimeType
], otherImpacts: [
listValues,
@@ -476,7 +472,6 @@
return _genericTypeCheck ??= new BackendImpact(staticUses: [
// TODO(johnniwinther): Investigate why this is needed.
_commonElements.setRuntimeTypeInfo,
- _commonElements.getRuntimeTypeInfo
], otherImpacts: [
listValues,
getRuntimeTypeArgument,
@@ -701,7 +696,6 @@
_commonElements.listClass
], globalUses: [
_commonElements.setRuntimeTypeInfo,
- _commonElements.getRuntimeTypeInfo
], otherImpacts: [
getRuntimeTypeArgument,
computeSignature
@@ -757,18 +751,6 @@
new BackendImpact(globalClasses: [_commonElements.closureClass]);
}
- BackendImpact _typeVariableMirror;
-
- /// Backend impact for type variables through mirrors.
- BackendImpact get typeVariableMirror {
- return _typeVariableMirror ??= new BackendImpact(staticUses: [
- _commonElements.typeVariableConstructor,
- _commonElements.createRuntimeType
- ], instantiatedClasses: [
- _commonElements.typeVariableClass
- ]);
- }
-
Map<int, BackendImpact> _genericInstantiation = <int, BackendImpact>{};
BackendImpact getGenericInstantiation(int typeArgumentCount) =>
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index c5c0da1..80b45fa 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -17,7 +17,6 @@
import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
import '../options.dart';
import 'field_analysis.dart' show JFieldAnalysis;
-import 'runtime_types.dart';
import 'runtime_types_new.dart' show RecipeEncoder;
import 'runtime_types_resolution.dart';
@@ -210,7 +209,6 @@
final JCommonElements _commonElements;
final JElementEnvironment _elementEnvironment;
final RuntimeTypesNeed _rtiNeed;
- final RuntimeTypesEncoder _rtiEncoder;
final RecipeEncoder _rtiRecipeEncoder;
final JFieldAnalysis _fieldAnalysis;
final Emitter _emitter;
@@ -225,7 +223,6 @@
this._commonElements,
this._elementEnvironment,
this._rtiNeed,
- this._rtiEncoder,
this._rtiRecipeEncoder,
this._fieldAnalysis,
this._emitter,
@@ -423,18 +420,6 @@
return rawJavaScript.replaceAll(COMMENT_RE, '');
}
- jsAst.Expression maybeAddTypeArguments(
- ConstantValue constant, InterfaceType type, jsAst.Expression value) {
- if (type is InterfaceType &&
- !_commonElements.dartTypes.treatAsRawType(type) &&
- _rtiNeed.classNeedsTypeArguments(type.element)) {
- return new jsAst.Call(
- getHelperProperty(_commonElements.setRuntimeTypeInfo),
- [value, _reifiedTypeArguments(constant, type.typeArguments)]);
- }
- return value;
- }
-
jsAst.Expression maybeAddListTypeArgumentsNewRti(
ConstantValue constant, InterfaceType type, jsAst.Expression value) {
assert(type.element == _commonElements.jsArrayClass);
@@ -446,24 +431,6 @@
return value;
}
- jsAst.Expression _reifiedTypeArguments(
- ConstantValue constant, List<DartType> typeArguments) {
- jsAst.Expression unexpected(TypeVariableType _variable) {
- TypeVariableType variable = _variable;
- throw failedAt(
- NO_LOCATION_SPANNABLE,
- "Unexpected type variable '${variable}'"
- " in constant '${constant.toDartText(_commonElements.dartTypes)}'");
- }
-
- List<jsAst.Expression> arguments = <jsAst.Expression>[];
- for (DartType argument in typeArguments) {
- arguments.add(
- _rtiEncoder.getTypeRepresentation(_emitter, argument, unexpected));
- }
- return new jsAst.ArrayInitializer(arguments);
- }
-
jsAst.Expression _reifiedTypeNewRti(DartType type) {
assert(!type.containsTypeVariables);
return TypeReference(TypeExpressionRecipe(type))..forConstant = true;
diff --git a/pkg/compiler/lib/src/js_backend/frequency_namer.dart b/pkg/compiler/lib/src/js_backend/frequency_namer.dart
index 1396e15..f929e7a 100644
--- a/pkg/compiler/lib/src/js_backend/frequency_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/frequency_namer.dart
@@ -29,9 +29,8 @@
jsAst.Name get staticsPropertyName =>
_staticsPropertyName ??= getFreshName(instanceScope, 'static');
- FrequencyBasedNamer(
- JClosedWorld closedWorld, RuntimeTypeTags rtiTags, FixedNames fixedNames)
- : super(closedWorld, rtiTags, fixedNames) {
+ FrequencyBasedNamer(JClosedWorld closedWorld, FixedNames fixedNames)
+ : super(closedWorld, fixedNames) {
fieldRegistry = new _FieldNamingRegistry(this);
}
diff --git a/pkg/compiler/lib/src/js_backend/minify_namer.dart b/pkg/compiler/lib/src/js_backend/minify_namer.dart
index 709ee76..60a2b9c 100644
--- a/pkg/compiler/lib/src/js_backend/minify_namer.dart
+++ b/pkg/compiler/lib/src/js_backend/minify_namer.dart
@@ -10,9 +10,8 @@
_MinifiedFieldNamer,
_MinifyConstructorBodyNamer,
_MinifiedOneShotInterceptorNamer {
- MinifyNamer(
- JClosedWorld closedWorld, RuntimeTypeTags rtiTags, FixedNames fixedNames)
- : super(closedWorld, rtiTags, fixedNames) {
+ MinifyNamer(JClosedWorld closedWorld, FixedNames fixedNames)
+ : super(closedWorld, fixedNames) {
reserveBackendNames();
fieldRegistry = new _FieldNamingRegistry(this);
}
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index d73344b..9b4e0ee 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -27,7 +27,6 @@
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
import '../js_backend/field_analysis.dart';
-import '../js_backend/runtime_types.dart' show RuntimeTypeTags;
import '../js_model/closure.dart';
import '../js_model/elements.dart' show JGeneratorBody;
import '../universe/call_structure.dart' show CallStructure;
@@ -432,9 +431,6 @@
r'$methodsWithOptionalArguments';
@override
- final RuntimeTypeTags rtiTags;
-
- @override
final FixedNames fixedNames;
/// The non-minifying namer's [callPrefix] with a dollar after it.
@@ -557,7 +553,7 @@
/// key into maps.
final Map<LibraryEntity, String> _libraryKeys = HashMap();
- Namer(this._closedWorld, this.rtiTags, this.fixedNames) {
+ Namer(this._closedWorld, this.fixedNames) {
_literalGetterPrefix = new StringBackedName(fixedNames.getterPrefix);
_literalSetterPrefix = new StringBackedName(fixedNames.setterPrefix);
}
@@ -2290,7 +2286,6 @@
/// Namer interface that can be used in modular code generation.
abstract class ModularNamer {
FixedNames get fixedNames;
- RuntimeTypeTags get rtiTags;
/// Returns a variable use for accessing [library].
///
@@ -2569,24 +2564,6 @@
return asName(fixedNames.operatorSignature);
case JsGetName.RTI_NAME:
return asName(fixedNames.rtiName);
- case JsGetName.FUNCTION_TYPE_TAG:
- return asName(rtiTags.functionTypeTag);
- case JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG:
- return asName(rtiTags.functionTypeGenericBoundsTag);
- case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG:
- return asName(rtiTags.functionTypeVoidReturnTag);
- case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG:
- return asName(rtiTags.functionTypeReturnTypeTag);
- case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG:
- return asName(rtiTags.functionTypeRequiredParametersTag);
- case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG:
- return asName(rtiTags.functionTypeOptionalParametersTag);
- case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG:
- return asName(rtiTags.functionTypeNamedParametersTag);
- case JsGetName.FUTURE_OR_TAG:
- return asName(rtiTags.futureOrTag);
- case JsGetName.FUTURE_OR_TYPE_ARGUMENT_TAG:
- return asName(rtiTags.futureOrTypeTag);
case JsGetName.IS_INDEXABLE_FIELD_NAME:
return operatorIs(_commonElements.jsIndexingBehaviorInterface);
case JsGetName.NULL_CLASS_TYPE_NAME:
@@ -2612,15 +2589,12 @@
class ModularNamerImpl extends ModularNamer {
final CodegenRegistry _registry;
@override
- final RuntimeTypeTags rtiTags;
- @override
final FixedNames fixedNames;
@override
final CommonElements _commonElements;
- ModularNamerImpl(
- this._registry, this._commonElements, this.rtiTags, this.fixedNames);
+ ModularNamerImpl(this._registry, this._commonElements, this.fixedNames);
@override
jsAst.Name get rtiFieldJsName {
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 8927b66..c8084d5 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -7,22 +7,14 @@
import '../common.dart';
import '../common/names.dart' show Identifiers;
import '../common_elements.dart'
- show
- CommonElements,
- ElementEnvironment,
- JCommonElements,
- JElementEnvironment;
+ show ElementEnvironment, JCommonElements, JElementEnvironment;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
-import '../js/js.dart' show js;
-import '../js_emitter/js_emitter.dart' show ModularEmitter;
import '../options.dart';
import '../universe/codegen_world_builder.dart';
import '../universe/feature.dart';
import '../world.dart';
-import 'namer.dart';
-import 'native_data.dart';
import 'runtime_types_codegen.dart';
import 'runtime_types_resolution.dart';
@@ -473,41 +465,6 @@
TrivialRuntimeTypesSubstitutions(this._closedWorld);
}
-abstract class RuntimeTypesEncoder {
- jsAst.Expression getSignatureEncoding(ModularNamer namer,
- ModularEmitter emitter, DartType type, jsAst.Expression this_);
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a function type.
- jsAst.Template get templateForIsFunctionType;
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a FutureOr type.
- jsAst.Template get templateForIsFutureOrType;
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the void type.
- jsAst.Template get templateForIsVoidType;
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the dynamic type.
- jsAst.Template get templateForIsDynamicType;
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a type argument of js-interop class.
- jsAst.Template get templateForIsJsInteropTypeArgument;
-
- /// Returns a [jsAst.Expression] representing the given [type]. Type variables
- /// are replaced by the [jsAst.Expression] returned by [onVariable].
- jsAst.Expression getTypeRepresentation(
- ModularEmitter emitter, DartType type, OnVariableCallback onVariable);
-
- jsAst.Expression getJsInteropTypeArguments(int count);
-
- /// Fixed strings used for runtime types encoding.
- RuntimeTypeTags get rtiTags;
-}
-
class _RuntimeTypesChecks implements RuntimeTypesChecks {
final RuntimeTypesSubstitutions _substitutions;
@override
@@ -823,391 +780,6 @@
return null;
}
-class RuntimeTypesEncoderImpl implements RuntimeTypesEncoder {
- final ElementEnvironment _elementEnvironment;
- final CommonElements commonElements;
- final TypeRepresentationGenerator _representationGenerator;
- final RuntimeTypesNeed _rtiNeed;
- @override
- final RuntimeTypeTags rtiTags;
-
- RuntimeTypesEncoderImpl(this.rtiTags, NativeBasicData nativeData,
- this._elementEnvironment, this.commonElements, this._rtiNeed)
- : _representationGenerator =
- new TypeRepresentationGenerator(rtiTags, nativeData);
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a function type.
- @override
- jsAst.Template get templateForIsFunctionType {
- return _representationGenerator.templateForIsFunctionType;
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a FutureOr type.
- @override
- jsAst.Template get templateForIsFutureOrType {
- return _representationGenerator.templateForIsFutureOrType;
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the void type.
- @override
- jsAst.Template get templateForIsVoidType {
- return _representationGenerator.templateForIsVoidType;
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the dynamic type.
- @override
- jsAst.Template get templateForIsDynamicType {
- return _representationGenerator.templateForIsDynamicType;
- }
-
- @override
- jsAst.Template get templateForIsJsInteropTypeArgument {
- return _representationGenerator.templateForIsJsInteropTypeArgument;
- }
-
- @override
- jsAst.Expression getTypeRepresentation(
- ModularEmitter emitter, DartType type, OnVariableCallback onVariable) {
- return _representationGenerator.getTypeRepresentation(
- emitter, type, onVariable);
- }
-
- String getTypeVariableName(TypeVariableType type) {
- String name = type.element.name;
- return name.replaceAll('#', '_');
- }
-
- jsAst.Expression getTypeEncoding(ModularEmitter emitter, DartType type,
- {bool alwaysGenerateFunction: false}) {
- ClassEntity contextClass = DartTypes.getClassContext(type);
- jsAst.Expression onVariable(TypeVariableType v) {
- return new jsAst.VariableUse(getTypeVariableName(v));
- }
-
- jsAst.Expression encoding =
- getTypeRepresentation(emitter, type, onVariable);
- if (contextClass == null && !alwaysGenerateFunction) {
- return encoding;
- } else {
- List<String> parameters = const <String>[];
- if (contextClass != null) {
- parameters = _elementEnvironment
- .getThisType(contextClass)
- .typeArguments
- .map((DartType _type) {
- TypeVariableType type = _type;
- return getTypeVariableName(type);
- }).toList();
- }
- return js('function(#) { return # }', [parameters, encoding]);
- }
- }
-
- @override
- jsAst.Expression getSignatureEncoding(ModularNamer namer,
- ModularEmitter emitter, DartType type, jsAst.Expression this_) {
- ClassEntity contextClass = DartTypes.getClassContext(type);
- jsAst.Expression encoding =
- getTypeEncoding(emitter, type, alwaysGenerateFunction: true);
- if (contextClass != null &&
- // We only generate folding using 'computeSignature' if [contextClass]
- // has reified type arguments. The 'computeSignature' function might not
- // be emitted (if it's not needed elsewhere) and the generated signature
- // will have `undefined` as its type variables in any case.
- //
- // This is needed specifically for --lax-runtime-type-to-string which
- // may require a signature on a method that uses class type variables
- // while at the same time not needing type arguments on the class.
- _rtiNeed.classNeedsTypeArguments(contextClass)) {
- jsAst.Name contextName = namer.className(contextClass);
- return js('function () { return #(#, #, #); }', [
- emitter.staticFunctionAccess(commonElements.computeSignature),
- encoding,
- this_,
- js.quoteName(contextName)
- ]);
- } else {
- return encoding;
- }
- }
-
- @override
- jsAst.Expression getJsInteropTypeArguments(int count) {
- return _representationGenerator.getJsInteropTypeArguments(count);
- }
-}
-
-/// Fixed strings used for runtime types encoding.
-// TODO(johnniwinther): Use different names for minified code?
-class RuntimeTypeTags {
- const RuntimeTypeTags();
-
- String get functionTypeTag => r'func';
-
- String get functionTypeVoidReturnTag => r'v';
-
- String get functionTypeReturnTypeTag => r'ret';
-
- String get functionTypeRequiredParametersTag => r'args';
-
- String get functionTypeOptionalParametersTag => r'opt';
-
- String get functionTypeNamedParametersTag => r'named';
-
- String get functionTypeGenericBoundsTag => r'bounds';
-
- String get futureOrTag => r'futureOr';
-
- String get futureOrTypeTag => r'type';
-}
-
-class TypeRepresentationGenerator
- implements DartTypeVisitor<jsAst.Expression, ModularEmitter> {
- final RuntimeTypeTags _rtiTags;
- final NativeBasicData _nativeData;
-
- OnVariableCallback onVariable;
- List<FunctionTypeVariable> functionTypeVariables = <FunctionTypeVariable>[];
-
- TypeRepresentationGenerator(this._rtiTags, this._nativeData);
-
- /// Creates a type representation for [type]. [onVariable] is called to
- /// provide the type representation for type variables.
- jsAst.Expression getTypeRepresentation(
- ModularEmitter emitter, DartType type, OnVariableCallback onVariable) {
- this.onVariable = onVariable;
- jsAst.Expression representation = visit(type, emitter);
- this.onVariable = null;
- assert(functionTypeVariables.isEmpty);
- return representation;
- }
-
- jsAst.Expression getJavaScriptClassName(
- Entity element, ModularEmitter emitter) {
- return emitter.typeAccess(element);
- }
-
- jsAst.Expression getDynamicValue() => js('null');
-
- jsAst.Expression getVoidValue() => js('-1');
-
- jsAst.Expression getJsInteropTypeArgumentValue() => js('-2');
-
- @override
- jsAst.Expression visit(DartType type, ModularEmitter emitter) =>
- type.accept(this, emitter);
-
- @override
- jsAst.Expression visitTypeVariableType(
- TypeVariableType type, ModularEmitter emitter) {
- return onVariable(type);
- }
-
- @override
- jsAst.Expression visitLegacyType(LegacyType type, ModularEmitter emitter) {
- throw UnsupportedError('Legacy RTI does not support legacy types');
- }
-
- @override
- jsAst.Expression visitNullableType(
- NullableType type, ModularEmitter emitter) {
- throw UnsupportedError('Legacy RTI does not support nullable types');
- }
-
- @override
- jsAst.Expression visitNeverType(NeverType type, ModularEmitter emitter) {
- throw UnsupportedError('Legacy RTI does not support the Never type');
- }
-
- @override
- jsAst.Expression visitFunctionTypeVariable(
- FunctionTypeVariable type, ModularEmitter emitter) {
- int position = functionTypeVariables.indexOf(type);
- assert(position >= 0);
- return js.number(functionTypeVariables.length - position - 1);
- }
-
- @override
- jsAst.Expression visitDynamicType(DynamicType type, ModularEmitter emitter) {
- return getDynamicValue();
- }
-
- @override
- jsAst.Expression visitErasedType(ErasedType type, ModularEmitter emitter) {
- throw UnsupportedError('Legacy RTI does not support erased types');
- }
-
- @override
- jsAst.Expression visitAnyType(AnyType type, ModularEmitter emitter) =>
- getJsInteropTypeArgumentValue();
-
- jsAst.Expression getJsInteropTypeArguments(int count,
- {jsAst.Expression name}) {
- List<jsAst.Expression> elements = <jsAst.Expression>[];
- if (name != null) {
- elements.add(name);
- }
- for (int i = 0; i < count; i++) {
- elements.add(getJsInteropTypeArgumentValue());
- }
- return new jsAst.ArrayInitializer(elements);
- }
-
- @override
- jsAst.Expression visitInterfaceType(
- InterfaceType type, ModularEmitter emitter) {
- jsAst.Expression name = getJavaScriptClassName(type.element, emitter);
- jsAst.Expression result;
- if (type.typeArguments.isEmpty) {
- result = name;
- } else {
- // Visit all type arguments. This is done even for jsinterop classes to
- // enforce the invariant that [onVariable] is called for each type
- // variable in the type.
- result = visitList(type.typeArguments, emitter, head: name);
- if (_nativeData.isJsInteropClass(type.element)) {
- // Replace type arguments of generic jsinterop classes with 'any' type.
- result =
- getJsInteropTypeArguments(type.typeArguments.length, name: name);
- }
- }
- return result;
- }
-
- jsAst.Expression visitList(List<DartType> types, ModularEmitter emitter,
- {jsAst.Expression head}) {
- List<jsAst.Expression> elements = <jsAst.Expression>[];
- if (head != null) {
- elements.add(head);
- }
- for (DartType type in types) {
- jsAst.Expression element = visit(type, emitter);
- if (element is jsAst.LiteralNull) {
- elements.add(new jsAst.ArrayHole());
- } else {
- elements.add(element);
- }
- }
- return new jsAst.ArrayInitializer(elements);
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a function type.
- jsAst.Template get templateForIsFunctionType {
- return jsAst.js.expressionTemplateFor("'${_rtiTags.functionTypeTag}' in #");
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is a FutureOr type.
- jsAst.Template get templateForIsFutureOrType {
- return jsAst.js.expressionTemplateFor("'${_rtiTags.futureOrTag}' in #");
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the void type.
- jsAst.Template get templateForIsVoidType {
- return jsAst.js.expressionTemplateFor("# === -1");
- }
-
- /// Returns the JavaScript template to determine at runtime if a type object
- /// is the dynamic type.
- jsAst.Template get templateForIsDynamicType {
- return jsAst.js.expressionTemplateFor("# == null");
- }
-
- jsAst.Template get templateForIsJsInteropTypeArgument {
- return jsAst.js.expressionTemplateFor("# === -2");
- }
-
- @override
- jsAst.Expression visitFunctionType(
- FunctionType type, ModularEmitter emitter) {
- List<jsAst.Property> properties = <jsAst.Property>[];
-
- void addProperty(String name, jsAst.Expression value) {
- properties.add(new jsAst.Property(js.string(name), value));
- }
-
- // Type representations for functions have a property which is a tag marking
- // them as function types. The value is not used, so '1' is just a dummy.
- addProperty(_rtiTags.functionTypeTag, js.number(1));
-
- if (type.typeVariables.isNotEmpty) {
- // Generic function types have type parameters which are reduced to de
- // Bruijn indexes.
- for (FunctionTypeVariable variable in type.typeVariables.reversed) {
- functionTypeVariables.add(variable);
- }
- // TODO(sra): This emits `P.Object` for the common unbounded case. We
- // could replace the Object bounds with an array hole for a compact `[,,]`
- // representation.
- addProperty(_rtiTags.functionTypeGenericBoundsTag,
- visitList(type.typeVariables.map((v) => v.bound).toList(), emitter));
- }
-
- if (type.returnType is! DynamicType) {
- addProperty(
- _rtiTags.functionTypeReturnTypeTag, visit(type.returnType, emitter));
- }
- if (!type.parameterTypes.isEmpty) {
- addProperty(_rtiTags.functionTypeRequiredParametersTag,
- visitList(type.parameterTypes, emitter));
- }
- if (!type.optionalParameterTypes.isEmpty) {
- addProperty(_rtiTags.functionTypeOptionalParametersTag,
- visitList(type.optionalParameterTypes, emitter));
- }
- if (!type.namedParameterTypes.isEmpty) {
- List<jsAst.Property> namedArguments = <jsAst.Property>[];
- List<String> names = type.namedParameters;
- List<DartType> types = type.namedParameterTypes;
- assert(types.length == names.length);
- for (int index = 0; index < types.length; index++) {
- jsAst.Expression name = js.string(names[index]);
- namedArguments
- .add(new jsAst.Property(name, visit(types[index], emitter)));
- }
- addProperty(_rtiTags.functionTypeNamedParametersTag,
- new jsAst.ObjectInitializer(namedArguments));
- }
-
- // Exit generic function scope.
- if (type.typeVariables.isNotEmpty) {
- functionTypeVariables.length -= type.typeVariables.length;
- }
-
- return new jsAst.ObjectInitializer(properties);
- }
-
- @override
- jsAst.Expression visitVoidType(VoidType type, ModularEmitter emitter) {
- return getVoidValue();
- }
-
- @override
- jsAst.Expression visitFutureOrType(
- FutureOrType type, ModularEmitter emitter) {
- List<jsAst.Property> properties = <jsAst.Property>[];
-
- void addProperty(String name, jsAst.Expression value) {
- properties.add(new jsAst.Property(js.string(name), value));
- }
-
- // Type representations for FutureOr have a property which is a tag marking
- // them as FutureOr types. The value is not used, so '1' is just a dummy.
- addProperty(_rtiTags.futureOrTag, js.number(1));
- if (type.typeArgument is! DynamicType) {
- addProperty(_rtiTags.futureOrTypeTag, visit(type.typeArgument, emitter));
- }
-
- return new jsAst.ObjectInitializer(properties);
- }
-}
-
class TypeCheckMapping implements TypeChecks {
final Map<ClassEntity, ClassChecks> map = new Map<ClassEntity, ClassChecks>();
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
index edbbc71..49e6c25 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -6,8 +6,7 @@
import 'package:js_runtime/shared/recipe_syntax.dart';
-import '../common_elements.dart'
- show CommonElements, JCommonElements, JElementEnvironment;
+import '../common_elements.dart' show CommonElements, JCommonElements;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
@@ -19,7 +18,6 @@
import 'namer.dart';
import 'native_data.dart';
import 'runtime_types_codegen.dart' show RuntimeTypesSubstitutions;
-import 'runtime_types_resolution.dart' show RuntimeTypesNeed;
class RecipeEncoding {
final jsAst.Literal recipe;
@@ -43,24 +41,16 @@
/// assumed to never be erased.
jsAst.Literal encodeMetadataRecipe(ModularEmitter emitter,
InterfaceType declaringType, DartType supertypeArgument);
-
- // TODO(sra): Still need a $signature function when the function type is a
- // function of closed type variables. See if the $signature method can always
- // be generated through SSA in those cases.
- jsAst.Expression encodeSignature(ModularNamer namer, ModularEmitter emitter,
- DartType type, jsAst.Expression this_);
}
class RecipeEncoderImpl implements RecipeEncoder {
final JClosedWorld _closedWorld;
final RuntimeTypesSubstitutions _rtiSubstitutions;
final NativeBasicData _nativeData;
- final JElementEnvironment _elementEnvironment;
final JCommonElements commonElements;
- final RuntimeTypesNeed _rtiNeed;
RecipeEncoderImpl(this._closedWorld, this._rtiSubstitutions, this._nativeData,
- this._elementEnvironment, this.commonElements, this._rtiNeed);
+ this.commonElements);
@override
RecipeEncoding encodeRecipe(ModularEmitter emitter,
@@ -85,17 +75,6 @@
.run()
.recipe;
}
-
- @override
- jsAst.Expression encodeSignature(ModularNamer namer, ModularEmitter emitter,
- DartType type, jsAst.Expression this_) {
- // TODO(sra): These inputs (referenced to quell lints) are used by the old
- // rti signature generator. Do we need them?
- _rtiNeed;
- commonElements;
- _elementEnvironment;
- throw UnimplementedError('RecipeEncoderImpl.getSignatureEncoding');
- }
}
class _RecipeGenerator implements DartTypeVisitor<void, void> {
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index d872941..b412bd7 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -92,7 +92,6 @@
_compiler.dumpInfoTask,
namer,
closedWorld,
- codegen.rtiEncoder,
codegen.rtiRecipeEncoder,
_nativeEmitter,
_backendStrategy.sourceInformationStrategy,
@@ -119,7 +118,7 @@
measureSubtask('finalize rti', () {
_finalizeRti(codegenInputs, codegenWorld);
});
- ProgramBuilder programBuilder = new ProgramBuilder(
+ ProgramBuilder programBuilder = ProgramBuilder(
_compiler.options,
_compiler.reporter,
closedWorld.elementEnvironment,
@@ -132,7 +131,6 @@
closedWorld.rtiNeed,
closedWorld.interceptorData,
typeTestRegistry.rtiChecks,
- codegenInputs.rtiEncoder,
codegenInputs.rtiRecipeEncoder,
codegenWorld.oneShotInterceptorData,
_backendStrategy.customElementsCodegenAnalysis,
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index a536bca..1016f9a 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -14,8 +14,6 @@
import '../js_backend/namer.dart' show Namer;
import '../js_backend/native_data.dart';
import '../js_backend/interceptor_data.dart';
-import '../js_backend/runtime_types.dart';
-import '../js_backend/runtime_types_new.dart' show RecipeEncoder;
import '../js_backend/type_reference.dart' show TypeReference;
import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
import '../universe/call_structure.dart' show CallStructure;
@@ -35,8 +33,6 @@
final Emitter _emitter;
final NativeEmitter _nativeEmitter;
final Namer _namer;
- final RuntimeTypesEncoder _rtiEncoder;
- final RecipeEncoder _rtiRecipeEncoder;
final NativeData _nativeData;
final InterceptorData _interceptorData;
final CodegenWorld _codegenWorld;
@@ -47,8 +43,6 @@
this._emitter,
this._nativeEmitter,
this._namer,
- this._rtiEncoder,
- this._rtiRecipeEncoder,
this._nativeData,
this._interceptorData,
this._codegenWorld,
@@ -180,18 +174,9 @@
if (selector.typeArgumentCount == 0) {
DartType defaultType = _closedWorld.elementEnvironment
.getTypeVariableDefaultType(typeVariable.element);
- if (_rtiRecipeEncoder != null) {
- defaultType = _eraseTypeVariablesToAny(defaultType);
- targetArguments[count++] =
- TypeReference(TypeExpressionRecipe(defaultType));
- } else {
- targetArguments[count++] = _rtiEncoder.getTypeRepresentation(
- _emitter, defaultType, (_) => _emitter.constantReference(
- // TODO(33422): Support type variables in default
- // types. Temporarily using the "any" type (encoded as -2) to
- // avoid failing on bounds checks.
- new IntConstantValue(new BigInt.from(-2))));
- }
+ defaultType = _eraseTypeVariablesToAny(defaultType);
+ targetArguments[count++] =
+ TypeReference(TypeExpressionRecipe(defaultType));
} else {
String jsName = '\$${typeVariable.element.name}';
stubParameters[parameterIndex++] = new jsAst.Parameter(jsName);
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index f1dde90..a54322d 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -26,8 +26,7 @@
import '../../js_backend/interceptor_data.dart';
import '../../js_backend/namer.dart' show Namer, StringBackedName;
import '../../js_backend/native_data.dart';
-import '../../js_backend/runtime_types.dart'
- show RuntimeTypesChecks, RuntimeTypesEncoder;
+import '../../js_backend/runtime_types.dart' show RuntimeTypesChecks;
import '../../js_backend/runtime_types_new.dart'
show RecipeEncoder, RecipeEncoding;
import '../../js_backend/runtime_types_new.dart' as newRti;
@@ -75,7 +74,6 @@
final RuntimeTypesNeed _rtiNeed;
final InterceptorData _interceptorData;
final RuntimeTypesChecks _rtiChecks;
- final RuntimeTypesEncoder _rtiEncoder;
final RecipeEncoder _rtiRecipeEncoder;
final OneShotInterceptorData _oneShotInterceptorData;
final CustomElementsCodegenAnalysis _customElementsCodegenAnalysis;
@@ -123,7 +121,6 @@
this._rtiNeed,
this._interceptorData,
this._rtiChecks,
- this._rtiEncoder,
this._rtiRecipeEncoder,
this._oneShotInterceptorData,
this._customElementsCodegenAnalysis,
@@ -646,12 +643,7 @@
_task.emitter, _commonElements, _namer, _codegenWorld, _closedWorld,
enableMinification: _options.enableMinification);
RuntimeTypeGenerator runtimeTypeGenerator = new RuntimeTypeGenerator(
- _commonElements,
- _outputUnitData,
- _task,
- _namer,
- _rtiChecks,
- _rtiEncoder);
+ _commonElements, _outputUnitData, _task, _namer, _rtiChecks);
void visitInstanceMember(MemberEntity member) {
if (!member.isAbstract && !member.isField) {
@@ -1014,12 +1006,10 @@
FunctionEntity element, bool canTearOff, bool canBeApplied) {
if (!_methodNeedsStubs(element)) return const <ParameterStubMethod>[];
- ParameterStubGenerator generator = new ParameterStubGenerator(
+ ParameterStubGenerator generator = ParameterStubGenerator(
_task.emitter,
_task.nativeEmitter,
_namer,
- _rtiEncoder,
- _rtiRecipeEncoder,
_nativeData,
_interceptorData,
_codegenWorld,
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index 5af0868..1da9bec 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -10,10 +10,8 @@
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
-import '../js_backend/js_interop_analysis.dart' as jsInteropAnalysis;
import '../js_backend/namer.dart' show Namer;
-import '../js_backend/runtime_types.dart'
- show RuntimeTypesChecks, RuntimeTypesEncoder;
+import '../js_backend/runtime_types.dart' show RuntimeTypesChecks;
import '../js_backend/runtime_types_codegen.dart'
show ClassChecks, ClassFunctionType, TypeCheck;
import '../js_emitter/sorter.dart';
@@ -85,16 +83,14 @@
}
class RuntimeTypeGenerator {
- final CommonElements _commonElements;
final OutputUnitData _outputUnitData;
final CodeEmitterTask emitterTask;
final Namer _namer;
final RuntimeTypesChecks _rtiChecks;
- final RuntimeTypesEncoder _rtiEncoder;
final _TypeContainedInOutputUnitVisitor _outputUnitVisitor;
- RuntimeTypeGenerator(this._commonElements, this._outputUnitData,
- this.emitterTask, this._namer, this._rtiChecks, this._rtiEncoder)
+ RuntimeTypeGenerator(CommonElements _commonElements, this._outputUnitData,
+ this.emitterTask, this._namer, this._rtiChecks)
: _outputUnitVisitor = new _TypeContainedInOutputUnitVisitor(
_commonElements, _outputUnitData);
@@ -185,18 +181,6 @@
_generateIsTestsOn(
classElement, generateFunctionTypeSignature, generateTypeCheck);
- if (classElement == _commonElements.jsJavaScriptFunctionClass) {
- var type =
- jsInteropAnalysis.buildJsFunctionType(_commonElements.dartTypes);
- if (type != null) {
- jsAst.Expression thisAccess = new jsAst.This();
- jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding(
- _namer, emitterTask.emitter, type, thisAccess);
- jsAst.Name operatorSignature =
- _namer.asName(_namer.fixedNames.operatorSignature);
- result.addSignature(classElement, operatorSignature, encoding);
- }
- }
return result;
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
index 800b883..b2b924b 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/emitter.dart
@@ -16,7 +16,6 @@
import '../../js/js.dart' as js;
import '../../js_backend/constant_emitter.dart';
import '../../js_backend/namer.dart';
-import '../../js_backend/runtime_types.dart';
import '../../js_backend/runtime_types_new.dart' show RecipeEncoder;
import '../../options.dart';
import '../../universe/codegen_world_builder.dart' show CodegenWorld;
@@ -149,7 +148,6 @@
class EmitterImpl extends ModularEmitterBase implements Emitter {
final DiagnosticReporter _reporter;
final JClosedWorld _closedWorld;
- final RuntimeTypesEncoder _rtiEncoder;
final RecipeEncoder _rtiRecipeEncoder;
final CompilerTask _task;
ModelEmitter _emitter;
@@ -165,7 +163,6 @@
DumpInfoTask dumpInfoTask,
Namer namer,
this._closedWorld,
- this._rtiEncoder,
this._rtiRecipeEncoder,
this._nativeEmitter,
SourceInformationStrategy sourceInformationStrategy,
@@ -183,7 +180,6 @@
this,
_nativeEmitter,
sourceInformationStrategy,
- _rtiEncoder,
_rtiRecipeEncoder,
shouldGenerateSourceMap);
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 5de338a..2e5779b 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -621,9 +621,7 @@
? TrivialRuntimeTypesSubstitutions(_closedWorld)
: RuntimeTypesImpl(_closedWorld),
_closedWorld.nativeData,
- _closedWorld.elementEnvironment,
- _closedWorld.commonElements,
- _closedWorld.rtiNeed);
+ _closedWorld.commonElements);
_rulesetEncoder =
RulesetEncoder(_closedWorld.dartTypes, _emitter, _recipeEncoder);
}
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index cf04b75..33479d9 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -113,7 +113,6 @@
this._emitter,
this._nativeEmitter,
this._sourceInformationStrategy,
- RuntimeTypesEncoder rtiEncoder,
RecipeEncoder rtiRecipeEncoder,
this._shouldGenerateSourceMap)
: _constantOrdering = new ConstantOrdering(_closedWorld.sorter) {
@@ -122,7 +121,6 @@
_closedWorld.commonElements,
_closedWorld.elementEnvironment,
_closedWorld.rtiNeed,
- rtiEncoder,
rtiRecipeEncoder,
_closedWorld.fieldAnalysis,
_emitter,
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index ecd134b..bd11e25 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -193,19 +193,12 @@
CodegenInputs onCodegenStart(
GlobalTypeInferenceResults globalTypeInferenceResults) {
JClosedWorld closedWorld = globalTypeInferenceResults.closedWorld;
- RuntimeTypeTags rtiTags = const RuntimeTypeTags();
FixedNames fixedNames = _compiler.options.enableMinification
? const MinifiedFixedNames()
: const FixedNames();
Tracer tracer =
new Tracer(closedWorld, _compiler.options, _compiler.outputProvider);
- RuntimeTypesEncoder rtiEncoder = new RuntimeTypesEncoderImpl(
- rtiTags,
- closedWorld.nativeData,
- closedWorld.elementEnvironment,
- closedWorld.commonElements,
- closedWorld.rtiNeed);
RuntimeTypesSubstitutions rtiSubstitutions;
if (_compiler.options.disableRtiOptimization) {
@@ -218,16 +211,11 @@
rtiSubstitutions = runtimeTypesImpl;
}
- RecipeEncoder rtiRecipeEncoder = new RecipeEncoderImpl(
- closedWorld,
- rtiSubstitutions,
- closedWorld.nativeData,
- closedWorld.elementEnvironment,
- closedWorld.commonElements,
- closedWorld.rtiNeed);
+ RecipeEncoder rtiRecipeEncoder = new RecipeEncoderImpl(closedWorld,
+ rtiSubstitutions, closedWorld.nativeData, closedWorld.commonElements);
- CodegenInputs codegen = new CodegenInputsImpl(rtiSubstitutions, rtiEncoder,
- rtiRecipeEncoder, tracer, rtiTags, fixedNames);
+ CodegenInputs codegen = new CodegenInputsImpl(
+ rtiSubstitutions, rtiRecipeEncoder, tracer, fixedNames);
functionCompiler.initialize(globalTypeInferenceResults, codegen);
return codegen;
@@ -287,13 +275,12 @@
CodegenInputs codegen,
OneShotInterceptorData oneShotInterceptorData) {
JClosedWorld closedWorld = globalTypeInferenceResults.closedWorld;
- RuntimeTypeTags rtiTags = codegen.rtiTags;
FixedNames fixedNames = codegen.fixedNames;
_namer = _compiler.options.enableMinification
? _compiler.options.useFrequencyNamer
- ? new FrequencyBasedNamer(closedWorld, rtiTags, fixedNames)
- : new MinifyNamer(closedWorld, rtiTags, fixedNames)
- : new Namer(closedWorld, rtiTags, fixedNames);
+ ? new FrequencyBasedNamer(closedWorld, fixedNames)
+ : new MinifyNamer(closedWorld, fixedNames)
+ : new Namer(closedWorld, fixedNames);
_nativeCodegenEnqueuer = new NativeCodegenEnqueuer(
_compiler.options,
closedWorld.elementEnvironment,
@@ -507,7 +494,6 @@
namer,
emitter,
codegen.tracer,
- codegen.rtiEncoder,
_sourceInformationStrategy,
_inlineCache,
_inlineDataCache);
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 4cd396f..801f78f 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -32,7 +32,6 @@
import '../js_backend/inferred_data.dart';
import '../js_backend/namer.dart' show ModularNamer;
import '../js_backend/native_data.dart';
-import '../js_backend/runtime_types.dart';
import '../js_backend/runtime_types_resolution.dart';
import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
import '../js_model/locals.dart' show JumpVisitor;
@@ -121,7 +120,6 @@
final CodegenRegistry registry;
final ClosureData _closureDataLookup;
final Tracer _tracer;
- final RuntimeTypesEncoder _rtiEncoder;
/// A stack of [InterfaceType]s that have been seen during inlining of
/// factory constructors. These types are preserved in [HInvokeStatic]s and
@@ -171,7 +169,6 @@
this._namer,
this._emitter,
this._tracer,
- this._rtiEncoder,
this._sourceInformationStrategy,
this._inlineCache,
this._inlineDataCache)
@@ -4502,36 +4499,12 @@
int isPrefixLength = _namer.fixedNames.operatorIsPrefix.length;
return js.js.expressionTemplateFor('#.substring($isPrefixLength)');
- case JsBuiltin.isFunctionType:
- return _rtiEncoder.templateForIsFunctionType;
-
- case JsBuiltin.isFutureOrType:
- return _rtiEncoder.templateForIsFutureOrType;
-
- case JsBuiltin.isVoidType:
- return _rtiEncoder.templateForIsVoidType;
-
- case JsBuiltin.isDynamicType:
- return _rtiEncoder.templateForIsDynamicType;
-
- case JsBuiltin.isJsInteropTypeArgument:
- return _rtiEncoder.templateForIsJsInteropTypeArgument;
-
case JsBuiltin.rawRtiToJsConstructorName:
return js.js.expressionTemplateFor("#.name");
case JsBuiltin.rawRuntimeType:
return js.js.expressionTemplateFor("#.constructor");
- case JsBuiltin.isSubtype:
- // TODO(floitsch): move this closer to where is-check properties are
- // built.
- String isPrefix = _namer.fixedNames.operatorIsPrefix;
- return js.js.expressionTemplateFor("('$isPrefix' + #) in #.prototype");
-
- case JsBuiltin.isGivenTypeRti:
- return js.js.expressionTemplateFor('#.name === #');
-
case JsBuiltin.getMetadata:
String metadataAccess =
_emitter.generateEmbeddedGlobalAccessString(METADATA);
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 9b643ec..9fd8e25 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -68,8 +68,8 @@
JClosedWorld closedWorld = _globalInferenceResults.closedWorld;
CodegenRegistry registry =
new CodegenRegistry(closedWorld.elementEnvironment, member);
- ModularNamer namer = new ModularNamerImpl(registry,
- closedWorld.commonElements, _codegen.rtiTags, _codegen.fixedNames);
+ ModularNamer namer = new ModularNamerImpl(
+ registry, closedWorld.commonElements, _codegen.fixedNames);
ModularEmitter emitter = new ModularEmitterImpl(namer, registry, _options);
if (member.isConstructor &&
member.enclosingClass == closedWorld.commonElements.jsNullClass) {
diff --git a/pkg/compiler/test/analyses/api_allowed.json b/pkg/compiler/test/analyses/api_allowed.json
index b0b2932..2e7b5b0 100644
--- a/pkg/compiler/test/analyses/api_allowed.json
+++ b/pkg/compiler/test/analyses/api_allowed.json
@@ -41,10 +41,6 @@
"Dynamic invocation of 'containsKey'.": 1,
"Dynamic access of '_js_helper::_first'.": 2
},
- "org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_rti.dart": {
- "Dynamic invocation of '<'.": 1,
- "Dynamic invocation of '-'.": 1
- },
"org-dartlang-sdk:///lib/_internal/js_runtime/lib/native_helper.dart": {
"Dynamic access of 'length'.": 2,
"Dynamic invocation of '[]'.": 1
@@ -225,4 +221,4 @@
"Dynamic access of 'port'.": 1,
"Dynamic invocation of 'dart._http::_toJSON'.": 1
}
-}
+}
\ No newline at end of file
diff --git a/pkg/compiler/test/analyses/api_allowed_nnbd.json b/pkg/compiler/test/analyses/api_allowed_nnbd.json
index e303631..2804f45 100644
--- a/pkg/compiler/test/analyses/api_allowed_nnbd.json
+++ b/pkg/compiler/test/analyses/api_allowed_nnbd.json
@@ -41,10 +41,6 @@
"Dynamic invocation of 'containsKey'.": 1,
"Dynamic access of '_js_helper::_first'.": 2
},
- "org-dartlang-sdk:///lib/_internal/js_runtime/lib/js_rti.dart": {
- "Dynamic invocation of '<'.": 1,
- "Dynamic invocation of '-'.": 1
- },
"org-dartlang-sdk:///lib/_internal/js_runtime/lib/native_helper.dart": {
"Dynamic access of 'length'.": 2,
"Dynamic invocation of '[]'.": 1
@@ -202,4 +198,4 @@
"org-dartlang-sdk:///lib/_http/websocket_impl.dart": {
"Dynamic invocation of 'dart._http::_toJSON'.": 1
}
-}
+}
\ No newline at end of file
diff --git a/pkg/compiler/test/impact/data/async.dart b/pkg/compiler/test/impact/data/async.dart
index 70738c5..e82aad3 100644
--- a/pkg/compiler/test/impact/data/async.dart
+++ b/pkg/compiler/test/impact/data/async.dart
@@ -72,10 +72,7 @@
_IterationMarker.uncaughtError(1),
_IterationMarker.yieldStar(1),
_makeSyncStarIterable<Null>(1),
- computeSignature(3),
def:local,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -99,10 +96,7 @@
_asyncStartSync(2),
_makeAsyncAwaitCompleter<Null>(0),
_wrapJsFunctionForAsync(1),
- computeSignature(3),
def:local,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -126,10 +120,7 @@
_makeAsyncStarStreamController<Null>(1),
_streamOfController(1),
_wrapJsFunctionForAsync(1),
- computeSignature(3),
def:local,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -150,10 +141,7 @@
_IterationMarker.uncaughtError(1),
_IterationMarker.yieldStar(1),
_makeSyncStarIterable<Null>(1),
- computeSignature(3),
def:<anonymous>,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -176,10 +164,7 @@
_asyncStartSync(2),
_makeAsyncAwaitCompleter<Null>(0),
_wrapJsFunctionForAsync(1),
- computeSignature(3),
def:<anonymous>,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -202,10 +187,7 @@
_makeAsyncStarStreamController<Null>(1),
_streamOfController(1),
_wrapJsFunctionForAsync(1),
- computeSignature(3),
def:<anonymous>,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
diff --git a/pkg/compiler/test/impact/data/classes.dart b/pkg/compiler/test/impact/data/classes.dart
index 067ac76..361a20b 100644
--- a/pkg/compiler/test/impact/data/classes.dart
+++ b/pkg/compiler/test/impact/data/classes.dart
@@ -269,7 +269,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -319,7 +318,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -399,7 +397,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -450,7 +447,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -565,7 +561,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -617,7 +612,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/constants/lib.dart b/pkg/compiler/test/impact/data/constants/lib.dart
index 6f53ca7..3610170 100644
--- a/pkg/compiler/test/impact/data/constants/lib.dart
+++ b/pkg/compiler/test/impact/data/constants/lib.dart
@@ -77,7 +77,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -127,7 +126,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/expressions.dart b/pkg/compiler/test/impact/data/expressions.dart
index e4ee98b..6b3d103 100644
--- a/pkg/compiler/test/impact/data/expressions.dart
+++ b/pkg/compiler/test/impact/data/expressions.dart
@@ -225,7 +225,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -275,7 +274,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -579,7 +577,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -629,7 +626,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -848,7 +844,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -898,7 +893,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -947,7 +941,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -997,7 +990,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1046,7 +1038,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1096,7 +1087,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1145,7 +1135,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1195,7 +1184,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1244,7 +1232,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1294,7 +1281,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1429,7 +1415,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2),
throwRuntimeError(1)],
@@ -1479,7 +1464,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2),
throwRuntimeError(1)],
diff --git a/pkg/compiler/test/impact/data/extract_type_arguments.dart b/pkg/compiler/test/impact/data/extract_type_arguments.dart
index ad21686..2ef7d2c 100644
--- a/pkg/compiler/test/impact/data/extract_type_arguments.dart
+++ b/pkg/compiler/test/impact/data/extract_type_arguments.dart
@@ -49,7 +49,6 @@
_isTop(1),
extractTypeArguments<A<dynamic>>(2),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -102,7 +101,6 @@
_isTop(1),
extractTypeArguments<A<dynamic>*>(2),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -154,7 +152,6 @@
_isTop(1),
extractTypeArguments<B<dynamic,dynamic>>(2),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -207,7 +204,6 @@
_isTop(1),
extractTypeArguments<B<dynamic,dynamic>*>(2),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/initializers.dart b/pkg/compiler/test/impact/data/initializers.dart
index 79bbcee..07f38b6 100644
--- a/pkg/compiler/test/impact/data/initializers.dart
+++ b/pkg/compiler/test/impact/data/initializers.dart
@@ -478,7 +478,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -528,7 +527,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/injected_cast.dart b/pkg/compiler/test/impact/data/injected_cast.dart
index 8a24d2c..4594379 100644
--- a/pkg/compiler/test/impact/data/injected_cast.dart
+++ b/pkg/compiler/test/impact/data/injected_cast.dart
@@ -227,7 +227,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -277,7 +276,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -328,7 +326,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -379,7 +376,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -805,7 +801,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -860,7 +855,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -916,7 +910,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -971,7 +964,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1029,7 +1021,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1084,7 +1075,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1140,7 +1130,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1195,7 +1184,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1353,7 +1341,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1403,7 +1390,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1452,7 +1438,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1502,7 +1487,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1556,7 +1540,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1609,7 +1592,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/invokes.dart b/pkg/compiler/test/impact/data/invokes.dart
index e2ab209..ba65ac4 100644
--- a/pkg/compiler/test/impact/data/invokes.dart
+++ b/pkg/compiler/test/impact/data/invokes.dart
@@ -322,7 +322,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -374,7 +373,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -487,7 +485,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -536,7 +533,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -584,7 +580,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -633,7 +628,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -681,7 +675,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -730,7 +723,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -778,7 +770,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -827,7 +818,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1284,7 +1274,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1334,7 +1323,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1454,10 +1442,7 @@
/*member: testLocalFunction:
static=[
- computeSignature(3),
def:localFunction,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[
inst:Function,
@@ -1504,11 +1489,8 @@
_isObject(1),
_isString(1),
_isTop(1),
- computeSignature(3),
def:localFunction,
findType(1),
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1558,11 +1540,8 @@
_isObject(1),
_isString(1),
_isTop(1),
- computeSignature(3),
def:localFunction,
findType(1),
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -1584,10 +1563,8 @@
/*member: testLocalFunctionInvoke:
dynamic=[call(0)],
- static=[computeSignature(3),
+ static=[
def:localFunction,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
localFunction(0),
setRuntimeTypeInfo(2)],
type=[inst:Function,
@@ -1601,10 +1578,8 @@
localFunction();
}
-/*member: testLocalFunctionGet:static=[computeSignature(3),
+/*member: testLocalFunctionGet:static=[
def:localFunction,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[inst:Function,
inst:JSArray<dynamic>,
@@ -1617,10 +1592,8 @@
localFunction;
}
-/*member: testClosure:static=[computeSignature(3),
+/*member: testClosure:static=[
def:<anonymous>,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[inst:Function,
inst:JSArray<dynamic>,
@@ -1634,10 +1607,8 @@
/*member: testClosureInvoke:
dynamic=[call(0)],
- static=[computeSignature(3),
+ static=[
def:<anonymous>,
- getRuntimeTypeArguments(3),
- getRuntimeTypeInfo(1),
setRuntimeTypeInfo(2)],
type=[inst:Function,
inst:JSArray<dynamic>,
diff --git a/pkg/compiler/test/impact/data/jsinterop.dart b/pkg/compiler/test/impact/data/jsinterop.dart
index 2068a85..b6ece09 100644
--- a/pkg/compiler/test/impact/data/jsinterop.dart
+++ b/pkg/compiler/test/impact/data/jsinterop.dart
@@ -94,7 +94,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -144,7 +143,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/jsinterop_setter2.dart b/pkg/compiler/test/impact/data/jsinterop_setter2.dart
index f334e80..95c7486 100644
--- a/pkg/compiler/test/impact/data/jsinterop_setter2.dart
+++ b/pkg/compiler/test/impact/data/jsinterop_setter2.dart
@@ -44,7 +44,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -105,7 +104,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/compiler/test/impact/data/runtime_type.dart b/pkg/compiler/test/impact/data/runtime_type.dart
index 71cf1bc..6464041 100644
--- a/pkg/compiler/test/impact/data/runtime_type.dart
+++ b/pkg/compiler/test/impact/data/runtime_type.dart
@@ -146,7 +146,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -201,7 +200,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -256,7 +254,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -313,7 +310,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -367,7 +363,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -420,7 +415,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -473,7 +467,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -528,7 +521,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -583,7 +575,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -639,7 +630,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -693,7 +683,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -748,7 +737,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -799,7 +787,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -850,7 +837,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -905,7 +891,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
@@ -963,7 +948,6 @@
_isString(1),
_isTop(1),
findType(1),
- getRuntimeTypeInfo(1),
instanceType(1),
setRuntimeTypeInfo(2)],
type=[
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
index bfe7ec8..19015f6 100644
--- a/pkg/dart2native/bin/dart2native.dart
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -19,8 +19,6 @@
path.join(binDir, 'dartaotruntime${executableSuffix}');
final String genSnapshot =
path.join(binDir, 'utils', 'gen_snapshot${executableSuffix}');
-final String platformDill =
- path.join(sdkDir, 'lib', '_internal', 'vm_platform_strong.dill');
final String productPlatformDill =
path.join(sdkDir, 'lib', '_internal', 'vm_platform_strong_product.dill');
@@ -45,20 +43,8 @@
print('Generating AOT kernel dill.');
}
- // Prefer to use the product platform file, if available. Fall back to the
- // normal one (this happens if `out/<build-dir>/dart-sdk` is used).
- //
- // Background information: For the `dart-sdk` we distribute we build release
- // and product mode configurations. Then we have an extra bundling step
- // which will add product-mode
- // gen_snapshot/dartaotruntime/vm_platform_strong_product.dill to the
- // release SDK (see tools/bots/dart_sdk.py:CopyAotBinaries)
- final String platformFileToUse = File(productPlatformDill).existsSync()
- ? productPlatformDill
- : platformDill;
-
final kernelResult = await generateAotKernel(dart, genKernel,
- platformFileToUse, sourceFile, kernelFile, packages, defines);
+ productPlatformDill, sourceFile, kernelFile, packages, defines);
if (kernelResult.exitCode != 0) {
stderr.writeln(kernelResult.stdout);
stderr.writeln(kernelResult.stderr);
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 8d3c11b..6d31716 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -107,7 +107,7 @@
if (uri.scheme == 'dev-dart-app') return true;
var scriptName = uri.path;
- return scriptName.contains('tests/compiler/dartdevc_native');
+ return scriptName.contains('tests/dartdevc');
}
bool _allowedDartLibrary(Uri uri) => uri.scheme == 'dart';
diff --git a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
index 1140c53..9a662e8 100644
--- a/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dart2js_nnbd_sdk_error_golden.txt
@@ -1,10 +1,10 @@
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1634|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1634|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1634|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1634|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
-ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1634|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
-ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1651|28|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1653|27|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1656|17|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1661|18|1|The operator '&' isn't defined for the type 'JSInt'.
-ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1661|44|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1636|7|5|Superinterfaces don't have a valid override for '&': JSNumber.& (num Function(num)), int.& (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1636|7|5|Superinterfaces don't have a valid override for '<<': JSNumber.<< (num Function(num)), int.<< (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1636|7|5|Superinterfaces don't have a valid override for '>>': JSNumber.>> (num Function(num)), int.>> (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1636|7|5|Superinterfaces don't have a valid override for '\|': JSNumber.\| (num Function(num)), int.\| (int Function(int)).
+ERROR|COMPILE_TIME_ERROR|INCONSISTENT_INHERITANCE|lib/_internal/js_runtime/lib/interceptors.dart|1636|7|5|Superinterfaces don't have a valid override for '^': JSNumber.^ (num Function(num)), int.^ (int Function(int)).
+ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1653|28|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1655|27|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1658|17|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1663|18|1|The operator '&' isn't defined for the type 'JSInt'.
+ERROR|STATIC_TYPE_WARNING|UNDEFINED_OPERATOR|lib/_internal/js_runtime/lib/interceptors.dart|1663|44|1|The operator '&' isn't defined for the type 'JSInt'.
diff --git a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
index 2f6957b..a4e5f6e 100644
--- a/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
+++ b/pkg/dev_compiler/tool/dartdevc_nnbd_sdk_error_golden.txt
@@ -1,8 +1,8 @@
-ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|3722|5|94|Const constructors can't throw exceptions.
-ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|7912|5|97|Const constructors can't throw exceptions.
+ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|3723|5|94|Const constructors can't throw exceptions.
+ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|7913|5|97|Const constructors can't throw exceptions.
ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|940|5|95|Const constructors can't throw exceptions.
ERROR|COMPILE_TIME_ERROR|CONST_CONSTRUCTOR_THROWS_EXCEPTION|lib/core/core.dart|973|5|94|Const constructors can't throw exceptions.
-ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|3720|3|5|Only redirecting factory constructors can be declared to be 'const'.
-ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|7910|3|5|Only redirecting factory constructors can be declared to be 'const'.
+ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|3721|3|5|Only redirecting factory constructors can be declared to be 'const'.
+ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|7911|3|5|Only redirecting factory constructors can be declared to be 'const'.
ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|938|3|5|Only redirecting factory constructors can be declared to be 'const'.
ERROR|SYNTACTIC_ERROR|CONST_FACTORY|lib/core/core.dart|971|3|5|Only redirecting factory constructors can be declared to be 'const'.
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 9ce8b51..a5d1775 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -82,4 +82,89 @@
const AllowedExperimentalFlags defaultAllowedExperimentalFlags =
const AllowedExperimentalFlags(sdkDefaultExperiments: {
ExperimentalFlag.nonNullable,
-}, sdkLibraryExperiments: {}, packageExperiments: {});
+}, sdkLibraryExperiments: {}, packageExperiments: {
+ "async": {
+ ExperimentalFlag.nonNullable,
+ },
+ "boolean_selector": {
+ ExperimentalFlag.nonNullable,
+ },
+ "characters": {
+ ExperimentalFlag.nonNullable,
+ },
+ "charcode": {
+ ExperimentalFlag.nonNullable,
+ },
+ "clock": {
+ ExperimentalFlag.nonNullable,
+ },
+ "collection": {
+ ExperimentalFlag.nonNullable,
+ },
+ "fake_async": {
+ ExperimentalFlag.nonNullable,
+ },
+ "fixnum": {
+ ExperimentalFlag.nonNullable,
+ },
+ "flutter": {
+ ExperimentalFlag.nonNullable,
+ },
+ "js": {
+ ExperimentalFlag.nonNullable,
+ },
+ "matcher": {
+ ExperimentalFlag.nonNullable,
+ },
+ "meta": {
+ ExperimentalFlag.nonNullable,
+ },
+ "path": {
+ ExperimentalFlag.nonNullable,
+ },
+ "pedantic": {
+ ExperimentalFlag.nonNullable,
+ },
+ "pool": {
+ ExperimentalFlag.nonNullable,
+ },
+ "sky_engine": {
+ ExperimentalFlag.nonNullable,
+ },
+ "source_maps": {
+ ExperimentalFlag.nonNullable,
+ },
+ "source_map_stack_trace": {
+ ExperimentalFlag.nonNullable,
+ },
+ "source_span": {
+ ExperimentalFlag.nonNullable,
+ },
+ "stack_trace": {
+ ExperimentalFlag.nonNullable,
+ },
+ "stream_channel": {
+ ExperimentalFlag.nonNullable,
+ },
+ "string_scanner": {
+ ExperimentalFlag.nonNullable,
+ },
+ "term_glyph": {
+ ExperimentalFlag.nonNullable,
+ },
+ "test": {
+ ExperimentalFlag.nonNullable,
+ },
+ "test_api": {
+ ExperimentalFlag.nonNullable,
+ },
+ "test_core": {
+ ExperimentalFlag.nonNullable,
+ },
+ "typed_data": {
+ ExperimentalFlag.nonNullable,
+ },
+ "vector_math": {
+ ExperimentalFlag.nonNullable,
+ },
+});
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index d596dfa..3f4c1e8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -5841,7 +5841,8 @@
void reportNonNullableInNullAwareWarningIfNeeded(
DartType operandType, String operationName, int offset) {
if (!inferrer.isTopLevel && inferrer.isNonNullableByDefault) {
- if (operandType is! InvalidType && !operandType.isPotentiallyNullable) {
+ if (operandType is! InvalidType &&
+ operandType.nullability == Nullability.nonNullable) {
inferrer.library.addProblem(
templateNonNullableInNullAware.withArguments(
operationName, operandType, inferrer.isNonNullableByDefault),
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 0755e0d..da02e67 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -326,12 +326,12 @@
loader.computeHierarchy();
loader.performTopLevelInference(myClasses);
loader.checkSupertypes(myClasses);
- loader.checkTypes();
loader.checkOverrides(myClasses);
loader.checkAbstractMembers(myClasses);
loader.addNoSuchMethodForwarders(myClasses);
loader.checkMixins(myClasses);
loader.buildOutlineExpressions(loader.coreTypes);
+ loader.checkTypes();
loader.checkRedirectingFactories(myClasses);
_updateDelayedParameterTypes();
installAllComponentProblems(loader.allComponentProblems);
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index dd4152e..c1cbe7d 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -16,6 +16,7 @@
import '../builder/builder.dart';
import '../builder/class_builder.dart';
+import '../builder/constructor_builder.dart';
import '../builder/constructor_reference_builder.dart';
import '../builder/field_builder.dart';
import '../builder/function_builder.dart';
@@ -582,7 +583,16 @@
// Check initializers.
if (builder is FunctionBuilder &&
- !builder.isAbstract &&
+ !(builder.isAbstract || builder.isExternal) &&
+ builder.formals != null) {
+ libraryBuilder.checkInitializersInFormals(
+ builder.formals, typeEnvironment);
+ }
+ });
+
+ constructors.local.forEach((String name, MemberBuilder builder) {
+ if (builder is ConstructorBuilder &&
+ !builder.isExternal &&
builder.formals != null) {
libraryBuilder.checkInitializersInFormals(
builder.formals, typeEnvironment);
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index 26858f0..a375a55 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -73,16 +73,15 @@
}
}
-/// Returns [type] normalized to the default nullability of [library].
+/// Returns [type] normalized to the known nullabilities of [library].
///
-/// If [library] is non-nullable by default all legacy types have been replaced
-/// with non-nullable types. Otherwise all non-legacy types have been replaced
-/// with legacy types.
+/// If [library] is non-nullable by default [type] returned (non-nullable
+/// libraries can handle all kinds of nullability). Otherwise all
+/// non-legacy types have been replaced with legacy types (legacy libraries
+/// can only handle legacy types).
DartType normalizeNullabilityInLibrary(DartType type, Library library) {
if (library.isNonNullableByDefault) {
- return type.accept(const _DemotionNullabilityNormalization(
- demoteTypeVariables: false, forNonNullableByDefault: true)) ??
- type;
+ return type;
} else {
return type.accept(const _DemotionNullabilityNormalization(
demoteTypeVariables: false, forNonNullableByDefault: false)) ??
diff --git a/pkg/front_end/test/patching/data/const_constructors/patch.dart b/pkg/front_end/test/patching/data/const_constructors/patch.dart
index c239691..1b92dab 100644
--- a/pkg/front_end/test/patching/data/const_constructors/patch.dart
+++ b/pkg/front_end/test/patching/data/const_constructors/patch.dart
@@ -16,5 +16,5 @@
patch
*/
@patch
- const PatchedClass({int field}) : _field = field;
+ const PatchedClass({int field: 0}) : _field = field;
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 4b0a818..669ebb1 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -178,6 +178,7 @@
class6b
clazz
cli
+clock
cls
cn
cnt
@@ -963,6 +964,7 @@
sizes
sj
sk
+sky
slash
slb
slots
@@ -1191,6 +1193,7 @@
variants
vary
vb
+vector
vegorov
versa
vice
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart b/pkg/front_end/testcases/nnbd/issue41952.dart
new file mode 100644
index 0000000..c01d2ed
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void Function<S2 extends R?>() i1<R>() => <S2 extends R?>() {};
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.outline.expect
new file mode 100644
index 0000000..75e8d54
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.outline.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method i1<R extends core::Object? = dynamic>() → <S2 extends self::i1::R? = dynamic>() → void
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.strong.expect
new file mode 100644
index 0000000..3eac783
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.strong.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method i1<R extends core::Object? = dynamic>() → <S2 extends self::i1::R? = dynamic>() → void
+ return <S2 extends self::i1::R? = self::i1::R?>() → core::Null? {};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.strong.transformed.expect
new file mode 100644
index 0000000..3eac783
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.strong.transformed.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method i1<R extends core::Object? = dynamic>() → <S2 extends self::i1::R? = dynamic>() → void
+ return <S2 extends self::i1::R? = self::i1::R?>() → core::Null? {};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline.expect
new file mode 100644
index 0000000..43cd5b0
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+void Function<S2 extends R?>() i1<R>() => <S2 extends R?>() {};
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..59c6f05
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+main() {}
+void Function<S2 extends R?>() i1<R>() => <S2 extends R?>() {};
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.weak.expect
new file mode 100644
index 0000000..3eac783
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.weak.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method i1<R extends core::Object? = dynamic>() → <S2 extends self::i1::R? = dynamic>() → void
+ return <S2 extends self::i1::R? = self::i1::R?>() → core::Null? {};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue41952.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue41952.dart.weak.transformed.expect
new file mode 100644
index 0000000..3eac783
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue41952.dart.weak.transformed.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method i1<R extends core::Object? = dynamic>() → <S2 extends self::i1::R? = dynamic>() → void
+ return <S2 extends self::i1::R? = self::i1::R?>() → core::Null? {};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42143.dart b/pkg/front_end/testcases/nnbd/issue42143.dart
index a711b13..03266d7 100644
--- a/pkg/front_end/testcases/nnbd/issue42143.dart
+++ b/pkg/front_end/testcases/nnbd/issue42143.dart
@@ -1,3 +1,7 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
import 'dart:async';
void h1<T extends FutureOr<T?>?>(T? t) {}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart b/pkg/front_end/testcases/nnbd/issue42362.dart
new file mode 100644
index 0000000..fe7cc97
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ final int i;
+
+ A.constructor1([this.i]); // error
+
+ A.constructor2({this.i}); // error
+
+ A.constructor3([int i]) // error
+ : this.i = i; // ok
+
+ A.constructor4({int i}) // error
+ : this.i = i; // ok
+
+ A.constructor5([int? i]) // ok
+ : this.i = i; // error
+
+ A.constructor6({int? i}) // ok
+ : this.i = i; // error
+
+ A.constructor7({required int i}) // ok
+ : this.i = i; // ok
+
+ external A.constructor8([int i]); // ok
+
+ external A.constructor9({int i}); // ok
+
+ factory A.factory3([int i]) = A.constructor3; // ok
+
+ factory A.factory4({int i}) = A.constructor4; // ok
+
+ factory A.factory5([int? i]) = A.constructor5; // ok
+
+ factory A.factory6({int? i}) = A.constructor6; // ok
+
+ factory A.factory7({required int i}) = A.constructor7; // ok
+
+ method3([int i]) {} // error
+
+ method4({int i}) {} // error
+
+ method5([int? i]) {} // ok
+
+ method6({int? i}) {} // ok
+
+ method7({required int i}) {} // ok
+
+ external method8([int i]); // ok
+
+ external method9({int i}); // ok
+}
+
+abstract class B {
+ var i = 42;
+
+ method3([int i]); // ok
+
+ method4({int i}); // ok
+
+ method5([int? i]); // ok
+
+ method6({int? i}); // ok
+
+ method7({required int i}); // ok
+}
+
+class C implements B {
+ var i;
+
+ C.constructor1([this.i]); // error
+
+ C.constructor2({this.i}); // error
+
+ C.constructor3([int i]) : this.i = i; // error
+
+ C.constructor4({int i}) : this.i = i; // error
+
+ C.constructor5([int? i]) : this.i = i; // error
+
+ C.constructor6({int? i}) : this.i = i; // error
+
+ C.constructor7({required int i}) // ok
+ : this.i = i; // ok
+
+ factory C.factory3([int i]) = C.constructor3; // ok
+
+ factory C.factory4({int i}) = C.constructor4; // ok
+
+ factory C.factory5([int? i]) = C.constructor5; // ok
+
+ factory C.factory6({int? i}) = C.constructor6; // ok
+
+ factory C.factory7({required int i}) = C.constructor7; // ok
+
+ method3([i]) {} // error
+
+ method4({i}) {} // error
+
+ method5([i]) {} // ok
+
+ method6({i}) {} // ok
+
+ method7({required i}) {} // ok
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.outline.expect
new file mode 100644
index 0000000..2911d31
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.outline.expect
@@ -0,0 +1,149 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:41:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([int i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:43:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({int i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:8:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:10:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:12:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor3([int i]) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:15:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor4({int i}) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:98:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:100:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:73:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:75:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:77:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor3([int i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:79:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor4({int i}) : this.i = i; // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::A::factory3, self::A::factory4, self::A::factory5, self::A::factory6, self::A::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i]) → self::A
+ ;
+ constructor constructor2({core::int i}) → self::A
+ ;
+ constructor constructor3([core::int i]) → self::A
+ ;
+ constructor constructor4({core::int i}) → self::A
+ ;
+ constructor constructor5([core::int? i]) → self::A
+ ;
+ constructor constructor6({core::int? i}) → self::A
+ ;
+ constructor constructor7({required core::int i}) → self::A
+ ;
+ external constructor constructor8([core::int i]) → self::A
+ ;
+ external constructor constructor9({core::int i}) → self::A
+ ;
+ static factory factory3([core::int i]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor3 in invalid-expression;
+ static factory factory4({core::int i}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor4 in invalid-expression;
+ static factory factory5([core::int? i]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor5 in invalid-expression;
+ static factory factory6({core::int? i}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor6 in invalid-expression;
+ static factory factory7({required core::int i}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor7 in invalid-expression;
+ method method3([core::int i]) → dynamic
+ ;
+ method method4({core::int i}) → dynamic
+ ;
+ method method5([core::int? i]) → dynamic
+ ;
+ method method6({core::int? i}) → dynamic
+ ;
+ method method7({required core::int i}) → dynamic
+ ;
+ external method method8([core::int i]) → dynamic;
+ external method method9({core::int i}) → dynamic;
+}
+abstract class B extends core::Object {
+ field core::int i;
+ synthetic constructor •() → self::B
+ ;
+ abstract method method3([core::int i]) → dynamic;
+ abstract method method4({core::int i}) → dynamic;
+ abstract method method5([core::int? i]) → dynamic;
+ abstract method method6({core::int? i}) → dynamic;
+ abstract method method7({required core::int i}) → dynamic;
+}
+class C extends core::Object implements self::B {
+ field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::C::factory3, self::C::factory4, self::C::factory5, self::C::factory6, self::C::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i]) → self::C
+ ;
+ constructor constructor2({core::int i}) → self::C
+ ;
+ constructor constructor3([core::int i]) → self::C
+ ;
+ constructor constructor4({core::int i}) → self::C
+ ;
+ constructor constructor5([core::int? i]) → self::C
+ ;
+ constructor constructor6({core::int? i}) → self::C
+ ;
+ constructor constructor7({required core::int i}) → self::C
+ ;
+ static factory factory3([core::int i]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor3 in invalid-expression;
+ static factory factory4({core::int i}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor4 in invalid-expression;
+ static factory factory5([core::int? i]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor5 in invalid-expression;
+ static factory factory6({core::int? i}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor6 in invalid-expression;
+ static factory factory7({required core::int i}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor7 in invalid-expression;
+ method method3([core::int i]) → dynamic
+ ;
+ method method4({core::int i}) → dynamic
+ ;
+ method method5([core::int? i]) → dynamic
+ ;
+ method method6({core::int? i}) → dynamic
+ ;
+ method method7({required core::int i}) → dynamic
+ ;
+}
+static method main() → void
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.strong.expect
new file mode 100644
index 0000000..7579211
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.strong.expect
@@ -0,0 +1,183 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:41:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([int i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:43:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({int i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:8:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:10:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:12:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor3([int i]) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:15:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor4({int i}) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:98:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:100:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:73:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:75:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:77:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor3([int i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:79:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor4({int i}) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor5([int? i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor6({int? i}) : this.i = i; // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::A::factory3, self::A::factory4, self::A::factory5, self::A::factory6, self::A::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::A
+ : self::A::i = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::A
+ : self::A::i = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ external constructor constructor8([core::int i = #C1]) → self::A
+ : super core::Object::•()
+ ;
+ external constructor constructor9({core::int i = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+ external method method8([core::int i = #C1]) → dynamic;
+ external method method9({core::int i = #C1}) → dynamic;
+}
+abstract class B extends core::Object {
+ field core::int i = 42;
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+ abstract method method3([core::int i = #C1]) → dynamic;
+ abstract method method4({core::int i = #C1}) → dynamic;
+ abstract method method5([core::int? i = #C1]) → dynamic;
+ abstract method method6({core::int? i = #C1}) → dynamic;
+ abstract method method7({required core::int i = #C1}) → dynamic;
+}
+class C extends core::Object implements self::B {
+ field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::C::factory3, self::C::factory4, self::C::factory5, self::C::factory6, self::C::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::C
+ : self::C::i = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor5([int? i]) : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::C
+ : self::C::i = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor6({int? i}) : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+}
+static method main() → void {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.strong.transformed.expect
new file mode 100644
index 0000000..c847fd5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.strong.transformed.expect
@@ -0,0 +1,183 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:41:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([int i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:43:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({int i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:8:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:10:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:12:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor3([int i]) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:15:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor4({int i}) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:98:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:100:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:73:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:75:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:77:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor3([int i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:79:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor4({int i}) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor5([int? i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor6({int? i}) : this.i = i; // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::A::factory3, self::A::factory4, self::A::factory5, self::A::factory6, self::A::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::A
+ : self::A::i = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in let core::int? #t2 = i in #t2.==(null) ?{core::int} #t2 as{TypeError,ForNonNullableByDefault} core::int : #t2{core::int}, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::A
+ : self::A::i = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in let core::int? #t4 = i in #t4.==(null) ?{core::int} #t4 as{TypeError,ForNonNullableByDefault} core::int : #t4{core::int}, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ external constructor constructor8([core::int i = #C1]) → self::A
+ : super core::Object::•()
+ ;
+ external constructor constructor9({core::int i = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+ external method method8([core::int i = #C1]) → dynamic;
+ external method method9({core::int i = #C1}) → dynamic;
+}
+abstract class B extends core::Object {
+ field core::int i = 42;
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+ abstract method method3([core::int i = #C1]) → dynamic;
+ abstract method method4({core::int i = #C1}) → dynamic;
+ abstract method method5([core::int? i = #C1]) → dynamic;
+ abstract method method6({core::int? i = #C1}) → dynamic;
+ abstract method method7({required core::int i = #C1}) → dynamic;
+}
+class C extends core::Object implements self::B {
+ field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::C::factory3, self::C::factory4, self::C::factory5, self::C::factory6, self::C::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::C
+ : self::C::i = let final<BottomType> #t5 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor5([int? i]) : this.i = i; // error
+ ^" in let core::int? #t6 = i in #t6.==(null) ?{core::int} #t6 as{TypeError,ForNonNullableByDefault} core::int : #t6{core::int}, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::C
+ : self::C::i = let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor6({int? i}) : this.i = i; // error
+ ^" in let core::int? #t8 = i in #t8.==(null) ?{core::int} #t8 as{TypeError,ForNonNullableByDefault} core::int : #t8{core::int}, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+}
+static method main() → void {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline.expect
new file mode 100644
index 0000000..7110b99
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline.expect
@@ -0,0 +1,56 @@
+class A {
+ final int i;
+ A.constructor1([this.i]);
+ A.constructor2({this.i});
+ A.constructor3([int i]) : this.i = i;
+ A.constructor4({int i}) : this.i = i;
+ A.constructor5([int? i]) : this.i = i;
+ A.constructor6({int? i}) : this.i = i;
+ A.constructor7({required int i}) : this.i = i;
+ external A.constructor8([int i]);
+ external A.constructor9({int i});
+ factory A.factory3([int i]) = A.constructor3;
+ factory A.factory4({int i}) = A.constructor4;
+ factory A.factory5([int? i]) = A.constructor5;
+ factory A.factory6({int? i}) = A.constructor6;
+ factory A.factory7({required int i}) = A.constructor7;
+ method3([int i]) {}
+ method4({int i}) {}
+ method5([int? i]) {}
+ method6({int? i}) {}
+ method7({required int i}) {}
+ external method8([int i]);
+ external method9({int i});
+}
+
+abstract class B {
+ var i = 42;
+ method3([int i]);
+ method4({int i});
+ method5([int? i]);
+ method6({int? i});
+ method7({required int i});
+}
+
+class C implements B {
+ var i;
+ C.constructor1([this.i]);
+ C.constructor2({this.i});
+ C.constructor3([int i]) : this.i = i;
+ C.constructor4({int i}) : this.i = i;
+ C.constructor5([int? i]) : this.i = i;
+ C.constructor6({int? i}) : this.i = i;
+ C.constructor7({required int i}) : this.i = i;
+ factory C.factory3([int i]) = C.constructor3;
+ factory C.factory4({int i}) = C.constructor4;
+ factory C.factory5([int? i]) = C.constructor5;
+ factory C.factory6({int? i}) = C.constructor6;
+ factory C.factory7({required int i}) = C.constructor7;
+ method3([i]) {}
+ method4({i}) {}
+ method5([i]) {}
+ method6({i}) {}
+ method7({required i}) {}
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..294d4f9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.textual_outline_modelled.expect
@@ -0,0 +1,56 @@
+abstract class B {
+ method3([int i]);
+ method4({int i});
+ method5([int? i]);
+ method6({int? i});
+ method7({required int i});
+ var i = 42;
+}
+
+class A {
+ A.constructor1([this.i]);
+ A.constructor2({this.i});
+ A.constructor3([int i]) : this.i = i;
+ A.constructor4({int i}) : this.i = i;
+ A.constructor5([int? i]) : this.i = i;
+ A.constructor6({int? i}) : this.i = i;
+ A.constructor7({required int i}) : this.i = i;
+ external A.constructor8([int i]);
+ external A.constructor9({int i});
+ external method8([int i]);
+ external method9({int i});
+ factory A.factory3([int i]) = A.constructor3;
+ factory A.factory4({int i}) = A.constructor4;
+ factory A.factory5([int? i]) = A.constructor5;
+ factory A.factory6({int? i}) = A.constructor6;
+ factory A.factory7({required int i}) = A.constructor7;
+ final int i;
+ method3([int i]) {}
+ method4({int i}) {}
+ method5([int? i]) {}
+ method6({int? i}) {}
+ method7({required int i}) {}
+}
+
+class C implements B {
+ C.constructor1([this.i]);
+ C.constructor2({this.i});
+ C.constructor3([int i]) : this.i = i;
+ C.constructor4({int i}) : this.i = i;
+ C.constructor5([int? i]) : this.i = i;
+ C.constructor6({int? i}) : this.i = i;
+ C.constructor7({required int i}) : this.i = i;
+ factory C.factory3([int i]) = C.constructor3;
+ factory C.factory4({int i}) = C.constructor4;
+ factory C.factory5([int? i]) = C.constructor5;
+ factory C.factory6({int? i}) = C.constructor6;
+ factory C.factory7({required int i}) = C.constructor7;
+ method3([i]) {}
+ method4({i}) {}
+ method5([i]) {}
+ method6({i}) {}
+ method7({required i}) {}
+ var i;
+}
+
+void main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.weak.expect
new file mode 100644
index 0000000..7579211
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.weak.expect
@@ -0,0 +1,183 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:41:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([int i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:43:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({int i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:8:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:10:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:12:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor3([int i]) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:15:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor4({int i}) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:98:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:100:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:73:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:75:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:77:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor3([int i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:79:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor4({int i}) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor5([int? i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor6({int? i}) : this.i = i; // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::A::factory3, self::A::factory4, self::A::factory5, self::A::factory6, self::A::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::A
+ : self::A::i = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::A
+ : self::A::i = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ external constructor constructor8([core::int i = #C1]) → self::A
+ : super core::Object::•()
+ ;
+ external constructor constructor9({core::int i = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::A
+ let dynamic #redirecting_factory = self::A::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::A
+ let dynamic #redirecting_factory = self::A::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+ external method method8([core::int i = #C1]) → dynamic;
+ external method method9({core::int i = #C1}) → dynamic;
+}
+abstract class B extends core::Object {
+ field core::int i = 42;
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+ abstract method method3([core::int i = #C1]) → dynamic;
+ abstract method method4({core::int i = #C1}) → dynamic;
+ abstract method method5([core::int? i = #C1]) → dynamic;
+ abstract method method6({core::int? i = #C1}) → dynamic;
+ abstract method method7({required core::int i = #C1}) → dynamic;
+}
+class C extends core::Object implements self::B {
+ field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::C::factory3, self::C::factory4, self::C::factory5, self::C::factory6, self::C::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::C
+ : self::C::i = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor5([int? i]) : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::C
+ : self::C::i = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor6({int? i}) : this.i = i; // error
+ ^" in i as{TypeError,ForNonNullableByDefault} core::int, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::C
+ let dynamic #redirecting_factory = self::C::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::C
+ let dynamic #redirecting_factory = self::C::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+}
+static method main() → void {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue42362.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42362.dart.weak.transformed.expect
new file mode 100644
index 0000000..d5a0891
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42362.dart.weak.transformed.expect
@@ -0,0 +1,183 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:41:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([int i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:43:16: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({int i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:8:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:10:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:12:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor3([int i]) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:15:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// A.constructor4({int i}) // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:98:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method3([i]) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:100:12: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// method4({i}) {} // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:73:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor1([this.i]); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:75:24: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor2({this.i}); // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:77:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor3([int i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:79:23: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
+// C.constructor4({int i}) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor5([int? i]) : this.i = i; // error
+// ^
+//
+// pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+// C.constructor6({int? i}) : this.i = i; // error
+// ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ final field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::A::factory3, self::A::factory4, self::A::factory5, self::A::factory6, self::A::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::A
+ : self::A::i = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:19:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::A
+ : self::A::i = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:22:18: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ : this.i = i; // error
+ ^" in i, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::A
+ : self::A::i = i, super core::Object::•()
+ ;
+ external constructor constructor8([core::int i = #C1]) → self::A
+ : super core::Object::•()
+ ;
+ external constructor constructor9({core::int i = #C1}) → self::A
+ : super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::A
+ let<BottomType> #redirecting_factory = self::A::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+ external method method8([core::int i = #C1]) → dynamic;
+ external method method9({core::int i = #C1}) → dynamic;
+}
+abstract class B extends core::Object {
+ field core::int i = 42;
+ synthetic constructor •() → self::B
+ : super core::Object::•()
+ ;
+ abstract method method3([core::int i = #C1]) → dynamic;
+ abstract method method4({core::int i = #C1}) → dynamic;
+ abstract method method5([core::int? i = #C1]) → dynamic;
+ abstract method method6({core::int? i = #C1}) → dynamic;
+ abstract method method7({required core::int i = #C1}) → dynamic;
+}
+class C extends core::Object implements self::B {
+ field core::int i;
+ static field dynamic _redirecting# = <dynamic>[self::C::factory3, self::C::factory4, self::C::factory5, self::C::factory6, self::C::factory7]/*isNullableByDefault*/;
+ constructor constructor1([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor2({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor3([core::int i = #C1]) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor4({core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ constructor constructor5([core::int? i = #C1]) → self::C
+ : self::C::i = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:81:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor5([int? i]) : this.i = i; // error
+ ^" in i, super core::Object::•()
+ ;
+ constructor constructor6({core::int? i = #C1}) → self::C
+ : self::C::i = let final<BottomType> #t4 = invalid-expression "pkg/front_end/testcases/nnbd/issue42362.dart:83:39: Error: A value of type 'int?' can't be assigned to a variable of type 'int'.
+ C.constructor6({int? i}) : this.i = i; // error
+ ^" in i, super core::Object::•()
+ ;
+ constructor constructor7({required core::int i = #C1}) → self::C
+ : self::C::i = i, super core::Object::•()
+ ;
+ static factory factory3([core::int i = #C1]) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor3 in invalid-expression;
+ static factory factory4({core::int i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor4 in invalid-expression;
+ static factory factory5([core::int? i = #C1]) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor5 in invalid-expression;
+ static factory factory6({core::int? i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor6 in invalid-expression;
+ static factory factory7({required core::int i = #C1}) → self::C
+ let<BottomType> #redirecting_factory = self::C::constructor7 in invalid-expression;
+ method method3([core::int i = #C1]) → dynamic {}
+ method method4({core::int i = #C1}) → dynamic {}
+ method method5([core::int? i = #C1]) → dynamic {}
+ method method6({core::int? i = #C1}) → dynamic {}
+ method method7({required core::int i = #C1}) → dynamic {}
+}
+static method main() → void {}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.outline.expect b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.outline.expect
index cae508d..25d8360 100644
--- a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.outline.expect
@@ -30,10 +30,6 @@
// void method([int i]) {}
// ^
//
-// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:8:36: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
-// external void patchedMethod([int i]);
-// ^
-//
// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:11:18: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
// void method([int i]) {}
// ^
diff --git a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.expect b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.expect
index 9a4131e..0c2e596 100644
--- a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.expect
@@ -32,10 +32,6 @@
// void method([int i]) {}
// ^
//
-// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:8:36: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
-// external void patchedMethod([int i]);
-// ^
-//
// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:11:18: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
// void method([int i]) {}
// ^
diff --git a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.transformed.expect
index 9a4131e..0c2e596 100644
--- a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.strong.transformed.expect
@@ -32,10 +32,6 @@
// void method([int i]) {}
// ^
//
-// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:8:36: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
-// external void patchedMethod([int i]);
-// ^
-//
// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:11:18: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
// void method([int i]) {}
// ^
diff --git a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.expect b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.expect
index 9a4131e..0c2e596 100644
--- a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.expect
@@ -32,10 +32,6 @@
// void method([int i]) {}
// ^
//
-// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:8:36: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
-// external void patchedMethod([int i]);
-// ^
-//
// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:11:18: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
// void method([int i]) {}
// ^
diff --git a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.transformed.expect
index 9a4131e..0c2e596 100644
--- a/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_optional_parameters/main.dart.weak.transformed.expect
@@ -32,10 +32,6 @@
// void method([int i]) {}
// ^
//
-// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:8:36: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
-// external void patchedMethod([int i]);
-// ^
-//
// pkg/front_end/testcases/nnbd/platform_optional_parameters/origin_lib.dart:11:18: Error: Optional parameter 'i' should have a default value because its type 'int' doesn't allow null.
// void method([int i]) {}
// ^
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003.dart b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart
new file mode 100644
index 0000000..814b061
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'issue42003_lib.dart';
+
+main() {
+ returnString()?.length;
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline.expect
new file mode 100644
index 0000000..7c147d5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+import 'issue42003_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..7c147d5
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+import 'issue42003_lib.dart';
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.expect
new file mode 100644
index 0000000..f5df90e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "issue42003_lib.dart" as iss;
+
+import "org-dartlang-testcase:///issue42003_lib.dart";
+
+static method main() → dynamic {
+ let final core::String* #t1 = iss::returnString() in #t1.{core::String::==}(null) ?{core::int?} null : #t1{core::String}.{core::String::length};
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+static method returnString() → core::String*
+ return "foo";
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.transformed.expect
new file mode 100644
index 0000000..f5df90e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003.dart.weak.transformed.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "issue42003_lib.dart" as iss;
+
+import "org-dartlang-testcase:///issue42003_lib.dart";
+
+static method main() → dynamic {
+ let final core::String* #t1 = iss::returnString() in #t1.{core::String::==}(null) ?{core::int?} null : #t1{core::String}.{core::String::length};
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+static method returnString() → core::String*
+ return "foo";
diff --git a/pkg/front_end/testcases/nnbd_mixed/issue42003_lib.dart b/pkg/front_end/testcases/nnbd_mixed/issue42003_lib.dart
new file mode 100644
index 0000000..f7f0749
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/issue42003_lib.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.6
+
+String returnString() => "foo";
diff --git a/pkg/js/CHANGELOG.md b/pkg/js/CHANGELOG.md
index 800418a..05ef42f 100644
--- a/pkg/js/CHANGELOG.md
+++ b/pkg/js/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.6.3-dev
+
+* Opt in to null safety.
+
## 0.6.2
* Improved documentation.
diff --git a/pkg/js/analysis_options.yaml b/pkg/js/analysis_options.yaml
new file mode 100644
index 0000000..9951703
--- /dev/null
+++ b/pkg/js/analysis_options.yaml
@@ -0,0 +1,47 @@
+include: package:pedantic/analysis_options.yaml
+
+analyzer:
+ strong-mode:
+ implicit-casts: false
+ enable-experiment:
+ - non-nullable
+
+linter:
+ rules:
+ - avoid_empty_else
+ - avoid_init_to_null
+ - avoid_null_checks_in_equality_operators
+ - avoid_unused_constructor_parameters
+ - await_only_futures
+ - camel_case_types
+ - cancel_subscriptions
+ - constant_identifier_names
+ - control_flow_in_finally
+ - directives_ordering
+ - empty_catches
+ - empty_constructor_bodies
+ - empty_statements
+ - hash_and_equals
+ - implementation_imports
+ - iterable_contains_unrelated_type
+ - library_names
+ - library_prefixes
+ - list_remove_unrelated_type
+ - non_constant_identifier_names
+ - overridden_fields
+ - package_api_docs
+ - package_names
+ - package_prefixed_library_names
+ - prefer_equal_for_default_values
+ - prefer_final_fields
+ - prefer_generic_function_type_aliases
+ - prefer_is_not_empty
+ - slash_for_doc_comments
+ - test_types_in_equals
+ - throw_in_finally
+ - type_init_formals
+ - unnecessary_brace_in_string_interps
+ - unnecessary_const
+ - unnecessary_new
+ - unrelated_type_equality_checks
+ - valid_regexps
diff --git a/pkg/js/lib/js.dart b/pkg/js/lib/js.dart
index 2ee0598..9de2f52 100644
--- a/pkg/js/lib/js.dart
+++ b/pkg/js/lib/js.dart
@@ -17,7 +17,7 @@
/// dart name is used. It is not valid to specify a custom [name] for class
/// instance members.
class JS {
- final String name;
+ final String? name;
const JS([this.name]);
}
diff --git a/pkg/js/pubspec.yaml b/pkg/js/pubspec.yaml
index f3e47e1..24616bf 100644
--- a/pkg/js/pubspec.yaml
+++ b/pkg/js/pubspec.yaml
@@ -1,7 +1,10 @@
name: js
-version: 0.6.2
+version: 0.6.3-dev
description: Annotations to create static Dart interfaces for JavaScript APIs.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/js
environment:
- sdk: '>=2.0.0 <3.0.0'
+ sdk: '>=2.9.0-1 <3.0.0'
+
+dev_dependencies:
+ pedantic: ^1.9.0
diff --git a/pkg/kernel/lib/library_index.dart b/pkg/kernel/lib/library_index.dart
index 3a05805..94db880 100644
--- a/pkg/kernel/lib/library_index.dart
+++ b/pkg/kernel/lib/library_index.dart
@@ -12,6 +12,7 @@
class LibraryIndex {
static const String getterPrefix = 'get:';
static const String setterPrefix = 'set:';
+ static const String tearoffPrefix = 'get#';
/// A special class name that can be used to access the top-level members
/// of a library.
@@ -237,7 +238,7 @@
String getDisambiguatedExtensionName(
ExtensionMemberDescriptor extensionMember) {
if (extensionMember.kind == ExtensionMemberKind.TearOff)
- return 'get#' + extensionMember.name.name;
+ return LibraryIndex.tearoffPrefix + extensionMember.name.name;
if (extensionMember.kind == ExtensionMemberKind.Getter)
return LibraryIndex.getterPrefix + extensionMember.name.name;
if (extensionMember.kind == ExtensionMemberKind.Setter)
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 8399281..78012f8 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -1861,9 +1861,10 @@
'(${expression.toSource()}) offset=${expression.offset}');
}
var origin = _makeEdgeOrigin(sourceType, expression);
+ var hard = _postDominatedLocals.isReferenceInScope(expression) ||
+ expression.unParenthesized is AsExpression;
var edge = _graph.makeNonNullable(sourceType.node, origin,
- hard: _postDominatedLocals.isReferenceInScope(expression),
- guards: _guards);
+ hard: hard, guards: _guards);
if (origin is ExpressionChecksOrigin) {
origin.checks.edges[FixReasonTarget.root] = edge;
}
@@ -2643,7 +2644,7 @@
if (name != null) {
parameterType = calleeType.namedParameters[name];
if (parameterType == null) {
- // TODO(#42327)
+ // TODO(paulberry)
_unimplemented(expression, 'Missing type for named parameter');
}
suppliedNamedParameters.add(name);
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index 01fe7f3..602ef69 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -298,8 +298,6 @@
implements MigrationResolutionHooks {
FixBuilder _fixBuilder;
- TypeProvider get typeProvider => _fixBuilder.typeProvider;
-
final Expando<List<CollectionElement>> _collectionElements = Expando();
final Expando<bool> _shouldStayNullAware = Expando();
@@ -310,6 +308,20 @@
FlowAnalysis<AstNode, Statement, Expression, PromotableElement, DartType>
_flowAnalysis;
+ TypeProvider get typeProvider => _fixBuilder.typeProvider;
+
+ Element get _elementHashCode =>
+ _fixBuilder.typeProvider.objectType.getGetter('hashCode');
+
+ Element get _elementNoSuchMethod =>
+ _fixBuilder.typeProvider.objectType.getGetter('noSuchMethod');
+
+ Element get _elementRuntimeType =>
+ _fixBuilder.typeProvider.objectType.getMethod('runtimeType');
+
+ Element get _elementToString =>
+ _fixBuilder.typeProvider.objectType.getMethod('toString');
+
@override
void freshTypeParameterCreated(TypeParameterElement newTypeParameter,
TypeParameterElement oldTypeParameter) {
@@ -587,15 +599,6 @@
return type;
}
- Element get _elementToString =>
- _fixBuilder.typeProvider.objectType.getMethod('toString');
- Element get _elementHashCode =>
- _fixBuilder.typeProvider.objectType.getGetter('hashCode');
- Element get _elementRuntimeType =>
- _fixBuilder.typeProvider.objectType.getMethod('runtimeType');
- Element get _elementNoSuchMethod =>
- _fixBuilder.typeProvider.objectType.getGetter('noSuchMethod');
-
bool _needsNullCheckDueToStructure(Expression node) {
var parent = node.parent;
@@ -1035,7 +1038,7 @@
.decoratedTypeAnnotation(_fixBuilder.source, node);
if (!typeIsNonNullableByContext(node)) {
var type = decoratedType.type;
- if (!type.isDynamic && !type.isVoid) {
+ if (!type.isDynamic && !type.isVoid && !type.isDartCoreNull) {
_makeTypeNameNullable(node, decoratedType);
}
}
diff --git a/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart b/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
index e5538ea..515595f 100644
--- a/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/instrumentation_renderer.dart
@@ -71,6 +71,7 @@
'dartPageStyle': resources.migration_css,
'highlightJsPath': migrationInfo.highlightJsPath,
'highlightStylePath': migrationInfo.highlightStylePath,
+ 'dartLogoPath': migrationInfo.dartLogoPath,
'sdkVersion': _dartSdkVersion,
'migrationAppliedStyle': hasBeenApplied ? 'applied' : 'proposed',
'needsRerunStyle': needsRerun ? 'needs-rerun' : '',
diff --git a/pkg/nnbd_migration/lib/src/front_end/migration_info.dart b/pkg/nnbd_migration/lib/src/front_end/migration_info.dart
index 7774927..ddc8ed6 100644
--- a/pkg/nnbd_migration/lib/src/front_end/migration_info.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/migration_info.dart
@@ -83,6 +83,9 @@
/// The path to the highlight.pack.js stylesheet, relative to [unitInfo].
String get highlightStylePath => PreviewSite.highlightCssPath;
+ /// The path of the Dart logo displayed in the toolbar.
+ String get dartLogoPath => PreviewSite.dartLogoPath;
+
/// Return the path to [unit] from [includedRoot], to be used as a display
/// name for a library.
String computeName(UnitInfo unit) =>
diff --git a/pkg/nnbd_migration/lib/src/front_end/resources/dart_192.png b/pkg/nnbd_migration/lib/src/front_end/resources/dart_192.png
new file mode 100644
index 0000000..16ed071
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/front_end/resources/dart_192.png
Binary files differ
diff --git a/pkg/nnbd_migration/lib/src/front_end/resources/index.html b/pkg/nnbd_migration/lib/src/front_end/resources/index.html
index 48d7a74..ecfd0c3 100644
--- a/pkg/nnbd_migration/lib/src/front_end/resources/index.html
+++ b/pkg/nnbd_migration/lib/src/front_end/resources/index.html
@@ -20,6 +20,7 @@
</div>
<p class="root">{{ root }}</p>
<header class="elevation-z4">
+ <img src="{{ dartLogoPath }}" alt="DartPad Logo" class="logo"/>
<h1 class="before-apply">Proposed null safety changes</h1>
<h1 class="after-apply">✓ Null safety migration applied</h1>
<h2 id="unit-name"> </h2>
diff --git a/pkg/nnbd_migration/lib/src/front_end/resources/migration.css b/pkg/nnbd_migration/lib/src/front_end/resources/migration.css
index d1bf62a..8f8c4e0 100644
--- a/pkg/nnbd_migration/lib/src/front_end/resources/migration.css
+++ b/pkg/nnbd_migration/lib/src/front_end/resources/migration.css
@@ -65,6 +65,12 @@
margin: 10px;
}
+header img.logo {
+ height: 24px;
+ width: 24px;
+ margin-right: 8px;
+}
+
footer .report-problem {
right: 0px;
margin: 4px 8px;
diff --git a/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart b/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
index f86160d..e03b662 100644
--- a/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
@@ -9,6 +9,10 @@
import 'dart:convert' as convert;
+String get dart_192_png {
+ return _dart_192_png ??= _decode(_dart_192_png_base64);
+}
+
String get highlight_css {
return _highlight_css ??= _decode(_highlight_css_base64);
}
@@ -34,6 +38,162 @@
return String.fromCharCodes(convert.base64Decode(data));
}
+String _dart_192_png;
+// dart_192_png md5 is '7d80a0adfe72aa9597d5e135b70b42c8'
+String _dart_192_png_base64 = '''
+iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAA
+CxMBAJqcGAAABCRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRv
+YmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRm
+PSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpE
+ZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk
+b2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5j
+b20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1l
+bnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4w
+LyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAg
+ICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjA8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZm
+OlhSZXNvbHV0aW9uPjcyPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlv
+bj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjwvdGlmZjpZ
+UmVzb2x1dGlvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjE5MjwvZXhpZjpQaXhlbFhE
+aW1lbnNpb24+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAg
+ICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTkyPC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAg
+ICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICAgIDxyZGY6U2VxLz4KICAgICAgICAgPC9kYzpzdWJqZWN0
+PgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxOToxMToyNyAxMzoxMToyMDwveG1wOk1vZGlmeURh
+dGU+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGl4ZWxtYXRvciAzLjk8L3htcDpDcmVhdG9yVG9v
+bD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CnQAoPMA
+AB6pSURBVHgB7V1rsBzFde6Z3b26usKAhMSVEAkGLCQQpqgKktDLCDBVBMcCh7omAvIAJF0hAXbwr/xI
+hR+pVFKVSlIkIEsC/Kj8QODYQRTlpCog8TAxhcs2JBgEhjLBDwwmNiiSru4+JufMbs/2PHqmp6d7XttD
+iZ3p6cfpc76vz+memb6EmMNowGjAaMBoYDQ1YI1mt8vX63scx37yWTJpN8iZtkOWOIQsIhZZDL+ng7Rv
+WxZ5q2eRw5MnkzcfXWnNlq8H1ZTIEKBAu2141pnfbJDLANxXEYesgX9nA+Dn202Avj0QDBLc8y4hvQ6Z
+gTtvQMq/Q5lvHFxrvVCg+LVo2hCgADNe9ZxzRrtBbgfl32zZ5ONWgxAHAO7+Q8Djv6gDCmBeuwVkOEE6
+jkUOkg6599BG8gTc4ZWKqsmkDTRgCJAjFDY+4yxp2mQbjOjT9hxyRg8CGQS91AGWQyK4pCHk206P/MXT
+660Xpeoa4UKGADkY3wV+E4BPyHZ7jCzttTMAP0JeIBNxOuQYeI6/WXgK+WszR4hQEifJEICjGBXJHvAt
+AH5LPfBZGSGUIkAu0m2Tb7e7ZOt3Nlg/Z++b82gNGAJE6yVTap7ADwraGIf5QZu83OiQz/3HRuut4H1z
+7deAIYBfH5muigQ+K7gbEs2SV9o9svk5QwJWNaFzQ4CQStInIPAbDbIdwpBtukMdUelcErTJK40u2Ww8
+AV9rhgB83STe2fg9AP4JAD7G+GOwqqN4cpsoQEIGSgKYExhPwNGVIQBHMXHJ62Edv9Ug22DlvZTAZ2Wn
+JDCegNXK8NwQYKiLxLMqAZ/tDCWB8QSsVvrnhgBhnYRSBk9uKzHih4QfJAxI8KMTx8nm56+03uTlG7V0
+Q4AYi7sjPsT3EONvK2OMHyN65C1KAgjdNj+13pAAlWQIEAEVD/j9VZ3STW4jRBZOMiTwq8oQgNEHhjpd
+WM7sweS2MUaWlG1VhxE106lLgg75kQXPCUbdExgCAJSueNJZSibINnidEtfxazXi85hiSNDXzEgTAEf8
+DryZCarAGL+2I74hAU8DIzoHuOJ5ZymM9ttxxK9zqMM3+/DOqHuCkfIABvhD4LNnlATODLn20OXWj9l7
+dT8fCQJQ4IMxRzLUEQHxqJKg1gRwgW+T7aRngC9KAlj5epWcIJtHxRPUkgCDER8nt1tHcXIrAnZeHvQE
+o0SCWhGAAT6GOovruo7PA6+q9FEiQS0IsOmgc6Y1B0IdM+Kr4gDxSEAgHFpX34lxpQmAIz48td0BH6Js
+hQdYpRzxsyq4yL1OXBJ0YE4A7w7VlQRZ7aNsxElTkTfi40tqJQB+UUrMgxx19wRF2S4N3r28CHwyTqZB
+6EJH/LIqTRchqCeAfYyufeYyC3emq81RVlv6FFwG4FdCUYzWVJMBSeC0yWuw7crmOpGg1Hbd9F0Y8R0Y
+8R13HX8y71WdUiuHAXvSqSoy1JEEpbSxC/yuO7m9rYgYv5RKSUK5wH0VRKgbCUpl63Xfd84amwXgOxDj
+j5OFdMTXKSSCgq2fPRfAVOWysCQI9j2qM15+PBn8qxMJSmPvDXt+sMsZm/jzxsRcCHVg19iu7K6xUWZM
+TiuNIpJFVZLDAzanNge+A7XgjxVYzSYhrRax5syBf+PuPwI7/DbwifEJchjmBJ+t8pygHHZf95dnrb7l
+uv86qdf+2M9efgW2AIc9wDUfYN/+QX+T2ktCTFL5vO+n7JcT1T+oA2hAGg0APNikOadFmhMTpDV/Pmks
+miTNpWeQrmW90WmT34Md6F7Pu4sq2gN6l+BYdOrtXav1sfGVy8kvfvIB+ej1N/ojjybRPPBrqr+q1UaS
+ADqD+rLhf03bIq2GReY2f0rmzT1MTl5wCjllxfJlY2ee9dim7zmfO3SJ9VrV+l48AW7es4Qc791KOrPg
+ci1yxoZ1oGxCfnNYDwkM+PkQpboJEgGvO/C/TtchM22HHMEq/m+WNH51lMz7ybtk8reXrli0Ytm/bn7R
+ufbAKuswv4Xy3aF/iKc4ydqNbRBQLiLwFx4c1DSgfwmQ4NTl58Ge9x1lcqFxqYGVVVrTiqL0BOpz9WfB
+TfqvB2kfneiSNw6/TV566j+Xv/L4k49d+fCb51VJLcUSYMuehRZxpvGPX3kHkAAVvGTDWiUkQGNGGdRr
+z5xEakBUby4ZYI5w9Ogx8tYb7yx/8akXDyy9+5uVIUGhBLB79i2kOXZG8O8EuZ4ALJCVBAb4kdhOlSiq
+QyQCDmQfHTm+/L1f/ubAnBv2VoIExRHgur8/1SHOTtLjLHdiOJSBBKKGS4WGEc2cRpcWkKDj2Mtn7cYB
+UgESFEeA8ZNugnW1j3MJgGCTCIfQWGkMNqKYTt3tVHqFhwOwlr0cniOUngTFEGDqvpPgae+dpIfTqPgj
+TThkgB+vSxV3hXVcERIUQwCr9XnSaC33TX7jrMOGQyuiV4eEDRPXjrknpAFhXbMkmLp/uVDlOWfKnwB/
+8pVxmDB9AcObVAcNh9aHV4eEDZKqQZM5TgPCOqckaM55rIxzgvwJcLx7HYz+FwmP/owVfOHQwBMIG4Kp
+x5yq0YCw7ikJLPtxMvVgqTxBvgTYvqdlkd7dqUd/1l40HAJPMB9I0FP4sIxtxpyLaSAVCezmeVaDHCgT
+CfIlwIf2NcRurZIZ/X3mYMKh+fDE2JDAp53cL9KRoAEkcIAE5ZgT5EeAqUfgNSpyt4o1SqjHXSJ1nxOg
+JygpCfBNSlX/5Y7qlA2mIwF6grFSeIL8CGAfuRLWhjcSjAczHC74afmSeYIg2KmYKn7ZulXUp6OO9CQo
+PhzKiQD4eUX3S8TG9zzlj6jC3sS4IE9QBDCLaFPUaulIgOFQsSTIhwCff3AjvOB/JekyL72JanSQLwr8
+XhXsxDiHcKhMACyTLNQeVSJBLgSwLOduYuNnXinX/qlGRX5zCIco2ETEKSJP2eWL1AmGxLbrCQpZItVP
+gKndq+FLl2uyxP6xoz+jVV84pHCJtGrAKoO8wl4A7dcnwTIIhx4n1+9ZwZhU+6l2Ath2409Jo9mSHf1F
+we9pioZD6/A5Ab5tkSXs6kPJq7tiJ0UTQYoEreaBPEmglwBb9l3kWI3rCHw1LXOkBj9thIZD6y6VJgGC
+py5HkX2RJsGWfDyBVgLYDrzz02iOy47+WQDohUMpSVD0qJmlz3FlK9MvGg454AlyIIE+AsA7HzDlvUE2
+9lcy/nrhkJgnKHKkjAOvyntF9DGVF8DO5kgCbQSwG707SWNsnsx7P0rAT1EjGA4VAQwqYt6/RfRVmgSk
+pXVOoIcAU/vOdhzrZtnRXzUgksKhIgChuo9p66tEn9ETWPYyawxIcMN956fto0h+PQSwye3wsfspuNVJ
+2kPp6M82zgmHKgEEth8Kz/Pue2ovgH2lJLDH4XsC9SRQT4Cp3Uuho7fIjP7awE9Bw4RDC86H19I76QlK
+q6rLL5IgbyKk1p1LgsYyyxpX7gmUEwDW/bfDRlcLZUb/1IqRKIDhkLvvEKwOnarwYZmEKKUqkhcJpLwA
+aqo/Mf5EnwT7lIVDagkw9dAieO1tm8zonysaMByCcW/JujXSzwmyyotAYP9lrU9F+eqQwAZPoIYEagnQ
+6NwKo/8SmdFfemRIaXkvzKJzgvVrCIZDKrdhZEViQc6es3nwnL3Hngfzjfy15wnUkEAdAW68fz6MILdn
+eeNTt3E98NOGBiRYvB6eEwAJsrw2QatkwYvnWQ/V9SXJU3ovgB1QSAJ1BOg2b4Z1/7OC2xwmKdy9rwAo
+Se1ENoGJbjhEyGIIh9ATyJKAAjVJjqz382gnLxJk0gVLgqkvXyBblxoC4EZXBDe64mxzKCudonJc8NP6
+qSfAOYFLAvF+5AFIKib7q7vdSpGgAa9NSM4J1BDAnvMHEPsvkyEAGjL3I6pNOieA1aEF54t9aF+I7AFl
+lUGGgEjCl0pkdz1B81zLgjmBhCfIToCpv5sLW5zDRlflXFMPYT2UwNjLJUFyOISGU2I8puksp7rkqYQX
+QMUhCazGJyz0BClJkJ0A9km/DxtdXQjBc2ob6gZRHNa5wnrhEHoCnBP4wyHdMnPlErihQzbdJFAmM/5J
+URs8QUoSZCPA1CNjoKAv0omkgI2KzSLKCM8T+MMhZcbSqIUqyKit+zQccrdcEZsYZyNA48hngHWXyIz+
+2pQwqFgU61w5ev3vlxevxdWhFbC4ld7DcevWfEM1CXR7AaXqcElggyfAfYeSSSBPgE33NK1e70uywbBq
+IyUqMQ0j6Lf74An6r02szrREmiibhgy56zdDH5TL6iPBQ7FLpPIEWHLmp2H0X1fG1x5CWA8lxFiLgt/L
+AglgocXu6tAK6ecEXnU5nqgEVqW8AOrYIwHsO3T93pU8tcsR4J57bKvnwEZXKlXMEzHH9AD4vd7hnAAO
+LxzK8KF9jr1xm/L6kHfDZWiPkqAFf6lmKtoTyBHgtaWfgr1cLpcd/XUaJTTYhxLELBOS0ZsY48Oy0fQE
+Or1ASN9iZkrO5ZKgcY67A92WsCeQIQDsc4Wb3OJGVzU6AqN/ZM+oJ3Bfm4CJcUpPgPMJkX+RbZtEeQ1Q
+T+CAJ7j+n3zhUHoC3LBvDXymdrXs6C/fi+SSocE+lJBcB+aIHY0YEsy/AEngf04Q1QIFfdS9qLS0+aPq
+CKbF9imYOeZapxeIaTb7rYEnGCPtA3Ov/as1tMLUBIACsM2h/EZXtOFS/TKjvxBQBiSYhCXSuLdI+UDG
+BqP++bXCL+/PJ3ol1DfRyqqYz13Kts5xLPI0Fb9JT4R+b9x7sdOzNmcZ/etiBPqh/SSEQ3j876uvwbjQ
+VycC138wDPPfCFwF8/XrofW5bQZK1OkS1TYYW/R1y0GPbc2hDaTyAHYPnvraLSgcNBStrrjfIOSEN3Zj
+uhLCLac7XhHqCXBOgOFQt+vG+P5iXm5/stCVvywlglBRTibRPnKKu8mVDYO8Tg31Ku4B4HVT2OpkiuA7
+FyN8DFU3UAKSAFCFS6QIjKEnCOWEAiGacjTJlqXnQ29Qd0/AUYqWZGEPYDvkLtJsTej3UVr6GV0pxVb0
+XfFU6gnW4hPjqCVSBK8o+LHZqPxDYVV4AvHO1TunGAFufOgcx7ZuzBL756rGNFgbCCYSGgwh6O+N25yP
+BPiNMV0dkhDGqz5YdihBFhKI9NUToeYnQgSwu71d8LnjybUa/XUY1iMBrA7BnCD4KrVck3wSyNWnppSu
+eUDe5EwmwE37zoRloz9WMfrr6lwQIkImHg6m8ev+g8qY7L7qQ21TElzKC4d8xQUvQq245YwXEFRfTLZE
+AtgdsgNG/9PK+sVXTN+034qGJTRLSYBzAi2eYEjHLCTQrqAKNBBPgC37JuGF4NtUjP4V0IVaEQckWIye
+4AL53Sb8QrGUG5LAn8dcpdFAPAEcchtscrt41Ed/aagBCbDspEuC4eoQwjjqXxrDmbxqNMAnwNQDCyzH
+2lG50Z8dJNXoKLIW4WZoODQgwXB1KFwtJUX4DpsSbtmEQax+0p1zCWDbzh/Bx+6/VffRX9fE3GcGIAHC
+dskgHEr7FqmvLoUXufRdobw6qoomwE33ngyu+w6pXd50SKm6TumYJoMgTDjUf4uU/41xeIzntVtER4ay
+6FoKHbag/yyaAJ2JLbDyc67MRlf6Rfa3IA4Wf7lCrphwSN1zgkJ6UptGwwT47J4Ji/TuqnvoU5gFByTo
+rw6l/6imMLlr2nCYAPPg7/o2xi4o41YntbGBFw6tcp8Yx02Ma9PnknbETwD82N1xpksqa73EMuFQKezp
+J8CrSy6Gzx3XlnmP/6DWip0GBqVJee2FQ6vIgpUmHEqpPSXZfQSwHft6WPpslfGDFyW9pZUUMHPmEpWG
+Q2swHDrf/aiGm5fKX5Lf/mO+kggjKcaQANv3tByb/G4VVn4k+xpZbDAIR97LLZHxBP3VIf4SqV+mbEwu
+Rd/9Hcr9akiAI+RceG4Pk1/6HnvusqhpMKfhU6YZLMMtN/AEp4MnWLDy/Jgd6MI1mC/E5KEzJECv+TsQ
+/pTye1/57qkpmW2cDcsQJAK9pkCeHJDArA6Fdac6xSMArP1vNWv/qtUbXx8Fvi8XDYdwTgATY/9HNezo
+r5qWPilG5sIjAHwVsqny4U/OZmPhqLTpQTjU9wR0dSi6Neo1lLY/QpUNCeA4M7r7rWvSFQ2NhN4wA6iI
+XEx2X8VSbftq4FwMhEISzHfnBOzcrC9NFvCL9JkjWa2ShwQgsFuWXa/tPitvqQFKF/vmBDwq5ttbXUug
+eRPTIwB89/tN2PA2Xy3qak1iWBZRPA96Es2J9xwEw/qDE+Mso7944/XP6REAFuj+G2ZcWm1ZOnXyEC0h
+qFbFDdjZXyIdflkmIaZbRITssnVXrdyQACdmD8Mq0HvwKkTV+pCrvHGcyYsE7hPjlFuz56qkCjU2RPu3
+7viAONYLsMNrhcQfihoCXyhhmJd3JjoyFkUCDHuwW5OXwsOyCy9I/fcJsN+ifeTpyK2D/zgvrlgp7w0J
+AOLB7m/f0i2lCgMolTEOzTENxRWT4F5MS/1bXp0DBbrhEJDA/5wgsZpSZygCGz4CkK71BHwE/+4oh0Fp
+jJBEAg+0GWCHdYTqGQiJE+PTLoQX6LxtGOMbStO3+Jrqc9dPgEdvfd9yev8Mr0RUsodhoAh2I4DkNEAJ
+FA01SAEcki2Uc5ggVGYgpLtEmoIEw1bkznQtf8pJk72UnwBQX89x/pF0Zz8YOS+QhOQYXYsWZYEddx7T
+lHfLbRNIgPUsducE+AId+7DMy+qepCG1v2S9r0IEII9O/w9Mtv5WpxfQaQwEhO8IJfjuci/SyihKAm6D
+KW742kISQB/RE/TDofCr1Gn7whNF5+ivSkae7Lz0MAEw57HevaQz+4JOEvAEKjTdh6z0KyZYPFCF0u5w
+60cSQEvuwzJcHYK/VEOPooBF2y/7bzQBHp8+5pDONOn1fl3Fp8OhQT+UEGOWAIJlAMQFakyzcbeE6hsI
+Sl+bwHBIRnaeHDpHf16beaRHEwBb3r/jJcdpT8OQ1tYxH1BpHOWKUkAClIkCN1CdkLhSZUGpyHUaDvUq
+8rCsSCzwCYBm2j/9qNPt3AWvSvd0kEAICZKZQoN+KEGyYsliLKBFziWbceM2BNTkapwTrIydGIu2UdfR
+H/sfTwDM8cj2LztOd0ACmbEMKynJkYYEga4iqIocqUQ12JeTeoJLyGmfrNfDMlE9iOZLJgDW9PC2+2Bi
+BSSwlXoC3YBKg/dIhdGhmrmpW2amqdSnPtngAt7whXCoTwJ2YpymYt2jv0/mNIIpyitGAGzsEY8E8Mdw
+xYspklNdNTKsiPAG6gRSU1MkkJAEUD2SAN8dintOoEaK6tWSDslIgl5b6Zwg0nAK9RiJ98jEhEYjSKBb
+9gSJ3NsoQ0gO1nPBTZcEl6YPh+o++qMC0xEAS+zffr/T69xZpYlxJN4jE7GDMUeABJgzEoAxVai6xW03
+QkYUEvOnCYd0g1+VHrLWk54A2KJHAltNOCQDxpQ9j2wiMjGhYnZ0ZbJyAcnkUXHKbYcjl9cmkgAuvHCI
+eVjm5RmcjAr4sbtyBMCSLgnUhkNYrc4jEu+RiQJSRI20UIwCFH9VHYl1cmQJtU9JgOGQ+z3B8IkxzZsX
++FXqh8ou8ytPAGxNoScoVCGyYKWjLgeALHDpeZKRaD72N7JMQtuRZTARKsa63SfGsEQquzrErb9iN7IR
+ADs79ARqwiHNCuRinXtDUCAKyITsLLCjzhOKDx8vJ2aMydBDEjh9EjCrQ6M2+qOGshMAa3FJ0IWJsaI5
+Adap8eBinXsjhTCUCByvkKKmYVaVddI+AgEoCdyHZd3wW6RDAdSdIenLdKghAPZo/7bd/dUheRLkqRtu
+W9wbEmZjgcue86pi87DnvPxp04N9G5Cg/xbpypEMh9QRAI3hkmAWl0ilw6GgjdLaOE1+blvcG2lqj8nL
+gps9jymS+RanT+6H9l44BO8OxawOZZWhbKM/9kctAbDG/dPgCdqZSIDV5HUgLiKxwb2Rl2SK2uH0w5c8
+8AT9t0jBE8R8WaZIqtJUo54A2DWXBPJzgkhAalYZt03uDc0CqaieI3tkMkuCT6oPh8o4+qOK9RAAa8Zw
+yGnfIRsORRoJ69V4cNvEG9ybGgWSrTpG3thuDEjQ321CXThUVvCjevURAGt/GF6l7nakSYBV5H3EYKdP
+glgE5S1toL0Y4WNu+SvxSHAJWQjfE9T9OYFeAqBq8XsCARLgZAzng+xRJNZi2xZGE9sbjecJ8sT2JUos
+lwT9b4zdj2oyTIzLPPpj1/UTAFtxP6qJ8QRgIVx9sK0gBYqNPBJwNfQIqRGGSsl4UOFi2qZZpFryPMEq
+shDmBDKvUpcd/KiXfAiALSWEQ912Bwigd1cFFEPmEAISzRQDSJm2fWUE26DZfGVlLigJVkM4dFE9w6H8
+CIAGQE/Q6+2Kmhi3T5wgDZhpIgmCh05MBduKuxYGFs3I/sZVHHWPLUvPo/IxaYLZmBICpy4JBt8YoycQ
+DIeqMPpj7/MlALa4f+ueEAkg9Jk5etwVBgVCQwaPqLRgnryupYBGC4n+pugMrTJFkXRZPU+A4dCFieFQ
+VcCPSsifANiqS4L20BMAAY4dOYYTAdKMcgFYBg40dJkOCrwi5Mq9bY8EGA5dyF0dqhL4EUvFEABb3j8N
+nmBAgkaDHPnwCOnMzJDxhuW+rotZoo4iwBYlRzCNBaQOGXXXH+xP5DVDgtPQEwTCoaqBH/tYHAGw9QEJ
+LHiLdObYCfLh+78m88aSRdIBMBRH5REEbPA62FbwfvA6mL+wa4YEGA7R5wRVBD/qMBltujWNJHDau5ye
+0/3pWz8j81p25EQ4KAYCpMpHaQEuolSGBK4nqPC7Q8UTABUOJIC4Z+c7b77T6Rw9SiaABCIAF8kjYk+T
+R0IDAxKcDkukp8XMCSRqzrVIOQiAXf6X6b0z776368cvv95dMLcVOw9gNWRIwGoj33P6KvVkhUlQHgKg
+7Z74wt63X3pt58yvPuhMzAESCNpTNJ9gdSabgAY8nbPhUAU9QbkIAIqf+dof7v35q4d3TfTaHQtWh0QP
+zyCiBUw+aQ2EdF1hEpSOAGiVN/9s497O+7/cNdGw4P0IQwJppGooGAI/baOiJCglAVCnL9x09t7W7LGd
+zYZtSEBBVvAvF/xUrgqSoLQEQJ1+95pT942T2Z0NOz0JEo1FjWZ+EzWAuhTWZ8VIUGoCoGVevGrevrHe
+7E47JQmwrLDRMLM5IjUgpcMKkaD0BECrfP/qeftaGUggZcRIOIxOIuosk94qQoJKEABh98MMJMDymYyJ
+FYzQoUxXQRJ02mCIHmiS0quIX78hm/7Lcl8hCS7+t+NO227uBjU23fdQIr4f4PUC1Z0iO6+aWqcrAz/V
+EmzDSCyHnL7qEmJ3j5OPXv4BvIDTLM4OIAv7538rRQDU6Q+vnvvA6idnSWNuazfpNZvwDhFVdapfQwS/
+uuS06K8j7sqCV97nf/py8u7csX/4xfPPPg8ojMuu716g2cri4IrnnK2kSXaDNwVPAPrK0JMMRfUZKoea
+dYPe1wVozJ4Dn3x0yA0H11qP+O4VeFE5D0B19dQG64FNz8FOEkgCG0iAoaXkgUAYNRLkCv6BXWBKgFOA
+Us07SyVMWvweAhI4HXI7qLST9e/2ISCKAEXaPmfNPyr9FNVTpQmAnRyQYIcKEmB9FCB1IkMd+4S2UnFU
+ngCoBCDBg84seAIruydglVpl4FRZdtYGus9rQQBU0qFPQTjUJTtgcaGdNRyKUnoVAFUFGaN0W2RabQiA
+SnQ9QVu9JwgaiAUanhd1lEWOovqvot1aEQAV4pIAPYGtxxNEKT0IRHodlVcmjdYX/JWpy5Txa6B2BMDu
+uSTA1SFN4ZBfhfyrIGBlr/ktmDtZNVBLAqBSkARkNl9PkNUYpnz+GqgtAVCVBzdaD5G2IUH+sKpOi7Um
+gCFBdYBYlKS1JwAlQdd4gqIwVup2R4IAaIFnIBwyJCg1FgsRbmQIYEhQCL5K3+hIEYCSAHZhn3afEwTe
+DS+9tYyAyjUwcgRADT693vpKrw0ksPJ7WKbccqZCJRoYSQKg5p7eOCBBjk+MlVjMVKJUAyNLANSiIYFS
+LFWyspEmgCFBJTGrVOiRJwAlAbxKvd1MjJViqxKVGQIMzHRovfVVb2JsVocqAV4VQhoCMFrEOYHrCczq
+EKOVep8aAgTsi57AhEMBpdT40hAgwrguCWZhToCewIRDERqqT5IhAMeW8I3xV+FDe0MCjn7qkmwIEGNJ
+lwQdsg0+sp81niBGURW+ZQiQYDz4suxrsDq0Hba2NCRI0FUVbxsCCFjNJUEHSGA8gYC2qpXFEEDQXi4J
+ZownEFRXZbIZAqQw1aHLIBw6MfAERnMpNFferJXdHboolSIJLn8e9jm2yR6YF4yPxI66ipSNO/Y5Vrk2
+4jYEkDDuwXXW1y/7jnMK/B3vL8JDs45EFSNZBHbybtoO+WgkO286bTRgNGA0YDRQMg38P1f9d+F9qq8M
+AAAAAElFTkSuQmCC
+''';
+
String _highlight_css;
// highlight_css md5 is 'fb012626bafd286510d32da815dae448'
String _highlight_css_base64 = '''
@@ -421,7 +581,7 @@
''';
String _index_html;
-// index_html md5 is 'b66394e479a3d5a43b260b7278cc74be'
+// index_html md5 is '803a2ed6c6547e0b448d0e28c28cf385'
String _index_html_base64 = '''
PGh0bWw+CjxoZWFkPgogICAgPHRpdGxlPk51bGwgU2FmZXR5IFByZXZpZXc8L3RpdGxlPgogICAgPHNj
cmlwdCBzcmM9Int7IGhpZ2hsaWdodEpzUGF0aCB9fSI+PC9zY3JpcHQ+CiAgICA8c2NyaXB0Pnt7IGRh
@@ -437,48 +597,49 @@
Zm9ybWF0ZWQgY29udGVudCBwbGFjZWhvbGRlciBlbGVtZW50IC0tPgogIDxhIGNsYXNzPSJidXR0b24g
Ym90dG9tIiB0YXJnZXQ9Il9ibGFuayI+RmlsZSBvbiBHaXRIdWI8L2E+PCEtLSBwb3N0IHRvIGdpdGh1
YiBwbGFjZWhvbGRlciBlbGVtZW50IC0tPgo8L2Rpdj4KPHAgY2xhc3M9InJvb3QiPnt7IHJvb3QgfX08
-L3A+CjxoZWFkZXIgY2xhc3M9ImVsZXZhdGlvbi16NCI+CiAgICA8aDEgY2xhc3M9ImJlZm9yZS1hcHBs
-eSI+UHJvcG9zZWQgbnVsbCBzYWZldHkgY2hhbmdlczwvaDE+CiAgICA8aDEgY2xhc3M9ImFmdGVyLWFw
-cGx5Ij4mIzEwMDAzOyBOdWxsIHNhZmV0eSBtaWdyYXRpb24gYXBwbGllZDwvaDE+CiAgICA8aDIgaWQ9
-InVuaXQtbmFtZSI+Jm5ic3A7PC9oMj4KICAgIDxidXR0b24gY2xhc3M9ImFwcGx5LW1pZ3JhdGlvbiI+
-JiM5OTk4OyBBcHBseSBNaWdyYXRpb248L2J1dHRvbj4KICAgIDxidXR0b24gY2xhc3M9ImFwcGx5LW1p
-Z3JhdGlvbiIgZGlzYWJsZWQ+JiM5OTk4OyBBcHBseSBNaWdyYXRpb248L2J1dHRvbj4KICAgIDxidXR0
-b24gY2xhc3M9InJlcnVuLW1pZ3JhdGlvbiBiZWZvcmUtYXBwbHkiPgogICAgICA8c3BhbiBjbGFzcz0i
-b3B0aW9uYWwiPiYjODYzNTsgUmVydW4gRnJvbSBTb3VyY2VzPC9zcGFuPgogICAgICA8c3BhbiBjbGFz
-cz0icmVxdWlyZWQiPgogICAgICAgIDxzcGFuIGNsYXNzPSJpY29uIiAKICAgICAgICAgIHRpdGxlPSJE
-aXNrIGNvbnRlbnRzIGhhdmUgY2hhbmdlZC4gUmVydW4gdG8gZ2V0IGFuIHVwLXRvLWRhdGUgbWlncmF0
-aW9uLiI+ITwvc3Bhbj4KICAgICAgICBSZXJ1biBXaXRoIENoYW5nZXMKICAgICAgPC9zcGFuPgogICAg
-PC9idXR0b24+CjwvaGVhZGVyPgo8ZGl2IGNsYXNzPSJwYW5lbHMgaG9yaXpvbnRhbCI+CiAgICA8ZGl2
-IGNsYXNzPSJuYXYtcGFuZWwiPgogICAgICAgIDxkaXYgY2xhc3M9Im5hdi1pbm5lciI+CiAgICAgICAg
-ICAgIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPlByb2plY3QgRmlsZXM8L2Rpdj4KICAgICAgICAg
-ICAgPGRpdiBjbGFzcz0ibmF2LXRyZWUiPjwvZGl2PgogICAgICAgIDwvZGl2PjwhLS0gL25hdi1pbm5l
-ciAtLT4KICAgIDwvZGl2PjwhLS0gL25hdiAtLT4KICAgIDxkaXYgY2xhc3M9ImNvbnRlbnQiPgogICAg
-ICAgIDxkaXYgY2xhc3M9InJlZ2lvbnMiPgogICAgICAgICAgICA8IS0tIFRoZSByZWdpb25zIG92ZXJs
-YXkgY29kZSBjb3B5IG9mIHRoZSBjb250ZW50IHRvIHByb3ZpZGUgLS0+CiAgICAgICAgICAgIDwhLS0g
-dG9vbHRpcHMgZm9yIG1vZGlmaWVkIHJlZ2lvbnMuIC0tPgogICAgICAgIDwvZGl2PjwhLS0gL3JlZ2lv
-bnMgLS0+CiAgICAgICAgPGRpdiBjbGFzcz0iY29kZSI+CiAgICAgICAgICAgIDwhLS0gQ29tcGlsYXRp
-b24gdW5pdCBjb250ZW50IGlzIHdyaXR0ZW4gaGVyZS4gLS0+CiAgICAgICAgICAgIDxwIGNsYXNzPSJ3
-ZWxjb21lIj4KICAgICAgICAgICAgICAgIFNlbGVjdCBhIHNvdXJjZSBmaWxlIG9uIHRoZSBsZWZ0IHRv
-IHByZXZpZXcgdGhlIHByb3Bvc2VkIGVkaXRzLgogICAgICAgICAgICA8L3A+CiAgICAgICAgPC9kaXY+
-CiAgICA8L2Rpdj48IS0tIC9jb250ZW50IC0tPgogICAgPGRpdiBjbGFzcz0iaW5mby1wYW5lbCI+CiAg
-ICAgICAgPGRpdiBjbGFzcz0iZWRpdC1saXN0Ij4KICAgICAgICAgICAgPGRpdiBjbGFzcz0icGFuZWwt
-aGVhZGluZyI+UHJvcG9zZWQgRWRpdHM8L2Rpdj4KICAgICAgICAgICAgPGRpdiBjbGFzcz0icGFuZWwt
-Y29udGVudCI+PC9kaXY+CiAgICAgICAgPC9kaXY+PCEtLSAvZWRpdC1saXN0IC0tPgogICAgICAgIDxk
-aXYgY2xhc3M9ImVkaXQtcGFuZWwiPgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJwYW5lbC1oZWFkaW5n
-Ij5FZGl0IERldGFpbHM8L2Rpdj4KICAgICAgICAgICAgPGRpdiBjbGFzcz0icGFuZWwtY29udGVudCI+
-CiAgICAgICAgICAgICAgICA8cCBjbGFzcz0icGxhY2Vob2xkZXIiPlNlZSBkZXRhaWxzIGFib3V0IGEg
-cHJvcG9zZWQgZWRpdC48L3A+CiAgICAgICAgICAgIDwvZGl2PjwhLS0gL3BhbmVsLWNvbnRlbnQgLS0+
-CiAgICAgICAgPC9kaXY+PCEtLSAvZWRpdC1wYW5lbCAtLT4KICAgIDwvZGl2PjwhLS0gL2luZm8tcGFu
-ZWwgLS0+CjwvZGl2PjwhLS0gL3BhbmVscyAtLT4KPGZvb3Rlcj4KICAgIDxhIHRhcmdldD0iX2JsYW5r
-IgogICAgICBocmVmPSJodHRwczovL2dvby5nbGUvZGFydC1udWxsLXNhZmV0eS1taWdyYXRpb24tdG9v
-bCI+TnVsbCBzYWZldHkKICAgICAgICBtaWdyYXRpb24gaGVscDwvYT4KICAgIDxzcGFuIGNsYXNzPSJ3
-aWRlIj4gPC9zcGFuPgogICAgPGRpdj5CYXNlZCBvbiA8c3BhbiBpZD0ic2RrLXZlcnNpb24iPnt7IHNk
-a1ZlcnNpb24gfX08L3NwYW4+PC9kaXY+CiAgICA8YnV0dG9uIGNsYXNzPSJyZXBvcnQtcHJvYmxlbSI+
-UmVwb3J0IGEgUHJvYmxlbTwvYnV0dG9uPgo8L2Zvb3Rlcj4KPC9ib2R5Pgo8L2h0bWw+Cg==
+L3A+CjxoZWFkZXIgY2xhc3M9ImVsZXZhdGlvbi16NCI+CiAgICA8aW1nIHNyYz0ie3sgZGFydExvZ29Q
+YXRoIH19IiBhbHQ9IkRhcnRQYWQgTG9nbyIgY2xhc3M9ImxvZ28iLz4KICAgIDxoMSBjbGFzcz0iYmVm
+b3JlLWFwcGx5Ij5Qcm9wb3NlZCBudWxsIHNhZmV0eSBjaGFuZ2VzPC9oMT4KICAgIDxoMSBjbGFzcz0i
+YWZ0ZXItYXBwbHkiPiYjMTAwMDM7IE51bGwgc2FmZXR5IG1pZ3JhdGlvbiBhcHBsaWVkPC9oMT4KICAg
+IDxoMiBpZD0idW5pdC1uYW1lIj4mbmJzcDs8L2gyPgogICAgPGJ1dHRvbiBjbGFzcz0iYXBwbHktbWln
+cmF0aW9uIj4mIzk5OTg7IEFwcGx5IE1pZ3JhdGlvbjwvYnV0dG9uPgogICAgPGJ1dHRvbiBjbGFzcz0i
+YXBwbHktbWlncmF0aW9uIiBkaXNhYmxlZD4mIzk5OTg7IEFwcGx5IE1pZ3JhdGlvbjwvYnV0dG9uPgog
+ICAgPGJ1dHRvbiBjbGFzcz0icmVydW4tbWlncmF0aW9uIGJlZm9yZS1hcHBseSI+CiAgICAgIDxzcGFu
+IGNsYXNzPSJvcHRpb25hbCI+JiM4NjM1OyBSZXJ1biBGcm9tIFNvdXJjZXM8L3NwYW4+CiAgICAgIDxz
+cGFuIGNsYXNzPSJyZXF1aXJlZCI+CiAgICAgICAgPHNwYW4gY2xhc3M9Imljb24iIAogICAgICAgICAg
+dGl0bGU9IkRpc2sgY29udGVudHMgaGF2ZSBjaGFuZ2VkLiBSZXJ1biB0byBnZXQgYW4gdXAtdG8tZGF0
+ZSBtaWdyYXRpb24uIj4hPC9zcGFuPgogICAgICAgIFJlcnVuIFdpdGggQ2hhbmdlcwogICAgICA8L3Nw
+YW4+CiAgICA8L2J1dHRvbj4KPC9oZWFkZXI+CjxkaXYgY2xhc3M9InBhbmVscyBob3Jpem9udGFsIj4K
+ICAgIDxkaXYgY2xhc3M9Im5hdi1wYW5lbCI+CiAgICAgICAgPGRpdiBjbGFzcz0ibmF2LWlubmVyIj4K
+ICAgICAgICAgICAgPGRpdiBjbGFzcz0icGFuZWwtaGVhZGluZyI+UHJvamVjdCBGaWxlczwvZGl2Pgog
+ICAgICAgICAgICA8ZGl2IGNsYXNzPSJuYXYtdHJlZSI+PC9kaXY+CiAgICAgICAgPC9kaXY+PCEtLSAv
+bmF2LWlubmVyIC0tPgogICAgPC9kaXY+PCEtLSAvbmF2IC0tPgogICAgPGRpdiBjbGFzcz0iY29udGVu
+dCI+CiAgICAgICAgPGRpdiBjbGFzcz0icmVnaW9ucyI+CiAgICAgICAgICAgIDwhLS0gVGhlIHJlZ2lv
+bnMgb3ZlcmxheSBjb2RlIGNvcHkgb2YgdGhlIGNvbnRlbnQgdG8gcHJvdmlkZSAtLT4KICAgICAgICAg
+ICAgPCEtLSB0b29sdGlwcyBmb3IgbW9kaWZpZWQgcmVnaW9ucy4gLS0+CiAgICAgICAgPC9kaXY+PCEt
+LSAvcmVnaW9ucyAtLT4KICAgICAgICA8ZGl2IGNsYXNzPSJjb2RlIj4KICAgICAgICAgICAgPCEtLSBD
+b21waWxhdGlvbiB1bml0IGNvbnRlbnQgaXMgd3JpdHRlbiBoZXJlLiAtLT4KICAgICAgICAgICAgPHAg
+Y2xhc3M9IndlbGNvbWUiPgogICAgICAgICAgICAgICAgU2VsZWN0IGEgc291cmNlIGZpbGUgb24gdGhl
+IGxlZnQgdG8gcHJldmlldyB0aGUgcHJvcG9zZWQgZWRpdHMuCiAgICAgICAgICAgIDwvcD4KICAgICAg
+ICA8L2Rpdj4KICAgIDwvZGl2PjwhLS0gL2NvbnRlbnQgLS0+CiAgICA8ZGl2IGNsYXNzPSJpbmZvLXBh
+bmVsIj4KICAgICAgICA8ZGl2IGNsYXNzPSJlZGl0LWxpc3QiPgogICAgICAgICAgICA8ZGl2IGNsYXNz
+PSJwYW5lbC1oZWFkaW5nIj5Qcm9wb3NlZCBFZGl0czwvZGl2PgogICAgICAgICAgICA8ZGl2IGNsYXNz
+PSJwYW5lbC1jb250ZW50Ij48L2Rpdj4KICAgICAgICA8L2Rpdj48IS0tIC9lZGl0LWxpc3QgLS0+CiAg
+ICAgICAgPGRpdiBjbGFzcz0iZWRpdC1wYW5lbCI+CiAgICAgICAgICAgIDxkaXYgY2xhc3M9InBhbmVs
+LWhlYWRpbmciPkVkaXQgRGV0YWlsczwvZGl2PgogICAgICAgICAgICA8ZGl2IGNsYXNzPSJwYW5lbC1j
+b250ZW50Ij4KICAgICAgICAgICAgICAgIDxwIGNsYXNzPSJwbGFjZWhvbGRlciI+U2VlIGRldGFpbHMg
+YWJvdXQgYSBwcm9wb3NlZCBlZGl0LjwvcD4KICAgICAgICAgICAgPC9kaXY+PCEtLSAvcGFuZWwtY29u
+dGVudCAtLT4KICAgICAgICA8L2Rpdj48IS0tIC9lZGl0LXBhbmVsIC0tPgogICAgPC9kaXY+PCEtLSAv
+aW5mby1wYW5lbCAtLT4KPC9kaXY+PCEtLSAvcGFuZWxzIC0tPgo8Zm9vdGVyPgogICAgPGEgdGFyZ2V0
+PSJfYmxhbmsiCiAgICAgIGhyZWY9Imh0dHBzOi8vZ29vLmdsZS9kYXJ0LW51bGwtc2FmZXR5LW1pZ3Jh
+dGlvbi10b29sIj5OdWxsIHNhZmV0eQogICAgICAgIG1pZ3JhdGlvbiBoZWxwPC9hPgogICAgPHNwYW4g
+Y2xhc3M9IndpZGUiPiA8L3NwYW4+CiAgICA8ZGl2PkJhc2VkIG9uIDxzcGFuIGlkPSJzZGstdmVyc2lv
+biI+e3sgc2RrVmVyc2lvbiB9fTwvc3Bhbj48L2Rpdj4KICAgIDxidXR0b24gY2xhc3M9InJlcG9ydC1w
+cm9ibGVtIj5SZXBvcnQgYSBQcm9ibGVtPC9idXR0b24+CjwvZm9vdGVyPgo8L2JvZHk+CjwvaHRtbD4K
''';
String _migration_css;
-// migration_css md5 is 'e7d5579e5a4661f81ce5734eff427a6d'
+// migration_css md5 is 'e6730f8303d73cb852f1717cb20e6c98'
String _migration_css_base64 = '''
LyogQ29weXJpZ2h0IChjKSAyMDE5LCB0aGUgRGFydCBwcm9qZWN0IGF1dGhvcnMuIFBsZWFzZSBzZWUg
dGhlIEFVVEhPUlMgZmlsZSAgKi8KLyogZm9yIGRldGFpbHMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuIFVz
@@ -500,138 +661,140 @@
MDA7CiAgbWFyZ2luLXJpZ2h0OiAyNHB4Owp9CgpoMSB7CiAgZm9udC1zaXplOiAxLjVlbTsKfQoKaGVh
ZGVyIGgyIHsKICBmb250LXNpemU6IDEuMmVtOwp9CgpoZWFkZXIgLmFwcGx5LW1pZ3JhdGlvbiwgLnJl
cnVuLW1pZ3JhdGlvbiB7CiAgcmlnaHQ6IDBweDsKICBmbG9hdDogcmlnaHQ7CiAgbWFyZ2luOiAxMHB4
-Owp9Cgpmb290ZXIgLnJlcG9ydC1wcm9ibGVtIHsKICByaWdodDogMHB4OwogIG1hcmdpbjogNHB4IDhw
-eDsKfQoKLnJlcnVuLW1pZ3JhdGlvbiAucmVxdWlyZWQgewogIGRpc3BsYXk6IG5vbmU7Cn0KCi5uZWVk
-cy1yZXJ1biAucmVydW4tbWlncmF0aW9uIC5yZXF1aXJlZCB7CiAgZGlzcGxheTogaW5pdGlhbDsKfQoK
-Lm5lZWRzLXJlcnVuIC5yZXJ1bi1taWdyYXRpb24gLm9wdGlvbmFsIHsKICBkaXNwbGF5Om5vbmU7Cn0K
-Ci8qIFJlZCB0cmlhbmdsZSAqLwoucmVydW4tbWlncmF0aW9uIC5yZXF1aXJlZCAuaWNvbjo6YmVmb3Jl
-IHsKICB0cmFuc2Zvcm06IHRyYW5zbGF0ZSgtOHB4LCAtMTFweCk7CiAgY29udGVudDogJ1wyNUIzJzsK
-ICBmb250LXNpemU6IDI1cHg7CiAgcG9zaXRpb246IGZpeGVkOwogIGNvbG9yOiAjZTgyYzJjOwogIHRl
-eHQtc2hhZG93OiAwcHggMHB4IDVweCB3aGl0ZTsKICB6LWluZGV4OiAtMzsKfQoKLyogUmVkIHRyaWFu
-Z2xlIGZpbGwgKi8KLnJlcnVuLW1pZ3JhdGlvbiAucmVxdWlyZWQgLmljb246OmFmdGVyIHsKICB0cmFu
-c2Zvcm06IHRyYW5zbGF0ZSgtOXB4LCAtMTBweCk7CiAgY29udGVudDogJ1wyNUI0JzsKICBmb250LXNp
-emU6IDI1cHg7CiAgcG9zaXRpb246IGZpeGVkOwogIGNvbG9yOiAjYjNlY2ZmOwogIHotaW5kZXg6IC0x
-Owp9CgovKiBSZWQgdHJpYW5nbGUgZXhjbGFtYXRpb24gKi8KLnJlcnVuLW1pZ3JhdGlvbiAucmVxdWly
-ZWQgLmljb24gewogIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICBtYXJnaW4tcmlnaHQ6IDhweDsKICB0
-cmFuc2Zvcm06IHRyYW5zbGF0ZSgwcHgsIDJweCk7CiAgbWFyZ2luLWxlZnQ6IDJweDsKICBjb2xvcjog
-IzJiMmIyYjsKfQoKZm9vdGVyIHsKICBjb2xvcjogI2NjYzsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjcz
-MjNhOwogIGRpc3BsYXk6IGZsZXg7CiAgZmxleC1kaXJlY3Rpb246IHJvdzsKICBhbGlnbi1pdGVtczog
-Y2VudGVyOwogIHBhZGRpbmc6IDhweCAwIDhweCAyNHB4Owp9Cgpmb290ZXIgLndpZGUgewogIGZsZXg6
-IDE7Cn0KCi5ob3Jpem9udGFsIHsKICBkaXNwbGF5OiBmbGV4Owp9CgoucGFuZWxzIHsKICBiYWNrZ3Jv
-dW5kLWNvbG9yOiAjMTIxYTI1OwogIGZsZXg6IDE7CiAgb3ZlcmZsb3c6IGhpZGRlbjsKfQoKLnBhbmVs
-LWhlYWRpbmcgewogIGNvbG9yOiBncmF5OwogIG1hcmdpbjogOHB4Owp9CgoubmF2LWxpbmssCi5yZWdp
-b24gewogIGN1cnNvcjogcG9pbnRlcjsKfQoKLm5hdi1wYW5lbCB7CiAgYmFja2dyb3VuZC1jb2xvcjog
-IzI4MmIyZTsKICBmbGV4OiAxIDIwMHB4OwogIG1hcmdpbjogMDsKICBvdmVyZmxvdzogc2Nyb2xsOwp9
-CgoubmF2LWlubmVyIHsKICBwYWRkaW5nOiAwIDAgN3B4IDdweDsKfQoKLmZpeGVkIHsKICBwb3NpdGlv
-bjogZml4ZWQ7CiAgdG9wOiAwOwp9Cgoucm9vdCB7CiAgbWFyZ2luOiAwOwogIGRpc3BsYXk6IG5vbmU7
-Cn0KCi5uYXYtdHJlZSA+IHVsIHsKICBwYWRkaW5nLWxlZnQ6IDZweDsKfQoKLm5hdi1pbm5lciB1bCB7
-CiAgcGFkZGluZy1sZWZ0OiAxMnB4OwogIG1hcmdpbjogMDsKfQoKLm5hdi1pbm5lciBsaSB7CiAgbGlz
-dC1zdHlsZS10eXBlOiBub25lOwp9CgoubmF2LWlubmVyIGxpOm5vdCguZGlyKSB7CiAgbWFyZ2luLWxl
-ZnQ6IDIwcHg7CiAgbWFyZ2luLWJvdHRvbTogM3B4Owp9CgoubmF2LWlubmVyIGxpLmRpciAuYXJyb3cg
-ewogIGN1cnNvcjogcG9pbnRlcjsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAgZm9udC1zaXplOiAx
-MHB4OwogIG1hcmdpbi1yaWdodDogNHB4OwogIHRyYW5zaXRpb246IHRyYW5zZm9ybSAwLjVzIGVhc2Ut
-b3V0Owp9CgoubmF2LWlubmVyIGxpLmRpciAuYXJyb3cuY29sbGFwc2VkIHsKICB0cmFuc2Zvcm06IHJv
-dGF0ZSgtOTBkZWcpOwp9CgoubmF2LWlubmVyIHVsIHsKICBtYXgtaGVpZ2h0OiAyMDAwcHg7CiAgdHJh
-bnNpdGlvbjogbWF4LWhlaWdodCAwLjVzIGVhc2Utb3V0Owp9CgoubmF2LWlubmVyIHVsLmNvbGxhcHNl
-ZCB7CiAgbWF4LWhlaWdodDogMCAhaW1wb3J0YW50OwogIG92ZXJmbG93OiBoaWRkZW47Cn0KCi5uYXYt
-aW5uZXIgLnNlbGVjdGVkLWZpbGUgewogIGNvbG9yOiB3aGl0ZTsKICBjdXJzb3I6IGluaGVyaXQ7CiAg
-Zm9udC13ZWlnaHQ6IDYwMDsKICB0ZXh0LWRlY29yYXRpb246IG5vbmU7Cn0KCi5lZGl0LWNvdW50IHsK
-ICBiYWNrZ3JvdW5kLWNvbG9yOiAjMzdhZWRjOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7CiAgY29sb3I6
-ICMwMDAwMDA7CiAgZGlzcGxheTogaW5saW5lLWJsb2NrOwogIGZvbnQtc2l6ZTogMTFweDsKICBmb250
-LXdlaWdodDogNjAwOwogIG1hcmdpbi1sZWZ0OiA1cHg7CiAgbWluLXdpZHRoOiAyNXB4OwogIHBhZGRp
-bmc6IDRweCAwIDJweCAwOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBsaW5lLWhlaWdodDogMWVtOwp9
-CgouY29udGVudCB7CiAgZmxleDogNCAzMDBweDsKICBiYWNrZ3JvdW5kOiAjMjgyYjJlOwogIGZvbnQt
-ZmFtaWx5OiBtb25vc3BhY2U7CiAgbWFyZ2luOiAwIDZweDsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAg
-d2hpdGUtc3BhY2U6IHByZTsKICBvdmVyZmxvdzogc2Nyb2xsOwp9CgouY29kZSB7CiAgcGFkZGluZzog
-MC41ZW07CiAgcG9zaXRpb246IGFic29sdXRlOwogIGxlZnQ6IDA7CiAgdG9wOiAwOwogIG1hcmdpbi1s
-ZWZ0OiA1NnB4Owp9CgouaGxqcyB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzI4MmIyZTsKICBkaXNwbGF5
-OiBibG9jazsKICBvdmVyZmxvdy14OiBhdXRvOwogIHBhZGRpbmc6IDAuNWVtOwp9CgouY29kZSAud2Vs
-Y29tZSB7CiAgZm9udC1mYW1pbHk6ICJHb29nbGUgU2FucyIsIlJvYm90byIsc2Fucy1zZXJpZjsKICBm
-b250LXNpemU6IDE4cHg7CiAgbWFyZ2luLXJpZ2h0OiA2MnB4OwogIGNvbG9yOiAjNzc3Owp9CgouY29k
-ZSAubmF2LWxpbmsgewogIGNvbG9yOiBpbmhlcml0OwogIHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25l
-Owp9CgouY29kZSAubmF2LWxpbms6dmlzaXRlZCB7CiAgY29sb3I6IGluaGVyaXQ7CiAgdGV4dC1kZWNv
-cmF0aW9uLWxpbmU6IG5vbmU7Cn0KCi5jb2RlIC5uYXYtbGluazpob3ZlciB7CiAgdGV4dC1kZWNvcmF0
-aW9uLWxpbmU6IHVuZGVybGluZTsKICBmb250LXdlaWdodDogNjAwOwp9CgoucmVnaW9ucyB7CiAgcGFk
-ZGluZzogMC41ZW07CiAgcG9zaXRpb246IGFic29sdXRlOwogIGxlZnQ6IDA7CiAgdG9wOiAwOwp9Cgou
-cmVnaW9ucyB0YWJsZSB7CiAgYm9yZGVyLXNwYWNpbmc6IDA7CiAgZm9udC1zaXplOiBpbmhlcml0Owp9
-CgoucmVnaW9ucyB0ZCB7CiAgYm9yZGVyOiBub25lOwogIC8qIFRoZSBjb250ZW50IG9mIHRoZSByZWdp
-b25zIGlzIG5vdCB2aXNpYmxlOyB0aGUgdXNlciBpbnN0ZWFkIHdpbGwgc2VlIHRoZQogICAqIGhpZ2hs
-aWdodGVkIGNvcHkgb2YgdGhlIGNvbnRlbnQuICovCiAgY29sb3I6IHJnYmEoMjU1LCAyNTUsIDI1NSwg
-MCk7CiAgcGFkZGluZzogMDsKICB3aGl0ZS1zcGFjZTogcHJlOwp9CgoucmVnaW9ucyB0ZDplbXB0eTph
-ZnRlciB7CiAgY29udGVudDogIlwwMGEwIjsKfQoKLnJlZ2lvbnMgdHIuaGlnaGxpZ2h0IHRkOmxhc3Qt
-Y2hpbGQgewogIGJhY2tncm91bmQtY29sb3I6ICM0NDQ0NDQ7CiAgY29sb3I6IHdoaXRlOwp9CgoucmVn
-aW9ucyB0ZC5saW5lLW5vIHsKICBib3JkZXItcmlnaHQ6IHNvbGlkICMyODJiMmUgMnB4OwogIGNvbG9y
-OiAjOTk5OTk5OwogIHBhZGRpbmctcmlnaHQ6IDRweDsKICB0ZXh0LWFsaWduOiByaWdodDsKICB2aXNp
-YmlsaXR5OiB2aXNpYmxlOwogIHdpZHRoOiA1MHB4OwogIGRpc3BsYXk6IGlubGluZS1ibG9jazsKfQoK
-LnJlZ2lvbnMgdHIuaGlnaGxpZ2h0IHRkLmxpbmUtbm8gewogIGJvcmRlci1yaWdodDogc29saWQgI2Nj
-YyAycHg7Cn0KCi5yZWdpb24gewogIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICBwb3NpdGlvbjogcmVs
-YXRpdmU7CiAgdmlzaWJpbGl0eTogdmlzaWJsZTsKICB6LWluZGV4OiAyMDA7Cn0KCi5yZWdpb24uYWRk
-ZWQtcmVnaW9uIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjY2NmZmNjOwogIGNvbG9yOiAjMDAzMzAwOwp9
-CgoucmVnaW9uLnJlbW92ZWQtcmVnaW9uIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjZmY2NjY2OwogIGNv
-bG9yOiAjMDAxMTAwOwp9CgoucmVnaW9uLmluZm9ybWF0aXZlLXJlZ2lvbiB7CiAgYmFja2dyb3VuZC1j
-b2xvcjogIzQwNDU0OTsgLyogIzI4MmIyZSwgbGlnaHRlbmVkIDEwJSAqLwogIGJvcmRlci1ib3R0b206
-IHNvbGlkIHJnYmEoMjU1LCAyNTUsIDAsIDAuNykgMXB4OwogIGRpc3BsYXk6IGlubGluZS1ibG9jazsK
-ICBoZWlnaHQ6IDE0cHg7IAogIHBvc2l0aW9uOiByZWxhdGl2ZTsKICB0b3A6IDFweDsKfQoKLnRhcmdl
-dCB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzQ0NDsKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgdmlzaWJp
-bGl0eTogdmlzaWJsZTsKICBmb250LXdlaWdodDogNjAwOwp9CgouaW5mby1wYW5lbCB7CiAgZmxleDog
-MSAyMDBweDsKICBtYXJnaW46IDA7CiAgaGVpZ2h0OiAxMDAlOwogIGRpc3BsYXk6IGZsZXg7CiAgZmxl
-eC1kaXJlY3Rpb246IGNvbHVtbjsKfQoKLmluZm8tcGFuZWwgLmVkaXQtcGFuZWwgewogIGJhY2tncm91
-bmQtY29sb3I6ICMyODJiMmU7CiAgb3ZlcmZsb3c6IGF1dG87Cn0KCi5pbmZvLXBhbmVsIC5wYW5lbC1j
-b250ZW50IHsKICBwYWRkaW5nOiA3cHg7Cn0KCi5pbmZvLXBhbmVsIC5wYW5lbC1jb250ZW50PiA6Zmly
-c3QtY2hpbGQgewogIG1hcmdpbi10b3A6IDA7Cn0KCi5pbmZvLXBhbmVsIC5ub3dyYXAgewogIHdoaXRl
-LXNwYWNlOiBub3dyYXA7Cn0KCi5pbmZvLXBhbmVsIHVsLAouaW5mby1wYW5lbCBvbCB7CiAgcGFkZGlu
-Zy1sZWZ0OiAyMHB4Owp9CgouaW5mby1wYW5lbCBsaSB7CiAgbWFyZ2luOiAwIDAgNXB4IDA7Cn0KCi5p
-bmZvLXBhbmVsIGEgewogIGNvbG9yOiAjMzNjY2ZmOwp9CgouaW5mby1wYW5lbCAuZWRpdC1saXN0IHsK
-ICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjgyYjJlOwogIG92ZXJmbG93OiBhdXRvOwp9CgouZWRpdC1wYW5l
-bCB7CiAgbWFyZ2luLXRvcDogNnB4OwogIGZsZXg6IDEgMTAwcHg7Cn0KCi5lZGl0LWxpc3QgewogIGZs
-ZXg6IDIgMTAwcHg7Cn0KCi5lZGl0LWxpc3QgLmVkaXQgewogIG1hcmdpbjogM3B4IDA7Cn0KCi5lZGl0
-LWxpc3QgLmVkaXQtbGluayB7CiAgY3Vyc29yOiBwb2ludGVyOwp9CgoucG9wdXAtcGFuZSB7CiAgZGlz
-cGxheTogbm9uZTsKICBwb3NpdGlvbjogZml4ZWQ7CiAgdG9wOiAxNTBweDsKICBsZWZ0OiAxNTBweDsK
-ICByaWdodDogMTUwcHg7CiAgYm90dG9tOiAxNTBweDsKICBib3JkZXI6IDFweCBzb2xpZCBibGFjazsK
-ICBib3JkZXItdG9wOiAycHggc29saWQgYmxhY2s7CiAgYm9yZGVyLXJhZGl1czogN3B4OwogIGJveC1z
-aGFkb3c6IDBweCAwcHggMjBweCAycHggI2I0YmZjYjIyOwogIHotaW5kZXg6IDQwMDsKICBiYWNrZ3Jv
-dW5kOiAjMmIzMDM2OwogIHBhZGRpbmc6IDIwcHg7Cn0KCi5wb3B1cC1wYW5lIC5jbG9zZSB7CiAgcG9z
-aXRpb246IGFic29sdXRlOwogIHJpZ2h0OiAxMHB4OwogIHRvcDogMTBweDsKICBjdXJzb3I6IHBvaW50
-ZXI7CiAgdGV4dC1zaGFkb3c6IDFweCAxcHggMnB4ICM4ODg7CiAgYm94LXNoYWRvdzogMXB4IDFweCAy
-cHggIzExMTsKfQoKLnBvcHVwLXBhbmUgaDIgewogIHBhZGRpbmc6IDIxcHg7CiAgaGVpZ2h0OiAxMCU7
-CiAgbWFyZ2luOiAwcHg7CiAgYm94LXNpemluZzogYm9yZGVyLWJveDsKfQoKLnBvcHVwLXBhbmUgcCB7
-CiAgaGVpZ2h0OiAxMCU7CiAgYm94LXNpemluZzogYm9yZGVyLWJveDsKICBwYWRkaW5nOiAwcHggMjBw
-eDsKfQoKLnBvcHVwLXBhbmUgcHJlIHsKICBiYWNrZ3JvdW5kOiAjMjgyYjJlOwogIHBhZGRpbmc6IDIw
-cHg7CiAgYm90dG9tOiAwcHg7CiAgb3ZlcmZsb3c6IGF1dG8gc2Nyb2xsOwogIGhlaWdodDogNjUlOwog
-IG1hcmdpbjogMHB4OwogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7Cn0KCi5wb3B1cC1wYW5lIC5idXR0
-b24uYm90dG9tIHsKICBtYXJnaW46IDIwcHggMHB4OwogIGRpc3BsYXk6IGJsb2NrOwogIHRleHQtYWxp
-Z246IGNlbnRlcjsKfQoKLnJlcnVubmluZy1wYW5lIHsKICBkaXNwbGF5OiBub25lOwp9Cgpib2R5LnJl
-cnVubmluZyAucmVydW5uaW5nLXBhbmUgewogIGRpc3BsYXk6IGJsb2NrOwogIHBvc2l0aW9uOiBmaXhl
-ZDsKICB0b3A6IDBweDsKICBib3R0b206IDBweDsKICBsZWZ0OiAwcHg7CiAgcmlnaHQ6IDBweDsKICBi
-YWNrZ3JvdW5kLWNvbG9yOiAjMDAwMDAwQUE7IC8qIHRyYW5zbHVjZW50IGJsYWNrICovCiAgei1pbmRl
-eDogNDAwOwp9CgoucmVydW5uaW5nLXBhbmUgaDEgewogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICB0b3A6
-IDUwJTsKICBsZWZ0OiA1MCU7CiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTUwJSwgLTUwJSk7Cn0KCi5l
-ZGl0LXBhbmVsIC50eXBlLWRlc2NyaXB0aW9uIHsKICAvKiBGcm9tIEhMSlMncyAuaGxqcy1rZXl3b3Jk
-LCAuaGxqcy1zZWxlY3Rvci10YWcsIC5obGpzLWRlbGV0aW9uICovCiAgY29sb3I6ICNjYzc4MzI7CiAg
-Zm9udC1mYW1pbHk6IG1vbm9zcGFjZTsKfQoKdWwudHJhY2UgewogIGZvbnQtc2l6ZTogMTNweDsKICBs
-aXN0LXN0eWxlLXR5cGU6IG5vbmU7CiAgcGFkZGluZy1sZWZ0OiAwcHg7Cn0KCnVsLnRyYWNlIGxpIHsK
-ICBjb2xvcjogd2hpdGU7Cn0KCnVsLnRyYWNlIGxpIC5mdW5jdGlvbiB7CiAgLyogRnJvbSBITEpTJ3Mg
-LmhsanMtc2VjdGlvbiwgLmhsanMtdGl0bGUsIC5obGpzLXR5cGUgKi8KICBjb2xvcjogI2ZmYzY2ZDsK
-ICBmb250LWZhbWlseTogbW9ub3NwYWNlOwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCnVsLnRyYWNlIGxp
-IHAuZHJhd2VyIHsKICBtYXJnaW46IDNweCAwcHg7CiAgcGFkZGluZzogMHB4IDBweCAwcHggMTRweDsK
-fQoKdWwudHJhY2UgbGkgcC5kcmF3ZXIgYnV0dG9uIHsKICBtYXJnaW4tcmlnaHQ6IDNweDsKfQoKLmVs
-ZXZhdGlvbi16NCB7CiAgYm94LXNoYWRvdzogMHB4IDJweCA0cHggLTFweCByZ2JhKDAsIDAsIDAsIDAu
-MiksCiAgICAgIDBweCA0cHggNXB4IDBweCByZ2JhKDAsIDAsIDAsIDAuMTQpLAogICAgICAwcHggMXB4
-IDEwcHggMHB4IHJnYmEoMCwgMCwgMCwgLjEyKTsKfQoKYSB7CiAgY29sb3I6ICNjY2M7CiAgZmlsbDog
-I2NjYzsKICB0ZXh0LWRlY29yYXRpb246IG5vbmU7Cn0KCmE6aG92ZXIgewogIGNvbG9yOiAjZmZmOwog
-IGZpbGw6ICNmZmY7Cn0KCi5hZGQtaGludC1saW5rIHsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAg
-bWFyZ2luOiAzcHg7Cn0KCi8qIENhcmVmdWwgaGVyZS4gYGEuYnV0dG9uYCBpcyByZXBldGl0aXZlIGJ1
-dCByZXF1aXJlZCB0byBnZXQgY29ycmVjdAogKiBzcGVjaWZpY2l0eSAqLwpidXR0b24sIC5idXR0b24s
-IGEuYnV0dG9uIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMzNjY2ZmOwogIGJvcmRlcjogMnB4IHNvbGlk
-ICMzN2FlZGM7CiAgYm9yZGVyLXJhZGl1czogM3B4OwogIHBhZGRpbmc6IDZweCAxMHB4OwogIGZvbnQt
-d2VpZ2h0OiBib2xkOwogIGNvbG9yOiAjMjgyODI4Owp9CgpidXR0b246aG92ZXIsIC5idXR0b246aG92
-ZXIgewogIGJhY2tncm91bmQtY29sb3I6ICM4MGRmZmY7CiAgYm9yZGVyOiAycHggc29saWQgIzUyYjhl
-MDsKICBjdXJzb3I6IHBvaW50ZXI7Cn0KCmJ1dHRvbltkaXNhYmxlZF0gewogIGJhY2tncm91bmQtY29s
-b3I6ICM3YWE4Yjg7CiAgY29sb3I6ICM1MDcxNzc7CiAgYm9yZGVyOiAycHggc29saWQgIzUwNzE3NzsK
-ICBjdXJzb3I6IG5vdC1hbGxvd2VkOwp9CgoucGxhY2Vob2xkZXIgewogIGNvbG9yOiAjNzc3OwogIHRl
-eHQtYWxpZ246IGNlbnRlcjsKICBtYXJnaW4tdG9wOiAzZW0gIWltcG9ydGFudDsKfQoKLyoqCiAqIEhM
-SlMgT3ZlcnJpZGVzCiAqLwouaGxqcyB7CiAgLyoqCiAgICogVGhpcyBhbGxvd3MgdGhlIHBlci1saW5l
-IGhpZ2hsaWdodHMgdG8gc2hvdy4KICAgKi8KICBiYWNrZ3JvdW5kOiBub25lOwp9Cg==
+Owp9CgpoZWFkZXIgaW1nLmxvZ28gewogIGhlaWdodDogMjRweDsKICB3aWR0aDogMjRweDsKICBtYXJn
+aW4tcmlnaHQ6IDhweDsKfQoKZm9vdGVyIC5yZXBvcnQtcHJvYmxlbSB7CiAgcmlnaHQ6IDBweDsKICBt
+YXJnaW46IDRweCA4cHg7Cn0KCi5yZXJ1bi1taWdyYXRpb24gLnJlcXVpcmVkIHsKICBkaXNwbGF5OiBu
+b25lOwp9CgoubmVlZHMtcmVydW4gLnJlcnVuLW1pZ3JhdGlvbiAucmVxdWlyZWQgewogIGRpc3BsYXk6
+IGluaXRpYWw7Cn0KCi5uZWVkcy1yZXJ1biAucmVydW4tbWlncmF0aW9uIC5vcHRpb25hbCB7CiAgZGlz
+cGxheTpub25lOwp9CgovKiBSZWQgdHJpYW5nbGUgKi8KLnJlcnVuLW1pZ3JhdGlvbiAucmVxdWlyZWQg
+Lmljb246OmJlZm9yZSB7CiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLThweCwgLTExcHgpOwogIGNvbnRl
+bnQ6ICdcMjVCMyc7CiAgZm9udC1zaXplOiAyNXB4OwogIHBvc2l0aW9uOiBmaXhlZDsKICBjb2xvcjog
+I2U4MmMyYzsKICB0ZXh0LXNoYWRvdzogMHB4IDBweCA1cHggd2hpdGU7CiAgei1pbmRleDogLTM7Cn0K
+Ci8qIFJlZCB0cmlhbmdsZSBmaWxsICovCi5yZXJ1bi1taWdyYXRpb24gLnJlcXVpcmVkIC5pY29uOjph
+ZnRlciB7CiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoLTlweCwgLTEwcHgpOwogIGNvbnRlbnQ6ICdcMjVC
+NCc7CiAgZm9udC1zaXplOiAyNXB4OwogIHBvc2l0aW9uOiBmaXhlZDsKICBjb2xvcjogI2IzZWNmZjsK
+ICB6LWluZGV4OiAtMTsKfQoKLyogUmVkIHRyaWFuZ2xlIGV4Y2xhbWF0aW9uICovCi5yZXJ1bi1taWdy
+YXRpb24gLnJlcXVpcmVkIC5pY29uIHsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAgbWFyZ2luLXJp
+Z2h0OiA4cHg7CiAgdHJhbnNmb3JtOiB0cmFuc2xhdGUoMHB4LCAycHgpOwogIG1hcmdpbi1sZWZ0OiAy
+cHg7CiAgY29sb3I6ICMyYjJiMmI7Cn0KCmZvb3RlciB7CiAgY29sb3I6ICNjY2M7CiAgYmFja2dyb3Vu
+ZC1jb2xvcjogIzI3MzIzYTsKICBkaXNwbGF5OiBmbGV4OwogIGZsZXgtZGlyZWN0aW9uOiByb3c7CiAg
+YWxpZ24taXRlbXM6IGNlbnRlcjsKICBwYWRkaW5nOiA4cHggMCA4cHggMjRweDsKfQoKZm9vdGVyIC53
+aWRlIHsKICBmbGV4OiAxOwp9CgouaG9yaXpvbnRhbCB7CiAgZGlzcGxheTogZmxleDsKfQoKLnBhbmVs
+cyB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzEyMWEyNTsKICBmbGV4OiAxOwogIG92ZXJmbG93OiBoaWRk
+ZW47Cn0KCi5wYW5lbC1oZWFkaW5nIHsKICBjb2xvcjogZ3JheTsKICBtYXJnaW46IDhweDsKfQoKLm5h
+di1saW5rLAoucmVnaW9uIHsKICBjdXJzb3I6IHBvaW50ZXI7Cn0KCi5uYXYtcGFuZWwgewogIGJhY2tn
+cm91bmQtY29sb3I6ICMyODJiMmU7CiAgZmxleDogMSAyMDBweDsKICBtYXJnaW46IDA7CiAgb3ZlcmZs
+b3c6IHNjcm9sbDsKfQoKLm5hdi1pbm5lciB7CiAgcGFkZGluZzogMCAwIDdweCA3cHg7Cn0KCi5maXhl
+ZCB7CiAgcG9zaXRpb246IGZpeGVkOwogIHRvcDogMDsKfQoKLnJvb3QgewogIG1hcmdpbjogMDsKICBk
+aXNwbGF5OiBub25lOwp9CgoubmF2LXRyZWUgPiB1bCB7CiAgcGFkZGluZy1sZWZ0OiA2cHg7Cn0KCi5u
+YXYtaW5uZXIgdWwgewogIHBhZGRpbmctbGVmdDogMTJweDsKICBtYXJnaW46IDA7Cn0KCi5uYXYtaW5u
+ZXIgbGkgewogIGxpc3Qtc3R5bGUtdHlwZTogbm9uZTsKfQoKLm5hdi1pbm5lciBsaTpub3QoLmRpcikg
+ewogIG1hcmdpbi1sZWZ0OiAyMHB4OwogIG1hcmdpbi1ib3R0b206IDNweDsKfQoKLm5hdi1pbm5lciBs
+aS5kaXIgLmFycm93IHsKICBjdXJzb3I6IHBvaW50ZXI7CiAgZGlzcGxheTogaW5saW5lLWJsb2NrOwog
+IGZvbnQtc2l6ZTogMTBweDsKICBtYXJnaW4tcmlnaHQ6IDRweDsKICB0cmFuc2l0aW9uOiB0cmFuc2Zv
+cm0gMC41cyBlYXNlLW91dDsKfQoKLm5hdi1pbm5lciBsaS5kaXIgLmFycm93LmNvbGxhcHNlZCB7CiAg
+dHJhbnNmb3JtOiByb3RhdGUoLTkwZGVnKTsKfQoKLm5hdi1pbm5lciB1bCB7CiAgbWF4LWhlaWdodDog
+MjAwMHB4OwogIHRyYW5zaXRpb246IG1heC1oZWlnaHQgMC41cyBlYXNlLW91dDsKfQoKLm5hdi1pbm5l
+ciB1bC5jb2xsYXBzZWQgewogIG1heC1oZWlnaHQ6IDAgIWltcG9ydGFudDsKICBvdmVyZmxvdzogaGlk
+ZGVuOwp9CgoubmF2LWlubmVyIC5zZWxlY3RlZC1maWxlIHsKICBjb2xvcjogd2hpdGU7CiAgY3Vyc29y
+OiBpbmhlcml0OwogIGZvbnQtd2VpZ2h0OiA2MDA7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwp9Cgou
+ZWRpdC1jb3VudCB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzM3YWVkYzsKICBib3JkZXItcmFkaXVzOiAx
+MHB4OwogIGNvbG9yOiAjMDAwMDAwOwogIGRpc3BsYXk6IGlubGluZS1ibG9jazsKICBmb250LXNpemU6
+IDExcHg7CiAgZm9udC13ZWlnaHQ6IDYwMDsKICBtYXJnaW4tbGVmdDogNXB4OwogIG1pbi13aWR0aDog
+MjVweDsKICBwYWRkaW5nOiA0cHggMCAycHggMDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgbGluZS1o
+ZWlnaHQ6IDFlbTsKfQoKLmNvbnRlbnQgewogIGZsZXg6IDQgMzAwcHg7CiAgYmFja2dyb3VuZDogIzI4
+MmIyZTsKICBmb250LWZhbWlseTogbW9ub3NwYWNlOwogIG1hcmdpbjogMCA2cHg7CiAgcG9zaXRpb246
+IHJlbGF0aXZlOwogIHdoaXRlLXNwYWNlOiBwcmU7CiAgb3ZlcmZsb3c6IHNjcm9sbDsKfQoKLmNvZGUg
+ewogIHBhZGRpbmc6IDAuNWVtOwogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICBsZWZ0OiAwOwogIHRvcDog
+MDsKICBtYXJnaW4tbGVmdDogNTZweDsKfQoKLmhsanMgewogIGJhY2tncm91bmQtY29sb3I6ICMyODJi
+MmU7CiAgZGlzcGxheTogYmxvY2s7CiAgb3ZlcmZsb3cteDogYXV0bzsKICBwYWRkaW5nOiAwLjVlbTsK
+fQoKLmNvZGUgLndlbGNvbWUgewogIGZvbnQtZmFtaWx5OiAiR29vZ2xlIFNhbnMiLCJSb2JvdG8iLHNh
+bnMtc2VyaWY7CiAgZm9udC1zaXplOiAxOHB4OwogIG1hcmdpbi1yaWdodDogNjJweDsKICBjb2xvcjog
+Izc3NzsKfQoKLmNvZGUgLm5hdi1saW5rIHsKICBjb2xvcjogaW5oZXJpdDsKICB0ZXh0LWRlY29yYXRp
+b24tbGluZTogbm9uZTsKfQoKLmNvZGUgLm5hdi1saW5rOnZpc2l0ZWQgewogIGNvbG9yOiBpbmhlcml0
+OwogIHRleHQtZGVjb3JhdGlvbi1saW5lOiBub25lOwp9CgouY29kZSAubmF2LWxpbms6aG92ZXIgewog
+IHRleHQtZGVjb3JhdGlvbi1saW5lOiB1bmRlcmxpbmU7CiAgZm9udC13ZWlnaHQ6IDYwMDsKfQoKLnJl
+Z2lvbnMgewogIHBhZGRpbmc6IDAuNWVtOwogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICBsZWZ0OiAwOwog
+IHRvcDogMDsKfQoKLnJlZ2lvbnMgdGFibGUgewogIGJvcmRlci1zcGFjaW5nOiAwOwogIGZvbnQtc2l6
+ZTogaW5oZXJpdDsKfQoKLnJlZ2lvbnMgdGQgewogIGJvcmRlcjogbm9uZTsKICAvKiBUaGUgY29udGVu
+dCBvZiB0aGUgcmVnaW9ucyBpcyBub3QgdmlzaWJsZTsgdGhlIHVzZXIgaW5zdGVhZCB3aWxsIHNlZSB0
+aGUKICAgKiBoaWdobGlnaHRlZCBjb3B5IG9mIHRoZSBjb250ZW50LiAqLwogIGNvbG9yOiByZ2JhKDI1
+NSwgMjU1LCAyNTUsIDApOwogIHBhZGRpbmc6IDA7CiAgd2hpdGUtc3BhY2U6IHByZTsKfQoKLnJlZ2lv
+bnMgdGQ6ZW1wdHk6YWZ0ZXIgewogIGNvbnRlbnQ6ICJcMDBhMCI7Cn0KCi5yZWdpb25zIHRyLmhpZ2hs
+aWdodCB0ZDpsYXN0LWNoaWxkIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjNDQ0NDQ0OwogIGNvbG9yOiB3
+aGl0ZTsKfQoKLnJlZ2lvbnMgdGQubGluZS1ubyB7CiAgYm9yZGVyLXJpZ2h0OiBzb2xpZCAjMjgyYjJl
+IDJweDsKICBjb2xvcjogIzk5OTk5OTsKICBwYWRkaW5nLXJpZ2h0OiA0cHg7CiAgdGV4dC1hbGlnbjog
+cmlnaHQ7CiAgdmlzaWJpbGl0eTogdmlzaWJsZTsKICB3aWR0aDogNTBweDsKICBkaXNwbGF5OiBpbmxp
+bmUtYmxvY2s7Cn0KCi5yZWdpb25zIHRyLmhpZ2hsaWdodCB0ZC5saW5lLW5vIHsKICBib3JkZXItcmln
+aHQ6IHNvbGlkICNjY2MgMnB4Owp9CgoucmVnaW9uIHsKICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7CiAg
+cG9zaXRpb246IHJlbGF0aXZlOwogIHZpc2liaWxpdHk6IHZpc2libGU7CiAgei1pbmRleDogMjAwOwp9
+CgoucmVnaW9uLmFkZGVkLXJlZ2lvbiB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2NjZmZjYzsKICBjb2xv
+cjogIzAwMzMwMDsKfQoKLnJlZ2lvbi5yZW1vdmVkLXJlZ2lvbiB7CiAgYmFja2dyb3VuZC1jb2xvcjog
+I2ZmNjY2NjsKICBjb2xvcjogIzAwMTEwMDsKfQoKLnJlZ2lvbi5pbmZvcm1hdGl2ZS1yZWdpb24gewog
+IGJhY2tncm91bmQtY29sb3I6ICM0MDQ1NDk7IC8qICMyODJiMmUsIGxpZ2h0ZW5lZCAxMCUgKi8KICBi
+b3JkZXItYm90dG9tOiBzb2xpZCByZ2JhKDI1NSwgMjU1LCAwLCAwLjcpIDFweDsKICBkaXNwbGF5OiBp
+bmxpbmUtYmxvY2s7CiAgaGVpZ2h0OiAxNHB4OyAKICBwb3NpdGlvbjogcmVsYXRpdmU7CiAgdG9wOiAx
+cHg7Cn0KCi50YXJnZXQgewogIGJhY2tncm91bmQtY29sb3I6ICM0NDQ7CiAgcG9zaXRpb246IHJlbGF0
+aXZlOwogIHZpc2liaWxpdHk6IHZpc2libGU7CiAgZm9udC13ZWlnaHQ6IDYwMDsKfQoKLmluZm8tcGFu
+ZWwgewogIGZsZXg6IDEgMjAwcHg7CiAgbWFyZ2luOiAwOwogIGhlaWdodDogMTAwJTsKICBkaXNwbGF5
+OiBmbGV4OwogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47Cn0KCi5pbmZvLXBhbmVsIC5lZGl0LXBhbmVs
+IHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjMjgyYjJlOwogIG92ZXJmbG93OiBhdXRvOwp9CgouaW5mby1w
+YW5lbCAucGFuZWwtY29udGVudCB7CiAgcGFkZGluZzogN3B4Owp9CgouaW5mby1wYW5lbCAucGFuZWwt
+Y29udGVudD4gOmZpcnN0LWNoaWxkIHsKICBtYXJnaW4tdG9wOiAwOwp9CgouaW5mby1wYW5lbCAubm93
+cmFwIHsKICB3aGl0ZS1zcGFjZTogbm93cmFwOwp9CgouaW5mby1wYW5lbCB1bCwKLmluZm8tcGFuZWwg
+b2wgewogIHBhZGRpbmctbGVmdDogMjBweDsKfQoKLmluZm8tcGFuZWwgbGkgewogIG1hcmdpbjogMCAw
+IDVweCAwOwp9CgouaW5mby1wYW5lbCBhIHsKICBjb2xvcjogIzMzY2NmZjsKfQoKLmluZm8tcGFuZWwg
+LmVkaXQtbGlzdCB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzI4MmIyZTsKICBvdmVyZmxvdzogYXV0bzsK
+fQoKLmVkaXQtcGFuZWwgewogIG1hcmdpbi10b3A6IDZweDsKICBmbGV4OiAxIDEwMHB4Owp9CgouZWRp
+dC1saXN0IHsKICBmbGV4OiAyIDEwMHB4Owp9CgouZWRpdC1saXN0IC5lZGl0IHsKICBtYXJnaW46IDNw
+eCAwOwp9CgouZWRpdC1saXN0IC5lZGl0LWxpbmsgewogIGN1cnNvcjogcG9pbnRlcjsKfQoKLnBvcHVw
+LXBhbmUgewogIGRpc3BsYXk6IG5vbmU7CiAgcG9zaXRpb246IGZpeGVkOwogIHRvcDogMTUwcHg7CiAg
+bGVmdDogMTUwcHg7CiAgcmlnaHQ6IDE1MHB4OwogIGJvdHRvbTogMTUwcHg7CiAgYm9yZGVyOiAxcHgg
+c29saWQgYmxhY2s7CiAgYm9yZGVyLXRvcDogMnB4IHNvbGlkIGJsYWNrOwogIGJvcmRlci1yYWRpdXM6
+IDdweDsKICBib3gtc2hhZG93OiAwcHggMHB4IDIwcHggMnB4ICNiNGJmY2IyMjsKICB6LWluZGV4OiA0
+MDA7CiAgYmFja2dyb3VuZDogIzJiMzAzNjsKICBwYWRkaW5nOiAyMHB4Owp9CgoucG9wdXAtcGFuZSAu
+Y2xvc2UgewogIHBvc2l0aW9uOiBhYnNvbHV0ZTsKICByaWdodDogMTBweDsKICB0b3A6IDEwcHg7CiAg
+Y3Vyc29yOiBwb2ludGVyOwogIHRleHQtc2hhZG93OiAxcHggMXB4IDJweCAjODg4OwogIGJveC1zaGFk
+b3c6IDFweCAxcHggMnB4ICMxMTE7Cn0KCi5wb3B1cC1wYW5lIGgyIHsKICBwYWRkaW5nOiAyMXB4Owog
+IGhlaWdodDogMTAlOwogIG1hcmdpbjogMHB4OwogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7Cn0KCi5w
+b3B1cC1wYW5lIHAgewogIGhlaWdodDogMTAlOwogIGJveC1zaXppbmc6IGJvcmRlci1ib3g7CiAgcGFk
+ZGluZzogMHB4IDIwcHg7Cn0KCi5wb3B1cC1wYW5lIHByZSB7CiAgYmFja2dyb3VuZDogIzI4MmIyZTsK
+ICBwYWRkaW5nOiAyMHB4OwogIGJvdHRvbTogMHB4OwogIG92ZXJmbG93OiBhdXRvIHNjcm9sbDsKICBo
+ZWlnaHQ6IDY1JTsKICBtYXJnaW46IDBweDsKICBib3gtc2l6aW5nOiBib3JkZXItYm94Owp9CgoucG9w
+dXAtcGFuZSAuYnV0dG9uLmJvdHRvbSB7CiAgbWFyZ2luOiAyMHB4IDBweDsKICBkaXNwbGF5OiBibG9j
+azsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCi5yZXJ1bm5pbmctcGFuZSB7CiAgZGlzcGxheTogbm9u
+ZTsKfQoKYm9keS5yZXJ1bm5pbmcgLnJlcnVubmluZy1wYW5lIHsKICBkaXNwbGF5OiBibG9jazsKICBw
+b3NpdGlvbjogZml4ZWQ7CiAgdG9wOiAwcHg7CiAgYm90dG9tOiAwcHg7CiAgbGVmdDogMHB4OwogIHJp
+Z2h0OiAwcHg7CiAgYmFja2dyb3VuZC1jb2xvcjogIzAwMDAwMEFBOyAvKiB0cmFuc2x1Y2VudCBibGFj
+ayAqLwogIHotaW5kZXg6IDQwMDsKfQoKLnJlcnVubmluZy1wYW5lIGgxIHsKICBwb3NpdGlvbjogYWJz
+b2x1dGU7CiAgdG9wOiA1MCU7CiAgbGVmdDogNTAlOwogIHRyYW5zZm9ybTogdHJhbnNsYXRlKC01MCUs
+IC01MCUpOwp9CgouZWRpdC1wYW5lbCAudHlwZS1kZXNjcmlwdGlvbiB7CiAgLyogRnJvbSBITEpTJ3Mg
+LmhsanMta2V5d29yZCwgLmhsanMtc2VsZWN0b3ItdGFnLCAuaGxqcy1kZWxldGlvbiAqLwogIGNvbG9y
+OiAjY2M3ODMyOwogIGZvbnQtZmFtaWx5OiBtb25vc3BhY2U7Cn0KCnVsLnRyYWNlIHsKICBmb250LXNp
+emU6IDEzcHg7CiAgbGlzdC1zdHlsZS10eXBlOiBub25lOwogIHBhZGRpbmctbGVmdDogMHB4Owp9Cgp1
+bC50cmFjZSBsaSB7CiAgY29sb3I6IHdoaXRlOwp9Cgp1bC50cmFjZSBsaSAuZnVuY3Rpb24gewogIC8q
+IEZyb20gSExKUydzIC5obGpzLXNlY3Rpb24sIC5obGpzLXRpdGxlLCAuaGxqcy10eXBlICovCiAgY29s
+b3I6ICNmZmM2NmQ7CiAgZm9udC1mYW1pbHk6IG1vbm9zcGFjZTsKICBmb250LXdlaWdodDogNjAwOwp9
+Cgp1bC50cmFjZSBsaSBwLmRyYXdlciB7CiAgbWFyZ2luOiAzcHggMHB4OwogIHBhZGRpbmc6IDBweCAw
+cHggMHB4IDE0cHg7Cn0KCnVsLnRyYWNlIGxpIHAuZHJhd2VyIGJ1dHRvbiB7CiAgbWFyZ2luLXJpZ2h0
+OiAzcHg7Cn0KCi5lbGV2YXRpb24tejQgewogIGJveC1zaGFkb3c6IDBweCAycHggNHB4IC0xcHggcmdi
+YSgwLCAwLCAwLCAwLjIpLAogICAgICAwcHggNHB4IDVweCAwcHggcmdiYSgwLCAwLCAwLCAwLjE0KSwK
+ICAgICAgMHB4IDFweCAxMHB4IDBweCByZ2JhKDAsIDAsIDAsIC4xMik7Cn0KCmEgewogIGNvbG9yOiAj
+Y2NjOwogIGZpbGw6ICNjY2M7CiAgdGV4dC1kZWNvcmF0aW9uOiBub25lOwp9CgphOmhvdmVyIHsKICBj
+b2xvcjogI2ZmZjsKICBmaWxsOiAjZmZmOwp9CgouYWRkLWhpbnQtbGluayB7CiAgZGlzcGxheTogaW5s
+aW5lLWJsb2NrOwogIG1hcmdpbjogM3B4Owp9CgovKiBDYXJlZnVsIGhlcmUuIGBhLmJ1dHRvbmAgaXMg
+cmVwZXRpdGl2ZSBidXQgcmVxdWlyZWQgdG8gZ2V0IGNvcnJlY3QKICogc3BlY2lmaWNpdHkgKi8KYnV0
+dG9uLCAuYnV0dG9uLCBhLmJ1dHRvbiB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzMzY2NmZjsKICBib3Jk
+ZXI6IDJweCBzb2xpZCAjMzdhZWRjOwogIGJvcmRlci1yYWRpdXM6IDNweDsKICBwYWRkaW5nOiA2cHgg
+MTBweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogIzI4MjgyODsKfQoKYnV0dG9uOmhvdmVy
+LCAuYnV0dG9uOmhvdmVyIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjODBkZmZmOwogIGJvcmRlcjogMnB4
+IHNvbGlkICM1MmI4ZTA7CiAgY3Vyc29yOiBwb2ludGVyOwp9CgpidXR0b25bZGlzYWJsZWRdIHsKICBi
+YWNrZ3JvdW5kLWNvbG9yOiAjN2FhOGI4OwogIGNvbG9yOiAjNTA3MTc3OwogIGJvcmRlcjogMnB4IHNv
+bGlkICM1MDcxNzc7CiAgY3Vyc29yOiBub3QtYWxsb3dlZDsKfQoKLnBsYWNlaG9sZGVyIHsKICBjb2xv
+cjogIzc3NzsKICB0ZXh0LWFsaWduOiBjZW50ZXI7CiAgbWFyZ2luLXRvcDogM2VtICFpbXBvcnRhbnQ7
+Cn0KCi8qKgogKiBITEpTIE92ZXJyaWRlcwogKi8KLmhsanMgewogIC8qKgogICAqIFRoaXMgYWxsb3dz
+IHRoZSBwZXItbGluZSBoaWdobGlnaHRzIHRvIHNob3cuCiAgICovCiAgYmFja2dyb3VuZDogbm9uZTsK
+fQo=
''';
String _migration_js;
@@ -709,12 +872,12 @@
czpzZXRPclVwZGF0ZUxlYWZUYWdzfX0oKQpmdW5jdGlvbiBpbml0aWFsaXplRGVmZXJyZWRIdW5rKGEp
e3g9di50eXBlcy5sZW5ndGgKYShodW5rSGVscGVycyx2LHcsJCl9ZnVuY3Rpb24gZ2V0R2xvYmFsRnJv
bU5hbWUoYSl7Zm9yKHZhciB0PTA7dDx3Lmxlbmd0aDt0Kyspe2lmKHdbdF09PUMpY29udGludWUKaWYo
-d1t0XVthXSlyZXR1cm4gd1t0XVthXX19dmFyIEM9e30sSD17ZW86ZnVuY3Rpb24gZW8oKXt9LApvbzpm
+d1t0XVthXSlyZXR1cm4gd1t0XVthXX19dmFyIEM9e30sSD17Rks6ZnVuY3Rpb24gRksoKXt9LApvbzpm
dW5jdGlvbihhKXt2YXIgdCxzPWFeNDgKaWYoczw9OSlyZXR1cm4gcwp0PWF8MzIKaWYoOTc8PXQmJnQ8
PTEwMilyZXR1cm4gdC04NwpyZXR1cm4tMX0sCnFDOmZ1bmN0aW9uKGEsYixjLGQpe1AuazEoYiwic3Rh
cnQiKQppZihjIT1udWxsKXtQLmsxKGMsImVuZCIpCmlmKGI+YylILnZoKFAuVEUoYiwwLGMsInN0YXJ0
IixudWxsKSl9cmV0dXJuIG5ldyBILm5IKGEsYixjLGQuQygibkg8MD4iKSl9LApLMTpmdW5jdGlvbihh
-LGIsYyxkKXtpZih1Lmd3LmMoYSkpcmV0dXJuIG5ldyBILnh5KGEsYixjLkMoIkA8MD4iKS5LcShkKS5D
+LGIsYyxkKXtpZih1Lmd3LmIoYSkpcmV0dXJuIG5ldyBILnh5KGEsYixjLkMoIkA8MD4iKS5LcShkKS5D
KCJ4eTwxLDI+IikpCnJldHVybiBuZXcgSC5pMShhLGIsYy5DKCJAPDA+IikuS3EoZCkuQygiaTE8MSwy
PiIpKX0sCldwOmZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBQLmxqKCJObyBlbGVtZW50Iil9LApkVTpmdW5j
dGlvbigpe3JldHVybiBuZXcgUC5saigiVG9vIG1hbnkgZWxlbWVudHMiKX0sCmFyOmZ1bmN0aW9uKCl7
@@ -724,137 +887,137 @@
biBhNyhhLGIsYyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9MApfLmQ9bnVsbApfLiR0aT1jfSwK
aTE6ZnVuY3Rpb24gaTEoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuJHRpPWN9LAp4eTpmdW5j
dGlvbiB4eShhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy4kdGk9Y30sCk1IOmZ1bmN0aW9uIE1I
-KGEsYixjKXt2YXIgXz10aGlzCl8uYT1udWxsCl8uYj1hCl8uYz1iCl8uJHRpPWN9LApBODpmdW5jdGlv
-biBBOChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy4kdGk9Y30sClU1OmZ1bmN0aW9uIFU1KGEs
-YixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLiR0aT1jfSwKU086ZnVuY3Rpb24gU08oYSxiLGMpe3Ro
+KGEsYixjKXt2YXIgXz10aGlzCl8uYT1udWxsCl8uYj1hCl8uYz1iCl8uJHRpPWN9LApsSjpmdW5jdGlv
+biBsSihhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy4kdGk9Y30sClU1OmZ1bmN0aW9uIFU1KGEs
+YixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLiR0aT1jfSwKdkc6ZnVuY3Rpb24gdkcoYSxiLGMpe3Ro
aXMuYT1hCnRoaXMuYj1iCnRoaXMuJHRpPWN9LApTVTpmdW5jdGlvbiBTVSgpe30sClJlOmZ1bmN0aW9u
-IFJlKCl7fSwKWEM6ZnVuY3Rpb24gWEMoKXt9LAp3djpmdW5jdGlvbiB3dihhKXt0aGlzLmE9YX0sCmRj
+IFJlKCl7fSwKdzI6ZnVuY3Rpb24gdzIoKXt9LAp3djpmdW5jdGlvbiB3dihhKXt0aGlzLmE9YX0sCmRj
OmZ1bmN0aW9uKCl7dGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBtb2RpZnkgdW5tb2RpZmlhYmxlIE1hcCIp
KX0sCk5ROmZ1bmN0aW9uKGEpe3ZhciB0LHM9SC5KZyhhKQppZih0eXBlb2Ygcz09InN0cmluZyIpcmV0
dXJuIHMKdD0ibWluaWZpZWQ6IithCnJldHVybiB0fSwKd1Y6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihi
-IT1udWxsKXt0PWIueAppZih0IT1udWxsKXJldHVybiB0fXJldHVybiB1LmFVLmMoYSl9LApkOmZ1bmN0
+IT1udWxsKXt0PWIueAppZih0IT1udWxsKXJldHVybiB0fXJldHVybiB1LmFVLmIoYSl9LApkOmZ1bmN0
aW9uKGEpe3ZhciB0CmlmKHR5cGVvZiBhPT0ic3RyaW5nIilyZXR1cm4gYQppZih0eXBlb2YgYT09Im51
bWJlciIpe2lmKGEhPT0wKXJldHVybiIiK2F9ZWxzZSBpZighMD09PWEpcmV0dXJuInRydWUiCmVsc2Ug
-aWYoITE9PT1hKXJldHVybiJmYWxzZSIKZWxzZSBpZihhPT1udWxsKXJldHVybiJudWxsIgp0PUouaihh
-KQppZih0eXBlb2YgdCE9InN0cmluZyIpdGhyb3cgSC5iKEgudEwoYSkpCnJldHVybiB0fSwKZVE6ZnVu
+aWYoITE9PT1hKXJldHVybiJmYWxzZSIKZWxzZSBpZihhPT1udWxsKXJldHVybiJudWxsIgp0PUouQWMo
+YSkKaWYodHlwZW9mIHQhPSJzdHJpbmciKXRocm93IEguYihILkkoYSkpCnJldHVybiB0fSwKZVE6ZnVu
Y3Rpb24oYSl7dmFyIHQ9YS4kaWRlbnRpdHlIYXNoCmlmKHQ9PW51bGwpe3Q9TWF0aC5yYW5kb20oKSow
eDNmZmZmZmZmfDAKYS4kaWRlbnRpdHlIYXNoPXR9cmV0dXJuIHR9LApIcDpmdW5jdGlvbihhLGIpe3Zh
-ciB0LHMscixxLHAsbyxuPW51bGwKaWYodHlwZW9mIGEhPSJzdHJpbmciKUgudmgoSC50TChhKSkKdD0v
-XlxzKlsrLV0/KCgweFthLWYwLTldKyl8KFxkKyl8KFthLXowLTldKykpXHMqJC9pLmV4ZWMoYSkKaWYo
-dD09bnVsbClyZXR1cm4gbgppZigzPj10Lmxlbmd0aClyZXR1cm4gSC5PSCh0LDMpCnM9SC55KHRbM10p
-CmlmKGI9PW51bGwpe2lmKHMhPW51bGwpcmV0dXJuIHBhcnNlSW50KGEsMTApCmlmKHRbMl0hPW51bGwp
-cmV0dXJuIHBhcnNlSW50KGEsMTYpCnJldHVybiBufWlmKGI8Mnx8Yj4zNil0aHJvdyBILmIoUC5URShi
-LDIsMzYsInJhZGl4IixuKSkKaWYoYj09PTEwJiZzIT1udWxsKXJldHVybiBwYXJzZUludChhLDEwKQpp
-ZihiPDEwfHxzPT1udWxsKXtyPWI8PTEwPzQ3K2I6ODYrYgpxPXRbMV0KZm9yKHA9cS5sZW5ndGgsbz0w
-O288cDsrK28paWYoKEMueEIuVyhxLG8pfDMyKT5yKXJldHVybiBufXJldHVybiBwYXJzZUludChhLGIp
-fSwKTTpmdW5jdGlvbihhKXt2YXIgdD1ILkg1KGEpCnJldHVybiB0fSwKSDU6ZnVuY3Rpb24oYSl7dmFy
-IHQscyxyCmlmKGEgaW5zdGFuY2VvZiBQLmspcmV0dXJuIEguZG0oSC56SyhhKSxudWxsKQppZihKLmlh
-KGEpPT09Qy5Pa3x8dS5hay5jKGEpKXt0PUMuTzQoYSkKaWYoSC5mKHQpKXJldHVybiB0CnM9YS5jb25z
-dHJ1Y3RvcgppZih0eXBlb2Ygcz09ImZ1bmN0aW9uIil7cj1zLm5hbWUKaWYodHlwZW9mIHI9PSJzdHJp
-bmciJiZILmYocikpcmV0dXJuIHJ9fXJldHVybiBILmRtKEgueksoYSksbnVsbCl9LApmOmZ1bmN0aW9u
-KGEpe3ZhciB0PWEhPT0iT2JqZWN0IiYmYSE9PSIiCnJldHVybiB0fSwKTTA6ZnVuY3Rpb24oKXtpZigh
-IXNlbGYubG9jYXRpb24pcmV0dXJuIHNlbGYubG9jYXRpb24uaHJlZgpyZXR1cm4gbnVsbH0sClZLOmZ1
-bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9YS5sZW5ndGgKaWYocDw9NTAwKXJldHVybiBTdHJpbmcuZnJv
-bUNoYXJDb2RlLmFwcGx5KG51bGwsYSkKZm9yKHQ9IiIscz0wO3M8cDtzPXIpe3I9cys1MDAKcT1yPHA/
-cjpwCnQrPVN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxhLnNsaWNlKHMscSkpfXJldHVybiB0
-fSwKQ3E6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9SC5WTShbXSx1LnQpCmZvcih0PWEubGVuZ3RoLHM9
-MDtzPGEubGVuZ3RoO2EubGVuZ3RoPT09dHx8KDAsSC5saykoYSksKytzKXtyPWFbc10KaWYoIUgub2so
-cikpdGhyb3cgSC5iKEgudEwocikpCmlmKHI8PTY1NTM1KUMuTm0uaShxLHIpCmVsc2UgaWYocjw9MTEx
-NDExMSl7Qy5ObS5pKHEsNTUyOTYrKEMuam4ud0coci02NTUzNiwxMCkmMTAyMykpCkMuTm0uaShxLDU2
-MzIwKyhyJjEwMjMpKX1lbHNlIHRocm93IEguYihILnRMKHIpKX1yZXR1cm4gSC5WSyhxKX0sCmVUOmZ1
-bmN0aW9uKGEpe3ZhciB0LHMscgpmb3IodD1hLmxlbmd0aCxzPTA7czx0Oysrcyl7cj1hW3NdCmlmKCFI
-Lm9rKHIpKXRocm93IEguYihILnRMKHIpKQppZihyPDApdGhyb3cgSC5iKEgudEwocikpCmlmKHI+NjU1
-MzUpcmV0dXJuIEguQ3EoYSl9cmV0dXJuIEguVksoYSl9LApmdzpmdW5jdGlvbihhLGIsYyl7dmFyIHQs
-cyxyLHEKaWYoYzw9NTAwJiZiPT09MCYmYz09PWEubGVuZ3RoKXJldHVybiBTdHJpbmcuZnJvbUNoYXJD
-b2RlLmFwcGx5KG51bGwsYSkKZm9yKHQ9YixzPSIiO3Q8Yzt0PXIpe3I9dCs1MDAKcT1yPGM/cjpjCnMr
-PVN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCxhLnN1YmFycmF5KHQscSkpfXJldHVybiBzfSwK
-THc6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoMDw9YSl7aWYoYTw9NjU1MzUpcmV0dXJuIFN0cmluZy5mcm9t
-Q2hhckNvZGUoYSkKaWYoYTw9MTExNDExMSl7dD1hLTY1NTM2CnJldHVybiBTdHJpbmcuZnJvbUNoYXJD
-b2RlKCg1NTI5NnxDLmpuLndHKHQsMTApKT4+PjAsNTYzMjB8dCYxMDIzKX19dGhyb3cgSC5iKFAuVEUo
-YSwwLDExMTQxMTEsbnVsbCxudWxsKSl9LApvMjpmdW5jdGlvbihhKXtpZihhLmRhdGU9PT12b2lkIDAp
-YS5kYXRlPW5ldyBEYXRlKGEuYSkKcmV0dXJuIGEuZGF0ZX0sCnRKOmZ1bmN0aW9uKGEpe3ZhciB0PUgu
-bzIoYSkuZ2V0RnVsbFllYXIoKSswCnJldHVybiB0fSwKTlM6ZnVuY3Rpb24oYSl7dmFyIHQ9SC5vMihh
-KS5nZXRNb250aCgpKzEKcmV0dXJuIHR9LApqQTpmdW5jdGlvbihhKXt2YXIgdD1ILm8yKGEpLmdldERh
-dGUoKSswCnJldHVybiB0fSwKSVg6ZnVuY3Rpb24oYSl7dmFyIHQ9SC5vMihhKS5nZXRIb3VycygpKzAK
-cmV0dXJuIHR9LApjaDpmdW5jdGlvbihhKXt2YXIgdD1ILm8yKGEpLmdldE1pbnV0ZXMoKSswCnJldHVy
-biB0fSwKSmQ6ZnVuY3Rpb24oYSl7dmFyIHQ9SC5vMihhKS5nZXRTZWNvbmRzKCkrMApyZXR1cm4gdH0s
-Cm8xOmZ1bmN0aW9uKGEpe3ZhciB0PUgubzIoYSkuZ2V0TWlsbGlzZWNvbmRzKCkrMApyZXR1cm4gdH0s
-CnpvOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHI9e30Kci5hPTAKdD1bXQpzPVtdCnIuYT1iLmxlbmd0
-aApDLk5tLkZWKHQsYikKci5iPSIiCmlmKGMhPW51bGwmJmMuYSE9PTApYy5LKDAsbmV3IEguQ2oocixz
-LHQpKQoiIityLmEKcmV0dXJuIEouSnkoYSxuZXcgSC5MSShDLlRlLDAsdCxzLDApKX0sCkVrOmZ1bmN0
-aW9uKGEsYixjKXt2YXIgdCxzLHIscQppZihiIGluc3RhbmNlb2YgQXJyYXkpdD1jPT1udWxsfHxjLmE9
-PT0wCmVsc2UgdD0hMQppZih0KXtzPWIKcj1zLmxlbmd0aAppZihyPT09MCl7aWYoISFhLiQwKXJldHVy
-biBhLiQwKCl9ZWxzZSBpZihyPT09MSl7aWYoISFhLiQxKXJldHVybiBhLiQxKHNbMF0pfWVsc2UgaWYo
-cj09PTIpe2lmKCEhYS4kMilyZXR1cm4gYS4kMihzWzBdLHNbMV0pfWVsc2UgaWYocj09PTMpe2lmKCEh
-YS4kMylyZXR1cm4gYS4kMyhzWzBdLHNbMV0sc1syXSl9ZWxzZSBpZihyPT09NCl7aWYoISFhLiQ0KXJl
-dHVybiBhLiQ0KHNbMF0sc1sxXSxzWzJdLHNbM10pfWVsc2UgaWYocj09PTUpaWYoISFhLiQ1KXJldHVy
-biBhLiQ1KHNbMF0sc1sxXSxzWzJdLHNbM10sc1s0XSkKcT1hWyIiKyIkIityXQppZihxIT1udWxsKXJl
-dHVybiBxLmFwcGx5KGEscyl9cmV0dXJuIEguRXcoYSxiLGMpfSwKRXc6ZnVuY3Rpb24oYSxiLGMpe3Zh
-ciB0LHMscixxLHAsbyxuLG0sbCxrPWIgaW5zdGFuY2VvZiBBcnJheT9iOlAuQ0goYiwhMCx1LnopLGo9
-ay5sZW5ndGgsaT1hLiRSCmlmKGo8aSlyZXR1cm4gSC56byhhLGssYykKdD1hLiRECnM9dD09bnVsbApy
-PSFzP3QoKTpudWxsCnE9Si5pYShhKQpwPXEuJEMKaWYodHlwZW9mIHA9PSJzdHJpbmciKXA9cVtwXQpp
-ZihzKXtpZihjIT1udWxsJiZjLmEhPT0wKXJldHVybiBILnpvKGEsayxjKQppZihqPT09aSlyZXR1cm4g
-cC5hcHBseShhLGspCnJldHVybiBILnpvKGEsayxjKX1pZihyIGluc3RhbmNlb2YgQXJyYXkpe2lmKGMh
-PW51bGwmJmMuYSE9PTApcmV0dXJuIEguem8oYSxrLGMpCmlmKGo+aStyLmxlbmd0aClyZXR1cm4gSC56
-byhhLGssbnVsbCkKQy5ObS5GVihrLHIuc2xpY2Uoai1pKSkKcmV0dXJuIHAuYXBwbHkoYSxrKX1lbHNl
-e2lmKGo+aSlyZXR1cm4gSC56byhhLGssYykKbz1PYmplY3Qua2V5cyhyKQppZihjPT1udWxsKWZvcihz
-PW8ubGVuZ3RoLG49MDtuPG8ubGVuZ3RoO28ubGVuZ3RoPT09c3x8KDAsSC5saykobyksKytuKUMuTm0u
-aShrLHJbSC55KG9bbl0pXSkKZWxzZXtmb3Iocz1vLmxlbmd0aCxtPTAsbj0wO248by5sZW5ndGg7by5s
-ZW5ndGg9PT1zfHwoMCxILmxrKShvKSwrK24pe2w9SC55KG9bbl0pCmlmKGMueDQobCkpeysrbQpDLk5t
-LmkoayxjLnEoMCxsKSl9ZWxzZSBDLk5tLmkoayxyW2xdKX1pZihtIT09Yy5hKXJldHVybiBILnpvKGEs
-ayxjKX1yZXR1cm4gcC5hcHBseShhLGspfX0sCnBZOmZ1bmN0aW9uKGEpe3Rocm93IEguYihILnRMKGEp
-KX0sCk9IOmZ1bmN0aW9uKGEsYil7aWYoYT09bnVsbClKLkhtKGEpCnRocm93IEguYihILkhZKGEsYikp
-fSwKSFk6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9ImluZGV4IgppZighSC5vayhiKSlyZXR1cm4gbmV3
-IFAudSghMCxiLHIsbnVsbCkKdD1ILlNjKEouSG0oYSkpCmlmKCEoYjwwKSl7aWYodHlwZW9mIHQhPT0i
-bnVtYmVyIilyZXR1cm4gSC5wWSh0KQpzPWI+PXR9ZWxzZSBzPSEwCmlmKHMpcmV0dXJuIFAuQ2YoYixh
-LHIsbnVsbCx0KQpyZXR1cm4gUC54KGIscil9LAphdTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9IkludmFs
-aWQgdmFsdWUiCmlmKGE+YylyZXR1cm4gbmV3IFAuYkooMCxjLCEwLGEsInN0YXJ0Iix0KQppZihiIT1u
-dWxsKXtpZighSC5vayhiKSlyZXR1cm4gbmV3IFAudSghMCxiLCJlbmQiLG51bGwpCmlmKGI8YXx8Yj5j
-KXJldHVybiBuZXcgUC5iSihhLGMsITAsYiwiZW5kIix0KX1yZXR1cm4gbmV3IFAudSghMCxiLCJlbmQi
-LG51bGwpfSwKdEw6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLnUoITAsYSxudWxsLG51bGwpfSwKYjpm
-dW5jdGlvbihhKXt2YXIgdAppZihhPT1udWxsKWE9bmV3IFAubigpCnQ9bmV3IEVycm9yKCkKdC5kYXJ0
-RXhjZXB0aW9uPWEKaWYoImRlZmluZVByb3BlcnR5IiBpbiBPYmplY3Qpe09iamVjdC5kZWZpbmVQcm9w
-ZXJ0eSh0LCJtZXNzYWdlIix7Z2V0OkguaH0pCnQubmFtZT0iIn1lbHNlIHQudG9TdHJpbmc9SC5oCnJl
-dHVybiB0fSwKaDpmdW5jdGlvbigpe3JldHVybiBKLmoodGhpcy5kYXJ0RXhjZXB0aW9uKX0sCnZoOmZ1
-bmN0aW9uKGEpe3Rocm93IEguYihhKX0sCmxrOmZ1bmN0aW9uKGEpe3Rocm93IEguYihQLmE0KGEpKX0s
-CmNNOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbwphPUguZUEoYS5yZXBsYWNlKFN0cmluZyh7fSks
-JyRyZWNlaXZlciQnKSkKdD1hLm1hdGNoKC9cXFwkW2EtekEtWl0rXFxcJC9nKQppZih0PT1udWxsKXQ9
-SC5WTShbXSx1LnMpCnM9dC5pbmRleE9mKCJcXCRhcmd1bWVudHNcXCQiKQpyPXQuaW5kZXhPZigiXFwk
-YXJndW1lbnRzRXhwclxcJCIpCnE9dC5pbmRleE9mKCJcXCRleHByXFwkIikKcD10LmluZGV4T2YoIlxc
-JG1ldGhvZFxcJCIpCm89dC5pbmRleE9mKCJcXCRyZWNlaXZlclxcJCIpCnJldHVybiBuZXcgSC5mOShh
-LnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJGFyZ3VtZW50c1xcXFxcXCQnLCdnJyksJygoPzp4fFte
-eF0pKiknKS5yZXBsYWNlKG5ldyBSZWdFeHAoJ1xcXFxcXCRhcmd1bWVudHNFeHByXFxcXFxcJCcsJ2cn
-KSwnKCg/Onh8W154XSkqKScpLnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJGV4cHJcXFxcXFwkJywn
-ZycpLCcoKD86eHxbXnhdKSopJykucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFwkbWV0aG9kXFxcXFxc
-JCcsJ2cnKSwnKCg/Onh8W154XSkqKScpLnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJHJlY2VpdmVy
-XFxcXFxcJCcsJ2cnKSwnKCg/Onh8W154XSkqKScpLHMscixxLHAsbyl9LApTNzpmdW5jdGlvbihhKXty
-ZXR1cm4gZnVuY3Rpb24oJGV4cHIkKXt2YXIgJGFyZ3VtZW50c0V4cHIkPSckYXJndW1lbnRzJCcKdHJ5
-eyRleHByJC4kbWV0aG9kJCgkYXJndW1lbnRzRXhwciQpfWNhdGNoKHQpe3JldHVybiB0Lm1lc3NhZ2V9
-fShhKX0sCk1qOmZ1bmN0aW9uKGEpe3JldHVybiBmdW5jdGlvbigkZXhwciQpe3RyeXskZXhwciQuJG1l
-dGhvZCR9Y2F0Y2godCl7cmV0dXJuIHQubWVzc2FnZX19KGEpfSwKSWo6ZnVuY3Rpb24oYSxiKXtyZXR1
-cm4gbmV3IEguVzAoYSxiPT1udWxsP251bGw6Yi5tZXRob2QpfSwKVDM6ZnVuY3Rpb24oYSxiKXt2YXIg
-dD1iPT1udWxsLHM9dD9udWxsOmIubWV0aG9kCnJldHVybiBuZXcgSC5heihhLHMsdD9udWxsOmIucmVj
-ZWl2ZXIpfSwKUnU6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaixpLGgsZyxmPW51
-bGwsZT1uZXcgSC5BbShhKQppZihhPT1udWxsKXJldHVybiBmCmlmKGEgaW5zdGFuY2VvZiBILmJxKXJl
-dHVybiBlLiQxKGEuYSkKaWYodHlwZW9mIGEhPT0ib2JqZWN0IilyZXR1cm4gYQppZigiZGFydEV4Y2Vw
-dGlvbiIgaW4gYSlyZXR1cm4gZS4kMShhLmRhcnRFeGNlcHRpb24pCmVsc2UgaWYoISgibWVzc2FnZSIg
-aW4gYSkpcmV0dXJuIGEKdD1hLm1lc3NhZ2UKaWYoIm51bWJlciIgaW4gYSYmdHlwZW9mIGEubnVtYmVy
-PT0ibnVtYmVyIil7cz1hLm51bWJlcgpyPXMmNjU1MzUKaWYoKEMuam4ud0cocywxNikmODE5MSk9PT0x
-MClzd2l0Y2gocil7Y2FzZSA0Mzg6cmV0dXJuIGUuJDEoSC5UMyhILmQodCkrIiAoRXJyb3IgIityKyIp
-IixmKSkKY2FzZSA0NDU6Y2FzZSA1MDA3OnJldHVybiBlLiQxKEguSWooSC5kKHQpKyIgKEVycm9yICIr
-cisiKSIsZikpfX1pZihhIGluc3RhbmNlb2YgVHlwZUVycm9yKXtxPSQuU24oKQpwPSQubHEoKQpvPSQu
-TjkoKQpuPSQuaUkoKQptPSQuS2YoKQpsPSQuWmgoKQprPSQuck4oKQokLmMzKCkKaj0kLkhLKCkKaT0k
-LnIxKCkKaD1xLnFTKHQpCmlmKGghPW51bGwpcmV0dXJuIGUuJDEoSC5UMyhILnkodCksaCkpCmVsc2V7
-aD1wLnFTKHQpCmlmKGghPW51bGwpe2gubWV0aG9kPSJjYWxsIgpyZXR1cm4gZS4kMShILlQzKEgueSh0
-KSxoKSl9ZWxzZXtoPW8ucVModCkKaWYoaD09bnVsbCl7aD1uLnFTKHQpCmlmKGg9PW51bGwpe2g9bS5x
-Uyh0KQppZihoPT1udWxsKXtoPWwucVModCkKaWYoaD09bnVsbCl7aD1rLnFTKHQpCmlmKGg9PW51bGwp
-e2g9bi5xUyh0KQppZihoPT1udWxsKXtoPWoucVModCkKaWYoaD09bnVsbCl7aD1pLnFTKHQpCmc9aCE9
-bnVsbH1lbHNlIGc9ITB9ZWxzZSBnPSEwfWVsc2UgZz0hMH1lbHNlIGc9ITB9ZWxzZSBnPSEwfWVsc2Ug
-Zz0hMH1lbHNlIGc9ITAKaWYoZylyZXR1cm4gZS4kMShILklqKEgueSh0KSxoKSl9fXJldHVybiBlLiQx
-KG5ldyBILnZWKHR5cGVvZiB0PT0ic3RyaW5nIj90OiIiKSl9aWYoYSBpbnN0YW5jZW9mIFJhbmdlRXJy
-b3Ipe2lmKHR5cGVvZiB0PT0ic3RyaW5nIiYmdC5pbmRleE9mKCJjYWxsIHN0YWNrIikhPT0tMSlyZXR1
-cm4gbmV3IFAuS1koKQp0PWZ1bmN0aW9uKGIpe3RyeXtyZXR1cm4gU3RyaW5nKGIpfWNhdGNoKGQpe31y
-ZXR1cm4gbnVsbH0oYSkKcmV0dXJuIGUuJDEobmV3IFAudSghMSxmLGYsdHlwZW9mIHQ9PSJzdHJpbmci
+ciB0LHMscixxLHAsbyxuPW51bGwKaWYodHlwZW9mIGEhPSJzdHJpbmciKUgudmgoSC5JKGEpKQp0PS9e
+XHMqWystXT8oKDB4W2EtZjAtOV0rKXwoXGQrKXwoW2EtejAtOV0rKSlccyokL2kuZXhlYyhhKQppZih0
+PT1udWxsKXJldHVybiBuCmlmKDM+PXQubGVuZ3RoKXJldHVybiBILmsodCwzKQpzPUguYyh0WzNdKQpp
+ZihiPT1udWxsKXtpZihzIT1udWxsKXJldHVybiBwYXJzZUludChhLDEwKQppZih0WzJdIT1udWxsKXJl
+dHVybiBwYXJzZUludChhLDE2KQpyZXR1cm4gbn1pZihiPDJ8fGI+MzYpdGhyb3cgSC5iKFAuVEUoYiwy
+LDM2LCJyYWRpeCIsbikpCmlmKGI9PT0xMCYmcyE9bnVsbClyZXR1cm4gcGFyc2VJbnQoYSwxMCkKaWYo
+YjwxMHx8cz09bnVsbCl7cj1iPD0xMD80NytiOjg2K2IKcT10WzFdCmZvcihwPXEubGVuZ3RoLG89MDtv
+PHA7KytvKWlmKChDLnhCLlcocSxvKXwzMik+cilyZXR1cm4gbn1yZXR1cm4gcGFyc2VJbnQoYSxiKX0s
+CmxoOmZ1bmN0aW9uKGEpe3ZhciB0PUguSDUoYSkKcmV0dXJuIHR9LApINTpmdW5jdGlvbihhKXt2YXIg
+dCxzLHIKaWYoYSBpbnN0YW5jZW9mIFAuTWgpcmV0dXJuIEguSihILnEoYSksbnVsbCkKaWYoSi5pYShh
+KT09PUMuT2t8fHUuYWsuYihhKSl7dD1DLndiKGEpCmlmKEguQmUodCkpcmV0dXJuIHQKcz1hLmNvbnN0
+cnVjdG9yCmlmKHR5cGVvZiBzPT0iZnVuY3Rpb24iKXtyPXMubmFtZQppZih0eXBlb2Ygcj09InN0cmlu
+ZyImJkguQmUocikpcmV0dXJuIHJ9fXJldHVybiBILkooSC5xKGEpLG51bGwpfSwKQmU6ZnVuY3Rpb24o
+YSl7dmFyIHQ9YSE9PSJPYmplY3QiJiZhIT09IiIKcmV0dXJuIHR9LApNMDpmdW5jdGlvbigpe2lmKCEh
+c2VsZi5sb2NhdGlvbilyZXR1cm4gc2VsZi5sb2NhdGlvbi5ocmVmCnJldHVybiBudWxsfSwKVks6ZnVu
+Y3Rpb24oYSl7dmFyIHQscyxyLHEscD1hLmxlbmd0aAppZihwPD01MDApcmV0dXJuIFN0cmluZy5mcm9t
+Q2hhckNvZGUuYXBwbHkobnVsbCxhKQpmb3IodD0iIixzPTA7czxwO3M9cil7cj1zKzUwMApxPXI8cD9y
+OnAKdCs9U3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLGEuc2xpY2UocyxxKSl9cmV0dXJuIHR9
+LApDcTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1ILlZNKFtdLHUudCkKZm9yKHQ9YS5sZW5ndGgscz0w
+O3M8YS5sZW5ndGg7YS5sZW5ndGg9PT10fHwoMCxILmxrKShhKSwrK3Mpe3I9YVtzXQppZighSC5vayhy
+KSl0aHJvdyBILmIoSC5JKHIpKQppZihyPD02NTUzNSlDLk5tLmkocSxyKQplbHNlIGlmKHI8PTExMTQx
+MTEpe0MuTm0uaShxLDU1Mjk2KyhDLmpuLndHKHItNjU1MzYsMTApJjEwMjMpKQpDLk5tLmkocSw1NjMy
+MCsociYxMDIzKSl9ZWxzZSB0aHJvdyBILmIoSC5JKHIpKX1yZXR1cm4gSC5WSyhxKX0sCmVUOmZ1bmN0
+aW9uKGEpe3ZhciB0LHMscgpmb3IodD1hLmxlbmd0aCxzPTA7czx0Oysrcyl7cj1hW3NdCmlmKCFILm9r
+KHIpKXRocm93IEguYihILkkocikpCmlmKHI8MCl0aHJvdyBILmIoSC5JKHIpKQppZihyPjY1NTM1KXJl
+dHVybiBILkNxKGEpfXJldHVybiBILlZLKGEpfSwKZnc6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixx
+CmlmKGM8PTUwMCYmYj09PTAmJmM9PT1hLmxlbmd0aClyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZS5h
+cHBseShudWxsLGEpCmZvcih0PWIscz0iIjt0PGM7dD1yKXtyPXQrNTAwCnE9cjxjP3I6YwpzKz1TdHJp
+bmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsYS5zdWJhcnJheSh0LHEpKX1yZXR1cm4gc30sCkx3OmZ1
+bmN0aW9uKGEpe3ZhciB0CmlmKDA8PWEpe2lmKGE8PTY1NTM1KXJldHVybiBTdHJpbmcuZnJvbUNoYXJD
+b2RlKGEpCmlmKGE8PTExMTQxMTEpe3Q9YS02NTUzNgpyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSgo
+NTUyOTZ8Qy5qbi53Ryh0LDEwKSk+Pj4wLDU2MzIwfHQmMTAyMyl9fXRocm93IEguYihQLlRFKGEsMCwx
+MTE0MTExLG51bGwsbnVsbCkpfSwKbzI6ZnVuY3Rpb24oYSl7aWYoYS5kYXRlPT09dm9pZCAwKWEuZGF0
+ZT1uZXcgRGF0ZShhLmEpCnJldHVybiBhLmRhdGV9LAp0SjpmdW5jdGlvbihhKXt2YXIgdD1ILm8yKGEp
+LmdldEZ1bGxZZWFyKCkrMApyZXR1cm4gdH0sCk5TOmZ1bmN0aW9uKGEpe3ZhciB0PUgubzIoYSkuZ2V0
+TW9udGgoKSsxCnJldHVybiB0fSwKakE6ZnVuY3Rpb24oYSl7dmFyIHQ9SC5vMihhKS5nZXREYXRlKCkr
+MApyZXR1cm4gdH0sCklYOmZ1bmN0aW9uKGEpe3ZhciB0PUgubzIoYSkuZ2V0SG91cnMoKSswCnJldHVy
+biB0fSwKY2g6ZnVuY3Rpb24oYSl7dmFyIHQ9SC5vMihhKS5nZXRNaW51dGVzKCkrMApyZXR1cm4gdH0s
+CkpkOmZ1bmN0aW9uKGEpe3ZhciB0PUgubzIoYSkuZ2V0U2Vjb25kcygpKzAKcmV0dXJuIHR9LApWYTpm
+dW5jdGlvbihhKXt2YXIgdD1ILm8yKGEpLmdldE1pbGxpc2Vjb25kcygpKzAKcmV0dXJuIHR9LAp6bzpm
+dW5jdGlvbihhLGIsYyl7dmFyIHQscyxyPXt9CnIuYT0wCnQ9W10Kcz1bXQpyLmE9Yi5sZW5ndGgKQy5O
+bS5GVih0LGIpCnIuYj0iIgppZihjIT1udWxsJiZjLmEhPT0wKWMuSygwLG5ldyBILkNqKHIscyx0KSkK
+IiIrci5hCnJldHVybiBKLkp5KGEsbmV3IEguTEkoQy5UZSwwLHQscywwKSl9LApFazpmdW5jdGlvbihh
+LGIsYyl7dmFyIHQscyxyLHEKaWYoYiBpbnN0YW5jZW9mIEFycmF5KXQ9Yz09bnVsbHx8Yy5hPT09MApl
+bHNlIHQ9ITEKaWYodCl7cz1iCnI9cy5sZW5ndGgKaWYocj09PTApe2lmKCEhYS4kMClyZXR1cm4gYS4k
+MCgpfWVsc2UgaWYocj09PTEpe2lmKCEhYS4kMSlyZXR1cm4gYS4kMShzWzBdKX1lbHNlIGlmKHI9PT0y
+KXtpZighIWEuJDIpcmV0dXJuIGEuJDIoc1swXSxzWzFdKX1lbHNlIGlmKHI9PT0zKXtpZighIWEuJDMp
+cmV0dXJuIGEuJDMoc1swXSxzWzFdLHNbMl0pfWVsc2UgaWYocj09PTQpe2lmKCEhYS4kNClyZXR1cm4g
+YS4kNChzWzBdLHNbMV0sc1syXSxzWzNdKX1lbHNlIGlmKHI9PT01KWlmKCEhYS4kNSlyZXR1cm4gYS4k
+NShzWzBdLHNbMV0sc1syXSxzWzNdLHNbNF0pCnE9YVsiIisiJCIrcl0KaWYocSE9bnVsbClyZXR1cm4g
+cS5hcHBseShhLHMpfXJldHVybiBILkV3KGEsYixjKX0sCkV3OmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxz
+LHIscSxwLG8sbixtLGwsaz1iIGluc3RhbmNlb2YgQXJyYXk/YjpQLkNIKGIsITAsdS56KSxqPWsubGVu
+Z3RoLGk9YS4kUgppZihqPGkpcmV0dXJuIEguem8oYSxrLGMpCnQ9YS4kRApzPXQ9PW51bGwKcj0hcz90
+KCk6bnVsbApxPUouaWEoYSkKcD1xLiRDCmlmKHR5cGVvZiBwPT0ic3RyaW5nIilwPXFbcF0KaWYocyl7
+aWYoYyE9bnVsbCYmYy5hIT09MClyZXR1cm4gSC56byhhLGssYykKaWYoaj09PWkpcmV0dXJuIHAuYXBw
+bHkoYSxrKQpyZXR1cm4gSC56byhhLGssYyl9aWYociBpbnN0YW5jZW9mIEFycmF5KXtpZihjIT1udWxs
+JiZjLmEhPT0wKXJldHVybiBILnpvKGEsayxjKQppZihqPmkrci5sZW5ndGgpcmV0dXJuIEguem8oYSxr
+LG51bGwpCkMuTm0uRlYoayxyLnNsaWNlKGotaSkpCnJldHVybiBwLmFwcGx5KGEsayl9ZWxzZXtpZihq
+PmkpcmV0dXJuIEguem8oYSxrLGMpCm89T2JqZWN0LmtleXMocikKaWYoYz09bnVsbClmb3Iocz1vLmxl
+bmd0aCxuPTA7bjxvLmxlbmd0aDtvLmxlbmd0aD09PXN8fCgwLEgubGspKG8pLCsrbilDLk5tLmkoayxy
+W0guYyhvW25dKV0pCmVsc2V7Zm9yKHM9by5sZW5ndGgsbT0wLG49MDtuPG8ubGVuZ3RoO28ubGVuZ3Ro
+PT09c3x8KDAsSC5saykobyksKytuKXtsPUguYyhvW25dKQppZihjLng0KGwpKXsrK20KQy5ObS5pKGss
+Yy5xKDAsbCkpfWVsc2UgQy5ObS5pKGsscltsXSl9aWYobSE9PWMuYSlyZXR1cm4gSC56byhhLGssYyl9
+cmV0dXJuIHAuYXBwbHkoYSxrKX19LApwWTpmdW5jdGlvbihhKXt0aHJvdyBILmIoSC5JKGEpKX0sCms6
+ZnVuY3Rpb24oYSxiKXtpZihhPT1udWxsKUouSChhKQp0aHJvdyBILmIoSC5IWShhLGIpKX0sCkhZOmZ1
+bmN0aW9uKGEsYil7dmFyIHQscyxyPSJpbmRleCIKaWYoIUgub2soYikpcmV0dXJuIG5ldyBQLkFUKCEw
+LGIscixudWxsKQp0PUguV1koSi5IKGEpKQppZighKGI8MCkpe2lmKHR5cGVvZiB0IT09Im51bWJlciIp
+cmV0dXJuIEgucFkodCkKcz1iPj10fWVsc2Ugcz0hMAppZihzKXJldHVybiBQLnQoYixhLHIsbnVsbCx0
+KQpyZXR1cm4gUC5PNyhiLHIpfSwKYXU6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PSJJbnZhbGlkIHZhbHVl
+IgppZihhPmMpcmV0dXJuIG5ldyBQLmJKKDAsYywhMCxhLCJzdGFydCIsdCkKaWYoYiE9bnVsbCl7aWYo
+IUgub2soYikpcmV0dXJuIG5ldyBQLkFUKCEwLGIsImVuZCIsbnVsbCkKaWYoYjxhfHxiPmMpcmV0dXJu
+IG5ldyBQLmJKKGEsYywhMCxiLCJlbmQiLHQpfXJldHVybiBuZXcgUC5BVCghMCxiLCJlbmQiLG51bGwp
+fSwKSTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuQVQoITAsYSxudWxsLG51bGwpfSwKYjpmdW5jdGlv
+bihhKXt2YXIgdAppZihhPT1udWxsKWE9bmV3IFAuTEsoKQp0PW5ldyBFcnJvcigpCnQuZGFydEV4Y2Vw
+dGlvbj1hCmlmKCJkZWZpbmVQcm9wZXJ0eSIgaW4gT2JqZWN0KXtPYmplY3QuZGVmaW5lUHJvcGVydHko
+dCwibWVzc2FnZSIse2dldDpILkp1fSkKdC5uYW1lPSIifWVsc2UgdC50b1N0cmluZz1ILkp1CnJldHVy
+biB0fSwKSnU6ZnVuY3Rpb24oKXtyZXR1cm4gSi5BYyh0aGlzLmRhcnRFeGNlcHRpb24pfSwKdmg6ZnVu
+Y3Rpb24oYSl7dGhyb3cgSC5iKGEpfSwKbGs6ZnVuY3Rpb24oYSl7dGhyb3cgSC5iKFAuYTQoYSkpfSwK
+Y006ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvCmE9SC5lQShhLnJlcGxhY2UoU3RyaW5nKHt9KSwn
+JHJlY2VpdmVyJCcpKQp0PWEubWF0Y2goL1xcXCRbYS16QS1aXStcXFwkL2cpCmlmKHQ9PW51bGwpdD1I
+LlZNKFtdLHUucykKcz10LmluZGV4T2YoIlxcJGFyZ3VtZW50c1xcJCIpCnI9dC5pbmRleE9mKCJcXCRh
+cmd1bWVudHNFeHByXFwkIikKcT10LmluZGV4T2YoIlxcJGV4cHJcXCQiKQpwPXQuaW5kZXhPZigiXFwk
+bWV0aG9kXFwkIikKbz10LmluZGV4T2YoIlxcJHJlY2VpdmVyXFwkIikKcmV0dXJuIG5ldyBILmY5KGEu
+cmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFwkYXJndW1lbnRzXFxcXFxcJCcsJ2cnKSwnKCg/Onh8W154
+XSkqKScpLnJlcGxhY2UobmV3IFJlZ0V4cCgnXFxcXFxcJGFyZ3VtZW50c0V4cHJcXFxcXFwkJywnZycp
+LCcoKD86eHxbXnhdKSopJykucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFwkZXhwclxcXFxcXCQnLCdn
+JyksJygoPzp4fFteeF0pKiknKS5yZXBsYWNlKG5ldyBSZWdFeHAoJ1xcXFxcXCRtZXRob2RcXFxcXFwk
+JywnZycpLCcoKD86eHxbXnhdKSopJykucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxcXFwkcmVjZWl2ZXJc
+XFxcXFwkJywnZycpLCcoKD86eHxbXnhdKSopJykscyxyLHEscCxvKX0sClM3OmZ1bmN0aW9uKGEpe3Jl
+dHVybiBmdW5jdGlvbigkZXhwciQpe3ZhciAkYXJndW1lbnRzRXhwciQ9JyRhcmd1bWVudHMkJwp0cnl7
+JGV4cHIkLiRtZXRob2QkKCRhcmd1bWVudHNFeHByJCl9Y2F0Y2godCl7cmV0dXJuIHQubWVzc2FnZX19
+KGEpfSwKTWo6ZnVuY3Rpb24oYSl7cmV0dXJuIGZ1bmN0aW9uKCRleHByJCl7dHJ5eyRleHByJC4kbWV0
+aG9kJH1jYXRjaCh0KXtyZXR1cm4gdC5tZXNzYWdlfX0oYSl9LApJajpmdW5jdGlvbihhLGIpe3JldHVy
+biBuZXcgSC5XMChhLGI9PW51bGw/bnVsbDpiLm1ldGhvZCl9LApUMzpmdW5jdGlvbihhLGIpe3ZhciB0
+PWI9PW51bGwscz10P251bGw6Yi5tZXRob2QKcmV0dXJuIG5ldyBILmF6KGEscyx0P251bGw6Yi5yZWNl
+aXZlcil9LApSdTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGY9bnVs
+bCxlPW5ldyBILkFtKGEpCmlmKGE9PW51bGwpcmV0dXJuIGYKaWYoYSBpbnN0YW5jZW9mIEguYnEpcmV0
+dXJuIGUuJDEoYS5hKQppZih0eXBlb2YgYSE9PSJvYmplY3QiKXJldHVybiBhCmlmKCJkYXJ0RXhjZXB0
+aW9uIiBpbiBhKXJldHVybiBlLiQxKGEuZGFydEV4Y2VwdGlvbikKZWxzZSBpZighKCJtZXNzYWdlIiBp
+biBhKSlyZXR1cm4gYQp0PWEubWVzc2FnZQppZigibnVtYmVyIiBpbiBhJiZ0eXBlb2YgYS5udW1iZXI9
+PSJudW1iZXIiKXtzPWEubnVtYmVyCnI9cyY2NTUzNQppZigoQy5qbi53RyhzLDE2KSY4MTkxKT09PTEw
+KXN3aXRjaChyKXtjYXNlIDQzODpyZXR1cm4gZS4kMShILlQzKEguZCh0KSsiIChFcnJvciAiK3IrIiki
+LGYpKQpjYXNlIDQ0NTpjYXNlIDUwMDc6cmV0dXJuIGUuJDEoSC5JaihILmQodCkrIiAoRXJyb3IgIity
+KyIpIixmKSl9fWlmKGEgaW5zdGFuY2VvZiBUeXBlRXJyb3Ipe3E9JC5TbigpCnA9JC5scSgpCm89JC5O
+OSgpCm49JC5pSSgpCm09JC5VTigpCmw9JC5aaCgpCms9JC5yTigpCiQuYzMoKQpqPSQuSEsoKQppPSQu
+cjEoKQpoPXEucVModCkKaWYoaCE9bnVsbClyZXR1cm4gZS4kMShILlQzKEguYyh0KSxoKSkKZWxzZXto
+PXAucVModCkKaWYoaCE9bnVsbCl7aC5tZXRob2Q9ImNhbGwiCnJldHVybiBlLiQxKEguVDMoSC5jKHQp
+LGgpKX1lbHNle2g9by5xUyh0KQppZihoPT1udWxsKXtoPW4ucVModCkKaWYoaD09bnVsbCl7aD1tLnFT
+KHQpCmlmKGg9PW51bGwpe2g9bC5xUyh0KQppZihoPT1udWxsKXtoPWsucVModCkKaWYoaD09bnVsbCl7
+aD1uLnFTKHQpCmlmKGg9PW51bGwpe2g9ai5xUyh0KQppZihoPT1udWxsKXtoPWkucVModCkKZz1oIT1u
+dWxsfWVsc2UgZz0hMH1lbHNlIGc9ITB9ZWxzZSBnPSEwfWVsc2UgZz0hMH1lbHNlIGc9ITB9ZWxzZSBn
+PSEwfWVsc2UgZz0hMAppZihnKXJldHVybiBlLiQxKEguSWooSC5jKHQpLGgpKX19cmV0dXJuIGUuJDEo
+bmV3IEgudlYodHlwZW9mIHQ9PSJzdHJpbmciP3Q6IiIpKX1pZihhIGluc3RhbmNlb2YgUmFuZ2VFcnJv
+cil7aWYodHlwZW9mIHQ9PSJzdHJpbmciJiZ0LmluZGV4T2YoImNhbGwgc3RhY2siKSE9PS0xKXJldHVy
+biBuZXcgUC5LWSgpCnQ9ZnVuY3Rpb24oYil7dHJ5e3JldHVybiBTdHJpbmcoYil9Y2F0Y2goZCl7fXJl
+dHVybiBudWxsfShhKQpyZXR1cm4gZS4kMShuZXcgUC5BVCghMSxmLGYsdHlwZW9mIHQ9PSJzdHJpbmci
P3QucmVwbGFjZSgvXlJhbmdlRXJyb3I6XHMqLywiIik6dCkpfWlmKHR5cGVvZiBJbnRlcm5hbEVycm9y
PT0iZnVuY3Rpb24iJiZhIGluc3RhbmNlb2YgSW50ZXJuYWxFcnJvcilpZih0eXBlb2YgdD09InN0cmlu
ZyImJnQ9PT0idG9vIG11Y2ggcmVjdXJzaW9uIilyZXR1cm4gbmV3IFAuS1koKQpyZXR1cm4gYX0sCnRz
@@ -862,7 +1025,7 @@
bClyZXR1cm4gbmV3IEguWE8oYSkKdD1hLiRjYWNoZWRUcmFjZQppZih0IT1udWxsKXJldHVybiB0CnJl
dHVybiBhLiRjYWNoZWRUcmFjZT1uZXcgSC5YTyhhKX0sCkI3OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxy
LHE9YS5sZW5ndGgKZm9yKHQ9MDt0PHE7dD1yKXtzPXQrMQpyPXMrMQpiLlkoMCxhW3RdLGFbc10pfXJl
-dHVybiBifSwKZnQ6ZnVuY3Rpb24oYSxiLGMsZCxlLGYpe3UuWi5iKGEpCnN3aXRjaChILlNjKGIpKXtj
+dHVybiBifSwKZnQ6ZnVuY3Rpb24oYSxiLGMsZCxlLGYpe3UuWi5hKGEpCnN3aXRjaChILldZKGIpKXtj
YXNlIDA6cmV0dXJuIGEuJDAoKQpjYXNlIDE6cmV0dXJuIGEuJDEoYykKY2FzZSAyOnJldHVybiBhLiQy
KGMsZCkKY2FzZSAzOnJldHVybiBhLiQzKGMsZCxlKQpjYXNlIDQ6cmV0dXJuIGEuJDQoYyxkLGUsZil9
dGhyb3cgSC5iKG5ldyBQLkNEKCJVbnN1cHBvcnRlZCBudW1iZXIgb2YgYXJndW1lbnRzIGZvciB3cmFw
@@ -871,7 +1034,7 @@
bmN0aW9uKGYsZyxoLGkpe3JldHVybiBlKGMsZCxmLGcsaCxpKX19KGEsYixILmZ0KQphLiRpZGVudGl0
eT10CnJldHVybiB0fSwKaUE6ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyl7dmFyIHQscyxyLHEscCxvLG4s
bSxsPW51bGwsaz1iWzBdLGo9ay4kY2FsbE5hbWUsaT1lP09iamVjdC5jcmVhdGUobmV3IEguengoKS5j
-b25zdHJ1Y3Rvci5wcm90b3R5cGUpOk9iamVjdC5jcmVhdGUobmV3IEguclQobCxsLGwsbCkuY29uc3Ry
+b25zdHJ1Y3Rvci5wcm90b3R5cGUpOk9iamVjdC5jcmVhdGUobmV3IEguankobCxsLGwsbCkuY29uc3Ry
dWN0b3IucHJvdG90eXBlKQppLiRpbml0aWFsaXplPWkuY29uc3RydWN0b3IKaWYoZSl0PWZ1bmN0aW9u
IHN0YXRpY190ZWFyX29mZigpe3RoaXMuJGluaXRpYWxpemUoKX0KZWxzZXtzPSQueWoKaWYodHlwZW9m
IHMhPT0ibnVtYmVyIilyZXR1cm4gcy5oKCkKJC55aj1zKzEKcz1uZXcgRnVuY3Rpb24oImEsYixjLGQi
@@ -932,1166 +1095,1210 @@
KHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuaCgpCiQueWo9dCsxCnJldHVybiBuZXcgRnVuY3Rp
b24obSt0KyJ9IikoKX0sCktxOmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcpe3JldHVybiBILmlBKGEsYixj
LGQsISFlLCEhZixnKX0sClRuOmZ1bmN0aW9uKGEsYil7cmV0dXJuIEguY0Uodi50eXBlVW5pdmVyc2Us
-SC56SyhhLmEpLGIpfSwKUFc6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSC5jRSh2LnR5cGVVbml2ZXJzZSxI
-LnpLKGEuYyksYil9LApEVjpmdW5jdGlvbihhKXtyZXR1cm4gYS5hfSwKeVM6ZnVuY3Rpb24oYSl7cmV0
-dXJuIGEuY30sCkUyOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPW5ldyBILnJUKCJzZWxmIiwidGFyZ2V0
-IiwicmVjZWl2ZXIiLCJuYW1lIikscD1KLkVwKE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKHEpKQpm
-b3IodD1wLmxlbmd0aCxzPTA7czx0Oysrcyl7cj1wW3NdCmlmKHFbcl09PT1hKXJldHVybiByfX0sCm9U
-OmZ1bmN0aW9uKGEpe2lmKGE9PW51bGwpSC5mTygiYm9vbGVhbiBleHByZXNzaW9uIG11c3Qgbm90IGJl
-IG51bGwiKQpyZXR1cm4gYX0sCmZPOmZ1bmN0aW9uKGEpe3Rocm93IEguYihuZXcgSC5rWShhKSl9LAph
-ZzpmdW5jdGlvbihhKXt0aHJvdyBILmIobmV3IFAuYyhhKSl9LApFZjpmdW5jdGlvbihhKXtyZXR1cm4g
-bmV3IEguRXEoYSl9LApZZzpmdW5jdGlvbihhKXtyZXR1cm4gdi5nZXRJc29sYXRlVGFnKGEpfSwKVk06
-ZnVuY3Rpb24oYSxiKXthLiR0aT1iCnJldHVybiBhfSwKb1g6ZnVuY3Rpb24oYSl7aWYoYT09bnVsbCly
-ZXR1cm4gbnVsbApyZXR1cm4gYS4kdGl9LApJTTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIEguWTkoYVsi
-JGEiK0guZChjKV0sSC5vWChiKSl9LApZOTpmdW5jdGlvbihhLGIpe2lmKGE9PW51bGwpcmV0dXJuIGIK
-YT1hLmFwcGx5KG51bGwsYikKaWYoYT09bnVsbClyZXR1cm4gbnVsbAppZihBcnJheS5pc0FycmF5KGEp
-KXJldHVybiBhCmlmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBhLmFwcGx5KG51bGwsYikKcmV0
-dXJuIGJ9LApJRzpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGEuYXBwbHkoYixILlk5KEouaWEoYilbIiRh
-IitILmQoYyldLEgub1goYikpKX0sCml3OmZ1bmN0aW9uKGEsYixjKXtPYmplY3QuZGVmaW5lUHJvcGVy
-dHkoYSxiLHt2YWx1ZTpjLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFibGU6
-dHJ1ZX0pfSwKdzM6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscD1ILnkoJC5ORi4kMShhKSksbz0kLm53
+SC5xKGEuYSksYil9LApQVzpmdW5jdGlvbihhLGIpe3JldHVybiBILmNFKHYudHlwZVVuaXZlcnNlLEgu
+cShhLmMpLGIpfSwKRFY6ZnVuY3Rpb24oYSl7cmV0dXJuIGEuYX0sCnlTOmZ1bmN0aW9uKGEpe3JldHVy
+biBhLmN9LApFMjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1uZXcgSC5qeSgic2VsZiIsInRhcmdldCIs
+InJlY2VpdmVyIiwibmFtZSIpLHA9Si5FcChPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhxKSkKZm9y
+KHQ9cC5sZW5ndGgscz0wO3M8dDsrK3Mpe3I9cFtzXQppZihxW3JdPT09YSlyZXR1cm4gcn19LApvVDpm
+dW5jdGlvbihhKXtpZihhPT1udWxsKUguZk8oImJvb2xlYW4gZXhwcmVzc2lvbiBtdXN0IG5vdCBiZSBu
+dWxsIikKcmV0dXJuIGF9LApmTzpmdW5jdGlvbihhKXt0aHJvdyBILmIobmV3IEgua1koYSkpfSwKYWc6
+ZnVuY3Rpb24oYSl7dGhyb3cgSC5iKG5ldyBQLnQ3KGEpKX0sCkVmOmZ1bmN0aW9uKGEpe3JldHVybiBu
+ZXcgSC5FcShhKX0sCllnOmZ1bmN0aW9uKGEpe3JldHVybiB2LmdldElzb2xhdGVUYWcoYSl9LApWTTpm
+dW5jdGlvbihhLGIpe2Fbdi5hcnJheVJ0aV09YgpyZXR1cm4gYX0sCm9YOmZ1bmN0aW9uKGEpe2lmKGE9
+PW51bGwpcmV0dXJuIG51bGwKcmV0dXJuIGEuJHRpfSwKSU06ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBI
+Llk5KGFbIiRhIitILmQoYyldLEgub1goYikpfSwKWTk6ZnVuY3Rpb24oYSxiKXtpZihhPT1udWxsKXJl
+dHVybiBiCmE9YS5hcHBseShudWxsLGIpCmlmKGE9PW51bGwpcmV0dXJuIG51bGwKaWYoQXJyYXkuaXNB
+cnJheShhKSlyZXR1cm4gYQppZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gYS5hcHBseShudWxs
+LGIpCnJldHVybiBifSwKSUc6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBhLmFwcGx5KGIsSC5ZOShKLmlh
+KGIpWyIkYSIrSC5kKGMpXSxILm9YKGIpKSl9LAppdzpmdW5jdGlvbihhLGIsYyl7T2JqZWN0LmRlZmlu
+ZVByb3BlcnR5KGEsYix7dmFsdWU6YyxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsY29uZmln
+dXJhYmxlOnRydWV9KX0sCkc6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscD1ILmMoJC55LiQxKGEpKSxv
+PSQualtwXQppZihvIT1udWxsKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoYSx2LmRpc3BhdGNoUHJvcGVy
+dHlOYW1lLHt2YWx1ZTpvLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFibGU6
+dHJ1ZX0pCnJldHVybiBvLml9dD0kLnZbcF0KaWYodCE9bnVsbClyZXR1cm4gdApzPXYuaW50ZXJjZXB0
+b3JzQnlUYWdbcF0KaWYocz09bnVsbCl7cD1ILmMoJC51LiQyKGEscCkpCmlmKHAhPW51bGwpe289JC5q
W3BdCmlmKG8hPW51bGwpe09iamVjdC5kZWZpbmVQcm9wZXJ0eShhLHYuZGlzcGF0Y2hQcm9wZXJ0eU5h
bWUse3ZhbHVlOm8sZW51bWVyYWJsZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVl
-fSkKcmV0dXJuIG8uaX10PSQudnZbcF0KaWYodCE9bnVsbClyZXR1cm4gdApzPXYuaW50ZXJjZXB0b3Jz
-QnlUYWdbcF0KaWYocz09bnVsbCl7cD1ILnkoJC5UWC4kMihhLHApKQppZihwIT1udWxsKXtvPSQubndb
-cF0KaWYobyE9bnVsbCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGEsdi5kaXNwYXRjaFByb3BlcnR5TmFt
-ZSx7dmFsdWU6byxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9
-KQpyZXR1cm4gby5pfXQ9JC52dltwXQppZih0IT1udWxsKXJldHVybiB0CnM9di5pbnRlcmNlcHRvcnNC
+fSkKcmV0dXJuIG8uaX10PSQudltwXQppZih0IT1udWxsKXJldHVybiB0CnM9di5pbnRlcmNlcHRvcnNC
eVRhZ1twXX19aWYocz09bnVsbClyZXR1cm4gbnVsbAp0PXMucHJvdG90eXBlCnI9cFswXQppZihyPT09
-IiEiKXtvPUguVmEodCkKJC5ud1twXT1vCk9iamVjdC5kZWZpbmVQcm9wZXJ0eShhLHYuZGlzcGF0Y2hQ
-cm9wZXJ0eU5hbWUse3ZhbHVlOm8sZW51bWVyYWJsZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3Vy
-YWJsZTp0cnVlfSkKcmV0dXJuIG8uaX1pZihyPT09In4iKXskLnZ2W3BdPXQKcmV0dXJuIHR9aWYocj09
-PSItIil7cT1ILlZhKHQpCk9iamVjdC5kZWZpbmVQcm9wZXJ0eShPYmplY3QuZ2V0UHJvdG90eXBlT2Yo
-YSksdi5kaXNwYXRjaFByb3BlcnR5TmFtZSx7dmFsdWU6cSxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxl
-OnRydWUsY29uZmlndXJhYmxlOnRydWV9KQpyZXR1cm4gcS5pfWlmKHI9PT0iKyIpcmV0dXJuIEguTGMo
-YSx0KQppZihyPT09IioiKXRocm93IEguYihQLlNZKHApKQppZih2LmxlYWZUYWdzW3BdPT09dHJ1ZSl7
-cT1ILlZhKHQpCk9iamVjdC5kZWZpbmVQcm9wZXJ0eShPYmplY3QuZ2V0UHJvdG90eXBlT2YoYSksdi5k
-aXNwYXRjaFByb3BlcnR5TmFtZSx7dmFsdWU6cSxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUs
-Y29uZmlndXJhYmxlOnRydWV9KQpyZXR1cm4gcS5pfWVsc2UgcmV0dXJuIEguTGMoYSx0KX0sCkxjOmZ1
-bmN0aW9uKGEsYil7dmFyIHQ9T2JqZWN0LmdldFByb3RvdHlwZU9mKGEpCk9iamVjdC5kZWZpbmVQcm9w
-ZXJ0eSh0LHYuZGlzcGF0Y2hQcm9wZXJ0eU5hbWUse3ZhbHVlOkouUXUoYix0LG51bGwsbnVsbCksZW51
-bWVyYWJsZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIGJ9LApW
-YTpmdW5jdGlvbihhKXtyZXR1cm4gSi5RdShhLCExLG51bGwsISFhLiRpWGopfSwKVkY6ZnVuY3Rpb24o
-YSxiLGMpe3ZhciB0PWIucHJvdG90eXBlCmlmKHYubGVhZlRhZ3NbYV09PT10cnVlKXJldHVybiBILlZh
-KHQpCmVsc2UgcmV0dXJuIEouUXUodCxjLG51bGwsbnVsbCl9LApYRDpmdW5jdGlvbigpe2lmKCEwPT09
-JC5CdilyZXR1cm4KJC5Cdj0hMApILloxKCl9LApaMTpmdW5jdGlvbigpe3ZhciB0LHMscixxLHAsbyxu
-LG0KJC5udz1PYmplY3QuY3JlYXRlKG51bGwpCiQudnY9T2JqZWN0LmNyZWF0ZShudWxsKQpILmtPKCkK
-dD12LmludGVyY2VwdG9yc0J5VGFnCnM9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModCkKaWYodHlw
-ZW9mIHdpbmRvdyE9InVuZGVmaW5lZCIpe3dpbmRvdwpyPWZ1bmN0aW9uKCl7fQpmb3IocT0wO3E8cy5s
-ZW5ndGg7KytxKXtwPXNbcV0Kbz0kLng3LiQxKHApCmlmKG8hPW51bGwpe249SC5WRihwLHRbcF0sbykK
-aWYobiE9bnVsbCl7T2JqZWN0LmRlZmluZVByb3BlcnR5KG8sdi5kaXNwYXRjaFByb3BlcnR5TmFtZSx7
-dmFsdWU6bixlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9KQpy
-LnByb3RvdHlwZT1vfX19fWZvcihxPTA7cTxzLmxlbmd0aDsrK3Epe3A9c1txXQppZigvXltBLVphLXpf
-XS8udGVzdChwKSl7bT10W3BdCnRbIiEiK3BdPW0KdFsifiIrcF09bQp0WyItIitwXT1tCnRbIisiK3Bd
-PW0KdFsiKiIrcF09bX19fSwKa086ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwLG8sbj1DLllxKCkKbj1I
-LnVkKEMuS1UsSC51ZChDLmZRLEgudWQoQy5pNyxILnVkKEMuaTcsSC51ZChDLnhpLEgudWQoQy5kayxI
-LnVkKEMud2IoQy5PNCksbikpKSkpKSkKaWYodHlwZW9mIGRhcnROYXRpdmVEaXNwYXRjaEhvb2tzVHJh
-bnNmb3JtZXIhPSJ1bmRlZmluZWQiKXt0PWRhcnROYXRpdmVEaXNwYXRjaEhvb2tzVHJhbnNmb3JtZXIK
-aWYodHlwZW9mIHQ9PSJmdW5jdGlvbiIpdD1bdF0KaWYodC5jb25zdHJ1Y3Rvcj09QXJyYXkpZm9yKHM9
-MDtzPHQubGVuZ3RoOysrcyl7cj10W3NdCmlmKHR5cGVvZiByPT0iZnVuY3Rpb24iKW49cihuKXx8bn19
-cT1uLmdldFRhZwpwPW4uZ2V0VW5rbm93blRhZwpvPW4ucHJvdG90eXBlRm9yVGFnCiQuTkY9bmV3IEgu
-ZEMocSkKJC5UWD1uZXcgSC53TihwKQokLng3PW5ldyBILlZYKG8pfSwKdWQ6ZnVuY3Rpb24oYSxiKXty
-ZXR1cm4gYShiKXx8Yn0sCnY0OmZ1bmN0aW9uKGEsYixjLGQsZSxmKXt2YXIgdD1iPyJtIjoiIixzPWM/
-IiI6ImkiLHI9ZD8idSI6IiIscT1lPyJzIjoiIixwPWY/ImciOiIiLG89ZnVuY3Rpb24oZyxoKXt0cnl7
-cmV0dXJuIG5ldyBSZWdFeHAoZyxoKX1jYXRjaChuKXtyZXR1cm4gbn19KGEsdCtzK3IrcStwKQppZihv
-IGluc3RhbmNlb2YgUmVnRXhwKXJldHVybiBvCnRocm93IEguYihQLnJyKCJJbGxlZ2FsIFJlZ0V4cCBw
-YXR0ZXJuICgiK1N0cmluZyhvKSsiKSIsYSxudWxsKSl9LAptMjpmdW5jdGlvbihhLGIsYyl7dmFyIHQK
-aWYodHlwZW9mIGI9PSJzdHJpbmciKXJldHVybiBhLmluZGV4T2YoYixjKT49MAplbHNlIGlmKGIgaW5z
-dGFuY2VvZiBILlZSKXt0PUMueEIuRyhhLGMpCnJldHVybiBiLmIudGVzdCh0KX1lbHNle3Q9Si5GTChi
-LEMueEIuRyhhLGMpKQpyZXR1cm4hdC5nbDAodCl9fSwKQTQ6ZnVuY3Rpb24oYSl7aWYoYS5pbmRleE9m
-KCIkIiwwKT49MClyZXR1cm4gYS5yZXBsYWNlKC9cJC9nLCIkJCQkIikKcmV0dXJuIGF9LAplQTpmdW5j
-dGlvbihhKXtpZigvW1tcXXt9KCkqKz8uXFxeJHxdLy50ZXN0KGEpKXJldHVybiBhLnJlcGxhY2UoL1tb
-XF17fSgpKis/LlxcXiR8XS9nLCJcXCQmIikKcmV0dXJuIGF9LAp5czpmdW5jdGlvbihhLGIsYyl7dmFy
-IHQ9SC5uTShhLGIsYykKcmV0dXJuIHR9LApuTTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEKaWYo
-Yj09PSIiKXtpZihhPT09IiIpcmV0dXJuIGMKdD1hLmxlbmd0aApmb3Iocz1jLHI9MDtyPHQ7KytyKXM9
-cythW3JdK2MKcmV0dXJuIHMuY2hhckNvZGVBdCgwKT09MD9zOnN9cT1hLmluZGV4T2YoYiwwKQppZihx
-PDApcmV0dXJuIGEKaWYoYS5sZW5ndGg8NTAwfHxjLmluZGV4T2YoIiQiLDApPj0wKXJldHVybiBhLnNw
-bGl0KGIpLmpvaW4oYykKcmV0dXJuIGEucmVwbGFjZShuZXcgUmVnRXhwKEguZUEoYiksJ2cnKSxILkE0
-KGMpKX0sClBEOmZ1bmN0aW9uIFBEKGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCldVOmZ1bmN0aW9u
-IFdVKCl7fSwKTFA6ZnVuY3Rpb24gTFAoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9
-YwpfLiR0aT1kfSwKWFI6ZnVuY3Rpb24gWFIoYSxiKXt0aGlzLmE9YQp0aGlzLiR0aT1ifSwKTEk6ZnVu
-Y3Rpb24gTEkoYSxiLGMsZCxlKXt2YXIgXz10aGlzCl8uYT1hCl8uYz1iCl8uZD1jCl8uZT1kCl8uZj1l
-fSwKQ2o6ZnVuY3Rpb24gQ2ooYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKZjk6ZnVu
-Y3Rpb24gZjkoYSxiLGMsZCxlLGYpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWQKXy5l
-PWUKXy5mPWZ9LApXMDpmdW5jdGlvbiBXMChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKYXo6ZnVuY3Rp
-b24gYXooYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKdlY6ZnVuY3Rpb24gdlYoYSl7
-dGhpcy5hPWF9LApicTpmdW5jdGlvbiBicShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKQW06ZnVuY3Rp
-b24gQW0oYSl7dGhpcy5hPWF9LApYTzpmdW5jdGlvbiBYTyhhKXt0aGlzLmE9YQp0aGlzLmI9bnVsbH0s
-ClRwOmZ1bmN0aW9uIFRwKCl7fSwKbGM6ZnVuY3Rpb24gbGMoKXt9LAp6eDpmdW5jdGlvbiB6eCgpe30s
-CnJUOmZ1bmN0aW9uIHJUKGEsYixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWR9
-LApFcTpmdW5jdGlvbiBFcShhKXt0aGlzLmE9YX0sCmtZOmZ1bmN0aW9uIGtZKGEpe3RoaXMuYT1hfSwK
-TjU6ZnVuY3Rpb24gTjUoYSl7dmFyIF89dGhpcwpfLmE9MApfLmY9Xy5lPV8uZD1fLmM9Xy5iPW51bGwK
-Xy5yPTAKXy4kdGk9YX0sCmRiOmZ1bmN0aW9uIGRiKGEsYil7dmFyIF89dGhpcwpfLmE9YQpfLmI9Ygpf
-LmQ9Xy5jPW51bGx9LAppNTpmdW5jdGlvbiBpNShhLGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApONjpm
-dW5jdGlvbiBONihhLGIsYyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmQ9Xy5jPW51bGwKXy4kdGk9
-Y30sCmRDOmZ1bmN0aW9uIGRDKGEpe3RoaXMuYT1hfSwKd046ZnVuY3Rpb24gd04oYSl7dGhpcy5hPWF9
-LApWWDpmdW5jdGlvbiBWWChhKXt0aGlzLmE9YX0sClZSOmZ1bmN0aW9uIFZSKGEsYil7dmFyIF89dGhp
-cwpfLmE9YQpfLmI9YgpfLmQ9Xy5jPW51bGx9LApFSzpmdW5jdGlvbiBFSyhhKXt0aGlzLmI9YX0sCktX
-OmZ1bmN0aW9uIEtXKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sClBiOmZ1bmN0aW9u
-IFBiKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1udWxsfSwKdFE6ZnVuY3Rp
-b24gdFEoYSxiKXt0aGlzLmE9YQp0aGlzLmM9Yn0sCnVuOmZ1bmN0aW9uIHVuKGEsYixjKXt0aGlzLmE9
-YQp0aGlzLmI9Ygp0aGlzLmM9Y30sClNkOmZ1bmN0aW9uIFNkKGEsYixjKXt2YXIgXz10aGlzCl8uYT1h
-Cl8uYj1iCl8uYz1jCl8uZD1udWxsfSwKWEY6ZnVuY3Rpb24oYSl7cmV0dXJuIGF9LApEUTpmdW5jdGlv
-bihhKXtyZXR1cm4gbmV3IEludDhBcnJheShhKX0sCm9kOmZ1bmN0aW9uKGEsYixjKXtpZihhPj4+MCE9
-PWF8fGE+PWMpdGhyb3cgSC5iKEguSFkoYixhKSl9LApyTTpmdW5jdGlvbihhLGIsYyl7dmFyIHQKaWYo
-IShhPj4+MCE9PWEpKXQ9Yj4+PjAhPT1ifHxhPmJ8fGI+YwplbHNlIHQ9ITAKaWYodCl0aHJvdyBILmIo
-SC5hdShhLGIsYykpCnJldHVybiBifSwKRVQ6ZnVuY3Rpb24gRVQoKXt9LApMWjpmdW5jdGlvbiBMWigp
-e30sCkRnOmZ1bmN0aW9uIERnKCl7fSwKUGc6ZnVuY3Rpb24gUGcoKXt9LAp4ajpmdW5jdGlvbiB4aigp
-e30sCmRFOmZ1bmN0aW9uIGRFKCl7fSwKWkE6ZnVuY3Rpb24gWkEoKXt9LAp3ZjpmdW5jdGlvbiB3Zigp
-e30sClBxOmZ1bmN0aW9uIFBxKCl7fSwKZUU6ZnVuY3Rpb24gZUUoKXt9LApWNjpmdW5jdGlvbiBWNigp
-e30sClJHOmZ1bmN0aW9uIFJHKCl7fSwKVlA6ZnVuY3Rpb24gVlAoKXt9LApXQjpmdW5jdGlvbiBXQigp
-e30sClpHOmZ1bmN0aW9uIFpHKCl7fSwKeFo6ZnVuY3Rpb24oYSxiKXt2YXIgdD1iLmQKcmV0dXJuIHQ9
-PW51bGw/Yi5kPUguSihhLCJiOCIsW2IuUV0pOnR9LApRMTpmdW5jdGlvbihhKXt2YXIgdD1hLnoKaWYo
-dD09PTZ8fHQ9PT03fHx0PT09OClyZXR1cm4gSC5RMShhLlEpCnJldHVybiB0PT09MTF8fHQ9PT0xMn0s
-Cm1EOmZ1bmN0aW9uKGEpe3JldHVybiBhLmRifSwKTjA6ZnVuY3Rpb24oYSl7cmV0dXJuIEguRSh2LnR5
-cGVVbml2ZXJzZSxhKX0sCkpTOmZ1bmN0aW9uKGEpe3ZhciB0PWEuJFMKaWYodCE9bnVsbCl7aWYodHlw
-ZW9mIHQ9PSJudW1iZXIiKXJldHVybiBILkJwKHQpCnJldHVybiBhLiRTKCl9cmV0dXJuIG51bGx9LApV
-ZTpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKEguUTEoYikpaWYoYSBpbnN0YW5jZW9mIEguVHApe3Q9SC5K
-UyhhKQppZih0IT1udWxsKXJldHVybiB0fXJldHVybiBILnpLKGEpfSwKeks6ZnVuY3Rpb24oYSl7dmFy
-IHQKaWYoYSBpbnN0YW5jZW9mIFAuayl7dD1hLiR0aQpyZXR1cm4gdCE9bnVsbD90OkguVlUoYSl9aWYo
-QXJyYXkuaXNBcnJheShhKSlyZXR1cm4gSC50NihhKQpyZXR1cm4gSC5WVShKLmlhKGEpKX0sCnQ2OmZ1
-bmN0aW9uKGEpe3ZhciB0PWEuJHRpLHM9dS5iCmlmKHQ9PW51bGwpcmV0dXJuIHMKaWYodC5jb25zdHJ1
-Y3RvciE9PXMuY29uc3RydWN0b3IpcmV0dXJuIHMKcmV0dXJuIHR9LApMaDpmdW5jdGlvbihhKXt2YXIg
-dD1hLiR0aQpyZXR1cm4gdCE9bnVsbD90OkguVlUoYSl9LApWVTpmdW5jdGlvbihhKXt2YXIgdD1hLmNv
-bnN0cnVjdG9yLHM9dC4kY2NhY2hlCmlmKHMhPW51bGwpcmV0dXJuIHMKcmV0dXJuIEgucjkoYSx0KX0s
-CnI5OmZ1bmN0aW9uKGEsYil7dmFyIHQ9YSBpbnN0YW5jZW9mIEguVHA/YS5fX3Byb3RvX18uX19wcm90
-b19fLmNvbnN0cnVjdG9yOmIscz1ILmFpKHYudHlwZVVuaXZlcnNlLHQubmFtZSkKYi4kY2NhY2hlPXMK
-cmV0dXJuIHN9LApCcDpmdW5jdGlvbihhKXt2YXIgdCxzPWEscj12LnR5cGVzLHE9cltzXQppZih0eXBl
-b2YgcT09InN0cmluZyIpe3Q9SC5FKHYudHlwZVVuaXZlcnNlLHEpCnJbc109dApyZXR1cm4gdH1yZXR1
-cm4gcX0sCkpKOmZ1bmN0aW9uKGEpe3ZhciB0LHM9dGhpcyxyPXMueixxPUguWU8KaWYoSC5jYyhzKSl7
-cT1ILkl3CnMuYj1zLmE9SC5obn1lbHNlIGlmKHI9PT05KXt0PXMuZGIKaWYoIktOIj09PXQpcT1ILm9r
-CmVsc2UgaWYoIkNQIj09PXQpcT1ILktICmVsc2UgaWYoIkZLIj09PXQpcT1ILktICmVsc2UgaWYoInFV
-Ij09PXQpcT1ILk1NCmVsc2UgaWYoImEyIj09PXQpcT1ILmwKZWxzZXtyPXMuUQppZihzLmNoLmV2ZXJ5
-KEguY2MpKXtzLng9IiRpIityCnE9SC50NH19fXMuYz1xCnJldHVybiBzLmMoYSl9LApZTzpmdW5jdGlv
-bihhKXt2YXIgdD10aGlzCnJldHVybiBILldlKHYudHlwZVVuaXZlcnNlLEguVWUoYSx0KSxudWxsLHQs
-bnVsbCl9LAp0NDpmdW5jdGlvbihhKXt2YXIgdD10aGlzLngKaWYoYSBpbnN0YW5jZW9mIFAuaylyZXR1
-cm4hIWFbdF0KcmV0dXJuISFKLmlhKGEpW3RdfSwKT3o6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT09bnVs
-bClyZXR1cm4gYQp0PXRoaXMKaWYodC5jKGEpKXJldHVybiBhCnRocm93IEguYihILlE1KEguV0soYSxI
-LlVlKGEsdCksSC5kbSh0LG51bGwpKSkpfSwKQXY6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT09bnVsbCly
-ZXR1cm4gYQp0PXRoaXMKaWYodC5jKGEpKXJldHVybiBhCnRocm93IEguYihILlpjKEguV0soYSxILlVl
-KGEsdCksSC5kbSh0LG51bGwpKSkpfSwKRGg6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQ9bnVsbAppZihI
-LldlKHYudHlwZVVuaXZlcnNlLGEsdCxiLHQpKXJldHVybiBhCnRocm93IEguYihILlpjKCJUaGUgdHlw
-ZSBhcmd1bWVudCAnIitILmQoSC5kbShhLHQpKSsiJyBpcyBub3QgYSBzdWJ0eXBlIG9mIHRoZSB0eXBl
-IHZhcmlhYmxlIGJvdW5kICciK0guZChILmRtKGIsdCkpKyInIG9mIHR5cGUgdmFyaWFibGUgJyIrYysi
-JyBpbiAnIitILmQoZCkrIicuIikpfSwKV0s6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PVAucChhKSxzPUgu
-ZG0oYj09bnVsbD9ILnpLKGEpOmIsbnVsbCkKcmV0dXJuIHQrIjogdHlwZSAnIitILmQocykrIicgaXMg
-bm90IGEgc3VidHlwZSBvZiB0eXBlICciK0guZChjKSsiJyJ9LApRNTpmdW5jdGlvbihhKXtyZXR1cm4g
-bmV3IEguaHooIkNhc3RFcnJvcjogIithKX0sClB2OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBILmh6
-KCJDYXN0RXJyb3I6ICIrSC5XSyhhLG51bGwsYikpfSwKWmM6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBI
-LmlNKCJUeXBlRXJyb3I6ICIrYSl9LApxOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBILmlNKCJUeXBl
-RXJyb3I6ICIrSC5XSyhhLG51bGwsYikpfSwKSXc6ZnVuY3Rpb24oYSl7cmV0dXJuITB9LApobjpmdW5j
-dGlvbihhKXtyZXR1cm4gYX0sCmw6ZnVuY3Rpb24oYSl7cmV0dXJuITA9PT1hfHwhMT09PWF9LApFOTpm
-dW5jdGlvbihhKXtpZighMD09PWF8fCExPT09YSlyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRo
-cm93IEguYihILlB2KGEsImJvb2wiKSl9LAp4ZDpmdW5jdGlvbihhKXtpZighMD09PWF8fCExPT09YSly
-ZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILnEoYSwiYm9vbCIpKX0sCmRqOmZ1
-bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIilyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBh
-CnRocm93IEguYihILlB2KGEsImRvdWJsZSIpKX0sCklnOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0i
-bnVtYmVyIilyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILnEoYSwiZG91Ymxl
-IikpfSwKb2s6ZnVuY3Rpb24oYSl7cmV0dXJuIHR5cGVvZiBhPT0ibnVtYmVyIiYmTWF0aC5mbG9vcihh
-KT09PWF9LApXWTpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJlciImJk1hdGguZmxvb3IoYSk9
-PT1hKXJldHVybiBhCmlmKGE9PW51bGwpcmV0dXJuIGEKdGhyb3cgSC5iKEguUHYoYSwiaW50IikpfSwK
-U2M6ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJudW1iZXIiJiZNYXRoLmZsb29yKGEpPT09YSlyZXR1
-cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILnEoYSwiaW50IikpfSwKS0g6ZnVuY3Rp
-b24oYSl7cmV0dXJuIHR5cGVvZiBhPT0ibnVtYmVyIn0sClZZOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBh
-PT0ibnVtYmVyIilyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILlB2KGEsIm51
-bSIpKX0sCkROOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIilyZXR1cm4gYQppZihhPT1u
-dWxsKXJldHVybiBhCnRocm93IEguYihILnEoYSwibnVtIikpfSwKTU06ZnVuY3Rpb24oYSl7cmV0dXJu
-IHR5cGVvZiBhPT0ic3RyaW5nIn0sCmMwOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ic3RyaW5nIily
-ZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILlB2KGEsIlN0cmluZyIpKX0sCnk6
-ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJzdHJpbmciKXJldHVybiBhCmlmKGE9PW51bGwpcmV0dXJu
-IGEKdGhyb3cgSC5iKEgucShhLCJTdHJpbmciKSl9LAppbzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscgpm
-b3IodD0iIixzPSIiLHI9MDtyPGEubGVuZ3RoOysrcixzPSIsICIpdCs9Qy54Qi5oKHMsSC5kbShhW3Jd
-LGIpKQpyZXR1cm4gdH0sCmJJOmZ1bmN0aW9uKGEwLGExLGEyKXt2YXIgdCxzLHIscSxwLG8sbixtLGws
-ayxqLGksaCxnLGYsZSxkLGMsYixhPSIsICIKaWYoYTIhPW51bGwpe3Q9YTIubGVuZ3RoCmlmKGExPT1u
-dWxsKXthMT1ILlZNKFtdLHUucykKcz1udWxsfWVsc2Ugcz1hMS5sZW5ndGgKcj1hMS5sZW5ndGgKZm9y
-KHE9dDtxPjA7LS1xKUMuTm0uaShhMSwiVCIrKHIrcSkpCmZvcihwPSI8IixvPSIiLHE9MDtxPHQ7Kytx
-LG89YSl7cCs9bwpuPWExLmxlbmd0aAptPW4tMS1xCmlmKG08MClyZXR1cm4gSC5PSChhMSxtKQpwPUMu
-eEIuaChwLGExW21dKQpsPWEyW3FdCmlmKCFILmNjKGwpKXArPUMueEIuaCgiIGV4dGVuZHMgIixILmRt
-KGwsYTEpKX1wKz0iPiJ9ZWxzZXtwPSIiCnM9bnVsbH1uPWEwLlEKaz1hMC5jaApqPWsuYQppPWoubGVu
-Z3RoCmg9ay5iCmc9aC5sZW5ndGgKZj1rLmMKZT1mLmxlbmd0aApkPUguZG0obixhMSkKZm9yKGM9IiIs
-Yj0iIixxPTA7cTxpOysrcSxiPWEpYys9Qy54Qi5oKGIsSC5kbShqW3FdLGExKSkKaWYoZz4wKXtjKz1i
-KyJbIgpmb3IoYj0iIixxPTA7cTxnOysrcSxiPWEpYys9Qy54Qi5oKGIsSC5kbShoW3FdLGExKSkKYys9
-Il0ifWlmKGU+MCl7Yys9YisieyIKZm9yKGI9IiIscT0wO3E8ZTtxKz0yLGI9YSljKz1DLnhCLmgoYixI
-LmRtKGZbcSsxXSxhMSkpKyIgIitmW3FdCmMrPSJ9In1pZihzIT1udWxsKWExLmxlbmd0aD1zCnJldHVy
-biBwKyIoIitjKyIpID0+ICIrSC5kKGQpfSwKZG06ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwPWEu
-egppZihwPT09NSlyZXR1cm4iZXJhc2VkIgppZihwPT09MilyZXR1cm4iZHluYW1pYyIKaWYocD09PTMp
-cmV0dXJuInZvaWQiCmlmKHA9PT0xKXJldHVybiJOZXZlciIKaWYocD09PTQpcmV0dXJuImFueSIKaWYo
-cD09PTYpcmV0dXJuIEguZChILmRtKGEuUSxiKSkrIioiCmlmKHA9PT03KXJldHVybiBILmQoSC5kbShh
-LlEsYikpKyI/IgppZihwPT09OClyZXR1cm4iRnV0dXJlT3I8IitILmQoSC5kbShhLlEsYikpKyI+Igpp
-ZihwPT09OSl7dD1ILm8zKGEuUSkKcz1hLmNoCnJldHVybiBzLmxlbmd0aCE9PTA/dCsoIjwiK0guaW8o
-cyxiKSsiPiIpOnR9aWYocD09PTExKXJldHVybiBILmJJKGEsYixudWxsKQppZihwPT09MTIpcmV0dXJu
-IEguYkkoYS5RLGIsYS5jaCkKaWYocD09PTEzKXtyPWEuUQpxPWIubGVuZ3RoCnI9cS0xLXIKaWYocjww
-fHxyPj1xKXJldHVybiBILk9IKGIscikKcmV0dXJuIGJbcl19cmV0dXJuIj8ifSwKbzM6ZnVuY3Rpb24o
-YSl7dmFyIHQscz1ILkpnKGEpCmlmKHMhPW51bGwpcmV0dXJuIHMKdD0ibWluaWZpZWQ6IithCnJldHVy
-biB0fSwKUW86ZnVuY3Rpb24oYSxiKXt2YXIgdD1hLnRSW2JdCmZvcig7dHlwZW9mIHQ9PSJzdHJpbmci
-Oyl0PWEudFJbdF0KcmV0dXJuIHR9LAphaTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbz1hLmVU
-LG49b1tiXQppZihuPT1udWxsKXJldHVybiBILkUoYSxiKQplbHNlIGlmKHR5cGVvZiBuPT0ibnVtYmVy
-Iil7dD1uCnM9SC5tKGEsNSwiIyIpCnI9W10KZm9yKHE9MDtxPHQ7KytxKXIucHVzaChzKQpwPUguSihh
-LGIscikKb1tiXT1wCnJldHVybiBwfWVsc2UgcmV0dXJuIG59LAp4YjpmdW5jdGlvbihhLGIpe3JldHVy
-biBILkl4KGEudFIsYil9LApGRjpmdW5jdGlvbihhLGIpe3JldHVybiBILkl4KGEuZVQsYil9LApFOmZ1
-bmN0aW9uKGEsYil7dmFyIHQscz1hLmVDLHI9cy5nZXQoYikKaWYociE9bnVsbClyZXR1cm4gcgp0PUgu
-eihhLG51bGwsYikKcy5zZXQoYix0KQpyZXR1cm4gdH0sCmNFOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxz
-LHI9Yi5jeAppZihyPT1udWxsKXI9Yi5jeD1uZXcgTWFwKCkKdD1yLmdldChjKQppZih0IT1udWxsKXJl
-dHVybiB0CnM9SC56KGEsYixjKQpyLnNldChjLHMpCnJldHVybiBzfSwKdjU6ZnVuY3Rpb24oYSxiLGMp
-e3ZhciB0LHMscixxPWIuY3kKaWYocT09bnVsbClxPWIuY3k9bmV3IE1hcCgpCnQ9Yy5kYgpzPXEuZ2V0
-KHQpCmlmKHMhPW51bGwpcmV0dXJuIHMKcj1ILmEoYSxiLGMuej09PTEwP2MuY2g6W2NdKQpxLnNldCh0
-LHIpCnJldHVybiByfSwKejpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC5pKEgubyhhLGIsYykpCnJldHVy
-biB0fSwKV0c6ZnVuY3Rpb24oYSxiKXt2YXIgdD1iLmRiCmEuZUMuc2V0KHQsYikKYi5hPUguT3oKYi5i
-PUguQXYKYi5jPUguSkoKcmV0dXJuIGJ9LAptOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPWEuZUMuZ2V0
-KGMpCmlmKHMhPW51bGwpcmV0dXJuIHMKdD1uZXcgSC5KYyhudWxsLG51bGwsbnVsbCkKdC56PWIKdC5k
-Yj1jCnJldHVybiBILldHKGEsdCl9LAp2OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHM9YS5lQy5nZXQo
-ZCkKaWYocyE9bnVsbClyZXR1cm4gcwp0PW5ldyBILkpjKG51bGwsbnVsbCxudWxsKQp0Lno9Ygp0LlE9
-Ywp0LmRiPWQKcmV0dXJuIEguV0coYSx0KX0sCkg6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPSIiK2IrIl4i
-LHI9YS5lQy5nZXQocykKaWYociE9bnVsbClyZXR1cm4gcgp0PW5ldyBILkpjKG51bGwsbnVsbCxudWxs
-KQp0Lno9MTMKdC5RPWIKdC5kYj1zCnJldHVybiBILldHKGEsdCl9LApVeDpmdW5jdGlvbihhKXt2YXIg
-dCxzLHIscT1hLmxlbmd0aApmb3IodD0iIixzPSIiLHI9MDtyPHE7KytyLHM9IiwiKXQrPXMrYVtyXS5k
-YgpyZXR1cm4gdH0sClM0OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbz1hLmxlbmd0aApmb3IodD0i
-IixzPSIiLHI9MDtyPG87cis9MixzPSIsIil7cT1hW3JdCnA9YVtyKzFdLmRiCnQrPXMrcSsiOiIrcH1y
-ZXR1cm4gdH0sCko6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscj1iCmlmKGMubGVuZ3RoIT09MClyKz0i
-PCIrSC5VeChjKSsiPiIKdD1hLmVDLmdldChyKQppZih0IT1udWxsKXJldHVybiB0CnM9bmV3IEguSmMo
-bnVsbCxudWxsLG51bGwpCnMuej05CnMuUT1iCnMuY2g9YwppZihjLmxlbmd0aD4wKXMuZD1jWzBdCnMu
-ZGI9cgpyZXR1cm4gSC5XRyhhLHMpfSwKYTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscAppZihi
-Lno9PT0xMCl7dD1iLlEKcz1iLmNoLmNvbmNhdChjKX1lbHNle3M9Ywp0PWJ9cj10LmRiKyI7IisoIjwi
-K0guVXgocykrIj4iKQpxPWEuZUMuZ2V0KHIpCmlmKHEhPW51bGwpcmV0dXJuIHEKcD1uZXcgSC5KYyhu
-dWxsLG51bGwsbnVsbCkKcC56PTEwCnAuUT10CnAuY2g9cwpwLmRiPXIKcmV0dXJuIEguV0coYSxwKX0s
-CkM6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxPWIuZGIscD1jLmEsbz1wLmxlbmd0aCxuPWMuYixt
-PW4ubGVuZ3RoLGw9Yy5jLGs9bC5sZW5ndGgsaj0iKCIrSC5VeChwKQppZihtPjApais9KG8+MD8iLCI6
-IiIpKyJbIitILlV4KG4pKyJdIgppZihrPjApais9KG8+MD8iLCI6IiIpKyJ7IitILlM0KGwpKyJ9Igp0
-PXErKGorIikiKQpzPWEuZUMuZ2V0KHQpCmlmKHMhPW51bGwpcmV0dXJuIHMKcj1uZXcgSC5KYyhudWxs
-LG51bGwsbnVsbCkKci56PTExCnIuUT1iCnIuY2g9YwpyLmRiPXQKcmV0dXJuIEguV0coYSxyKX0sCkQ6
-ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9Yi5kYisiPCIrSC5VeChjKSsiPiIscj1hLmVDLmdldChzKQpp
-ZihyIT1udWxsKXJldHVybiByCnQ9bmV3IEguSmMobnVsbCxudWxsLG51bGwpCnQuej0xMgp0LlE9Ygp0
-LmNoPWMKdC5kYj1zCnJldHVybiBILldHKGEsdCl9LApvOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm57dTph
-LGU6YixyOmMsczpbXSxwOjB9fSwKaTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxq
-LGksaCxnPWEucixmPWEucwpmb3IodD1nLmxlbmd0aCxzPTA7czx0Oyl7cj1nLmNoYXJDb2RlQXQocykK
-aWYocj49NDgmJnI8PTU3KXM9SC5BKHMrMSxyLGcsZikKZWxzZSBpZigoKChyfDMyKT4+PjApLTk3JjY1
-NTM1KTwyNnx8cj09PTk1fHxyPT09MzYpcz1ILnQoYSxzLGcsZiwhMSkKZWxzZSBpZihyPT09NDYpcz1I
-LnQoYSxzLGcsZiwhMCkKZWxzZXsrK3MKc3dpdGNoKHIpe2Nhc2UgNDQ6YnJlYWsKY2FzZSA1ODpicmVh
-awpjYXNlIDU5OmYucHVzaChILksoYS51LGEuZSxmLnBvcCgpKSkKYnJlYWsKY2FzZSA5NDpmLnB1c2go
-SC5IKGEudSxmLnBvcCgpKSkKYnJlYWsKY2FzZSAzNTpmLnB1c2goSC5tKGEudSw1LCIjIikpCmJyZWFr
-CmNhc2UgNjQ6Zi5wdXNoKEgubShhLnUsMiwiQCIpKQpicmVhawpjYXNlIDEyNjpmLnB1c2goSC5tKGEu
-dSwzLCJ+IikpCmJyZWFrCmNhc2UgNjA6Zi5wdXNoKGEucCkKYS5wPWYubGVuZ3RoCmJyZWFrCmNhc2Ug
-NjI6cT1hLnUKcD1mLnNwbGljZShhLnApCkgucihhLnUsYS5lLHApCmEucD1mLnBvcCgpCm89Zi5wb3Ao
-KQppZih0eXBlb2Ygbz09InN0cmluZyIpZi5wdXNoKEguSihxLG8scCkpCmVsc2V7bj1ILksocSxhLmUs
-bykKc3dpdGNoKG4ueil7Y2FzZSAxMTpmLnB1c2goSC5EKHEsbixwKSkKYnJlYWsKZGVmYXVsdDpmLnB1
-c2goSC5hKHEsbixwKSkKYnJlYWt9fWJyZWFrCmNhc2UgMzg6SC5JKGEsZikKYnJlYWsKY2FzZSA0Mjpt
-PWEudQpsPUguSyhtLGEuZSxmLnBvcCgpKQpmLnB1c2goSC52KG0sNixsLGwuZGIrIioiKSkKYnJlYWsK
-Y2FzZSA2MzptPWEudQpsPUguSyhtLGEuZSxmLnBvcCgpKQpmLnB1c2goSC52KG0sNyxsLGwuZGIrIj8i
-KSkKYnJlYWsKY2FzZSA0NzptPWEudQpsPUguSyhtLGEuZSxmLnBvcCgpKQpmLnB1c2goSC52KG0sOCxs
-LGwuZGIrIi8iKSkKYnJlYWsKY2FzZSA0MDpmLnB1c2goYS5wKQphLnA9Zi5sZW5ndGgKYnJlYWsKY2Fz
-ZSA0MTpxPWEudQprPW5ldyBILkcoKQpqPXEuc0VBCmk9cS5zRUEKbz1mLnBvcCgpCmlmKHR5cGVvZiBv
-PT0ibnVtYmVyIilzd2l0Y2gobyl7Y2FzZS0xOmo9Zi5wb3AoKQpicmVhawpjYXNlLTI6aT1mLnBvcCgp
-CmJyZWFrCmRlZmF1bHQ6Zi5wdXNoKG8pCmJyZWFrfWVsc2UgZi5wdXNoKG8pCnA9Zi5zcGxpY2UoYS5w
-KQpILnIoYS51LGEuZSxwKQphLnA9Zi5wb3AoKQprLmE9cAprLmI9agprLmM9aQpmLnB1c2goSC5DKHEs
-SC5LKHEsYS5lLGYucG9wKCkpLGspKQpicmVhawpjYXNlIDkxOmYucHVzaChhLnApCmEucD1mLmxlbmd0
-aApicmVhawpjYXNlIDkzOnA9Zi5zcGxpY2UoYS5wKQpILnIoYS51LGEuZSxwKQphLnA9Zi5wb3AoKQpm
-LnB1c2gocCkKZi5wdXNoKC0xKQpicmVhawpjYXNlIDEyMzpmLnB1c2goYS5wKQphLnA9Zi5sZW5ndGgK
-YnJlYWsKY2FzZSAxMjU6cD1mLnNwbGljZShhLnApCkguQihhLnUsYS5lLHApCmEucD1mLnBvcCgpCmYu
-cHVzaChwKQpmLnB1c2goLTIpCmJyZWFrCmRlZmF1bHQ6dGhyb3ciQmFkIGNoYXJhY3RlciAiK3J9fX1o
-PWYucG9wKCkKcmV0dXJuIEguSyhhLnUsYS5lLGgpfSwKQTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxz
-LHI9Yi00OApmb3IodD1jLmxlbmd0aDthPHQ7KythKXtzPWMuY2hhckNvZGVBdChhKQppZighKHM+PTQ4
-JiZzPD01NykpYnJlYWsKcj1yKjEwKyhzLTQ4KX1kLnB1c2gocikKcmV0dXJuIGF9LAp0OmZ1bmN0aW9u
-KGEsYixjLGQsZSl7dmFyIHQscyxyLHEscCxvLG49YisxCmZvcih0PWMubGVuZ3RoO248dDsrK24pe3M9
-Yy5jaGFyQ29kZUF0KG4pCmlmKHM9PT00Nil7aWYoZSlicmVhawplPSEwfWVsc2V7aWYoISgoKChzfDMy
-KT4+PjApLTk3JjY1NTM1KTwyNnx8cz09PTk1fHxzPT09MzYpKXI9cz49NDgmJnM8PTU3CmVsc2Ugcj0h
-MAppZighcilicmVha319cT1jLnN1YnN0cmluZyhiLG4pCmlmKGUpe3Q9YS51CnA9YS5lCmlmKHAuej09
-PTEwKXA9cC5RCm89SC5Rbyh0LHAuUSlbcV0KaWYobz09bnVsbClILnZoKCdObyAiJytxKyciIGluICIn
-K0gubUQocCkrJyInKQpkLnB1c2goSC5jRSh0LHAsbykpfWVsc2UgZC5wdXNoKHEpCnJldHVybiBufSwK
-STpmdW5jdGlvbihhLGIpe3ZhciB0PWIucG9wKCkKaWYoMD09PXQpe2IucHVzaChILm0oYS51LDEsIjAm
-IikpCnJldHVybn1pZigxPT09dCl7Yi5wdXNoKEgubShhLnUsNCwiMSYiKSkKcmV0dXJufXRocm93IEgu
-YihQLmhWKCJVbmV4cGVjdGVkIGV4dGVuZGVkIG9wZXJhdGlvbiAiK0guZCh0KSkpfSwKSzpmdW5jdGlv
-bihhLGIsYyl7aWYodHlwZW9mIGM9PSJzdHJpbmciKXJldHVybiBILkooYSxjLGEuc0VBKQplbHNlIGlm
-KHR5cGVvZiBjPT0ibnVtYmVyIilyZXR1cm4gSC5UVihhLGIsYykKZWxzZSByZXR1cm4gY30sCnI6ZnVu
-Y3Rpb24oYSxiLGMpe3ZhciB0LHM9Yy5sZW5ndGgKZm9yKHQ9MDt0PHM7Kyt0KWNbdF09SC5LKGEsYixj
-W3RdKX0sCkI6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9Yy5sZW5ndGgKZm9yKHQ9MTt0PHM7dCs9Milj
-W3RdPUguSyhhLGIsY1t0XSl9LApUVjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyPWIuegppZihyPT09
-MTApe2lmKGM9PT0wKXJldHVybiBiLlEKdD1iLmNoCnM9dC5sZW5ndGgKaWYoYzw9cylyZXR1cm4gdFtj
-LTFdCmMtPXMKYj1iLlEKcj1iLnp9ZWxzZSBpZihjPT09MClyZXR1cm4gYgppZihyIT09OSl0aHJvdyBI
-LmIoUC5oVigiSW5kZXhlZCBiYXNlIG11c3QgYmUgYW4gaW50ZXJmYWNlIHR5cGUiKSkKdD1iLmNoCmlm
-KGM8PXQubGVuZ3RoKXJldHVybiB0W2MtMV0KdGhyb3cgSC5iKFAuaFYoIkJhZCBpbmRleCAiK2MrIiBm
-b3IgIitiLncoMCkpKX0sCldlOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxyLHEscCxvLG4sbSxs
-LGsKaWYoYj09PWQpcmV0dXJuITAKaWYoSC5jYyhkKSlyZXR1cm4hMAp0PWIuegppZih0PT09NClyZXR1
-cm4hMAppZihILmNjKGIpKXJldHVybiExCmlmKGI9PT11LlApcmV0dXJuITAKcz10PT09MTMKaWYocylp
-ZihILldlKGEsY1tiLlFdLGMsZCxlKSlyZXR1cm4hMApyPWQuegppZih0PT09NilyZXR1cm4gSC5XZShh
-LGIuUSxjLGQsZSkKaWYocj09PTYpe3E9ZC5RCnJldHVybiBILldlKGEsYixjLHEsZSl9aWYodD09PTgp
-e2lmKCFILldlKGEsYi5RLGMsZCxlKSlyZXR1cm4hMQpyZXR1cm4gSC5XZShhLEgueFooYSxiKSxjLGQs
-ZSl9aWYodD09PTcpe3E9SC5XZShhLGIuUSxjLGQsZSkKcmV0dXJuIHF9aWYocj09PTgpe2lmKEguV2Uo
-YSxiLGMsZC5RLGUpKXJldHVybiEwCnJldHVybiBILldlKGEsYixjLEgueFooYSxkKSxlKX1pZihyPT09
-Nyl7cT1ILldlKGEsYixjLGQuUSxlKQpyZXR1cm4gcX1pZihzKXJldHVybiExCnE9dCE9PTExCmlmKCgh
-cXx8dD09PTEyKSYmZD09PXUuWilyZXR1cm4hMAppZihyPT09MTIpe2lmKGI9PT11LmcpcmV0dXJuITAK
-aWYodCE9PTEyKXJldHVybiExCnA9Yi5jaApvPWQuY2gKbj1wLmxlbmd0aAppZihuIT09by5sZW5ndGgp
-cmV0dXJuITEKZm9yKHE9dS5hdixtPTA7bTxuOysrbSl7bD1wW21dCms9b1ttXQpxLmIobCkKcS5iKGsp
-CmlmKCFILldlKGEsbCxjLGssZSl8fCFILldlKGEsayxlLGwsYykpcmV0dXJuITF9Yz1jPT1udWxsP3A6
-cC5jb25jYXQoYykKZT1lPT1udWxsP286by5jb25jYXQoZSkKcmV0dXJuIEguYk8oYSxiLlEsYyxkLlEs
-ZSl9aWYocj09PTExKXtpZihiPT09dS5nKXJldHVybiEwCmlmKHEpcmV0dXJuITEKcmV0dXJuIEguYk8o
-YSxiLGMsZCxlKX1pZih0PT09OSl7aWYociE9PTkpcmV0dXJuITEKcmV0dXJuIEgucEcoYSxiLGMsZCxl
-KX1yZXR1cm4hMX0sCmJPOmZ1bmN0aW9uKGEwLGExLGEyLGEzLGE0KXt2YXIgdCxzLHIscSxwLG8sbixt
-LGwsayxqLGksaCxnLGYsZSxkLGMsYixhCmlmKCFILldlKGEwLGExLlEsYTIsYTMuUSxhNCkpcmV0dXJu
-ITEKdD1hMS5jaApzPWEzLmNoCnI9dC5hCnE9cy5hCnA9ci5sZW5ndGgKbz1xLmxlbmd0aAppZihwPm8p
-cmV0dXJuITEKbj1vLXAKbT10LmIKbD1zLmIKaz1tLmxlbmd0aApqPWwubGVuZ3RoCmlmKHArazxvK2op
-cmV0dXJuITEKZm9yKGk9MDtpPHA7KytpKXtoPXJbaV0KaWYoIUguV2UoYTAscVtpXSxhNCxoLGEyKSly
-ZXR1cm4hMX1mb3IoaT0wO2k8bjsrK2kpe2g9bVtpXQppZighSC5XZShhMCxxW3AraV0sYTQsaCxhMikp
-cmV0dXJuITF9Zm9yKGk9MDtpPGo7KytpKXtoPW1bbitpXQppZighSC5XZShhMCxsW2ldLGE0LGgsYTIp
-KXJldHVybiExfWc9dC5jCmY9cy5jCmU9Zy5sZW5ndGgKZD1mLmxlbmd0aApmb3IoaT0wLGM9MDtjPGQ7
-Yys9Mil7Yj1mW2NdCmRve2lmKGk+PWUpcmV0dXJuITEKYT1nW2ldCmkrPTJ9d2hpbGUoYTxiKQppZihi
-PGEpcmV0dXJuITEKaD1nW2ktMV0KaWYoIUguV2UoYTAsZltjKzFdLGE0LGgsYTIpKXJldHVybiExfXJl
-dHVybiEwfSwKcEc6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzLHIscSxwLG8sbixtLGw9Yi5RLGs9
-ZC5RCmlmKGw9PT1rKXt0PWIuY2gKcz1kLmNoCnI9dC5sZW5ndGgKZm9yKHE9MDtxPHI7KytxKXtwPXRb
-cV0Kbz1zW3FdCmlmKCFILldlKGEscCxjLG8sZSkpcmV0dXJuITF9cmV0dXJuITB9bj1ILlFvKGEsbCkK
-aWYobj09bnVsbClyZXR1cm4hMQptPW5ba10KaWYobT09bnVsbClyZXR1cm4hMQpyPW0ubGVuZ3RoCnM9
-ZC5jaApmb3IocT0wO3E8cjsrK3EpaWYoIUguV2UoYSxILmNFKGEsYixtW3FdKSxjLHNbcV0sZSkpcmV0
-dXJuITEKcmV0dXJuITB9LApjYzpmdW5jdGlvbihhKXt2YXIgdCxzCmlmKGE9PT11LkspcmV0dXJuITAK
-dD1hLnoKaWYodCE9PTIpaWYodCE9PTMpaWYodCE9PTQpaWYodCE9PTUpcz10PT09OCYmSC5jYyhhLlEp
-CmVsc2Ugcz0hMAplbHNlIHM9ITAKZWxzZSBzPSEwCmVsc2Ugcz0hMApyZXR1cm4gc30sCkl4OmZ1bmN0
-aW9uKGEsYil7dmFyIHQscyxyPU9iamVjdC5rZXlzKGIpLHE9ci5sZW5ndGgKZm9yKHQ9MDt0PHE7Kyt0
-KXtzPXJbdF0KYVtzXT1iW3NdfX0sCkpjOmZ1bmN0aW9uIEpjKGEsYixjKXt2YXIgXz10aGlzCl8uYT1h
-Cl8uYj1iCl8uYz1jCl8ueT1fLng9Xy5kPW51bGwKXy56PTAKXy5kYj1fLmN5PV8uY3g9Xy5jaD1fLlE9
-bnVsbH0sCkc6ZnVuY3Rpb24gRygpe3RoaXMuYz10aGlzLmI9dGhpcy5hPW51bGx9LAp1OTpmdW5jdGlv
-biB1OSgpe30sCmh6OmZ1bmN0aW9uIGh6KGEpe3RoaXMuYT1hfSwKaU06ZnVuY3Rpb24gaU0oYSl7dGhp
-cy5hPWF9LApSOTpmdW5jdGlvbihhKXtyZXR1cm4gdS5kLmMoYSl8fHUuQi5jKGEpfHx1LmR6LmMoYSl8
-fHUuSS5jKGEpfHx1LkEuYyhhKXx8dS5nNC5jKGEpfHx1LmcyLmMoYSl9LApKZzpmdW5jdGlvbihhKXty
-ZXR1cm4gdi5tYW5nbGVkR2xvYmFsTmFtZXNbYV19fSxKPXsKUXU6ZnVuY3Rpb24oYSxiLGMsZCl7cmV0
-dXJue2k6YSxwOmIsZTpjLHg6ZH19LAprczpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwPWFbdi5kaXNw
-YXRjaFByb3BlcnR5TmFtZV0KaWYocD09bnVsbClpZigkLkJ2PT1udWxsKXtILlhEKCkKcD1hW3YuZGlz
-cGF0Y2hQcm9wZXJ0eU5hbWVdfWlmKHAhPW51bGwpe3Q9cC5wCmlmKCExPT09dClyZXR1cm4gcC5pCmlm
-KCEwPT09dClyZXR1cm4gYQpzPU9iamVjdC5nZXRQcm90b3R5cGVPZihhKQppZih0PT09cylyZXR1cm4g
-cC5pCmlmKHAuZT09PXMpdGhyb3cgSC5iKFAuU1koIlJldHVybiBpbnRlcmNlcHRvciBmb3IgIitILmQo
-dChhLHApKSkpfXI9YS5jb25zdHJ1Y3RvcgpxPXI9PW51bGw/bnVsbDpyWyQuVU4oKV0KaWYocSE9bnVs
-bClyZXR1cm4gcQpxPUgudzMoYSkKaWYocSE9bnVsbClyZXR1cm4gcQppZih0eXBlb2YgYT09ImZ1bmN0
-aW9uIilyZXR1cm4gQy5ERwp0PU9iamVjdC5nZXRQcm90b3R5cGVPZihhKQppZih0PT1udWxsKXJldHVy
-biBDLlpRCmlmKHQ9PT1PYmplY3QucHJvdG90eXBlKXJldHVybiBDLlpRCmlmKHR5cGVvZiByPT0iZnVu
-Y3Rpb24iKXtPYmplY3QuZGVmaW5lUHJvcGVydHkociwkLlVOKCkse3ZhbHVlOkMudkIsZW51bWVyYWJs
-ZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIEMudkJ9cmV0dXJu
-IEMudkJ9LApRaTpmdW5jdGlvbihhLGIpe2lmKGE8MHx8YT40Mjk0OTY3Mjk1KXRocm93IEguYihQLlRF
-KGEsMCw0Mjk0OTY3Mjk1LCJsZW5ndGgiLG51bGwpKQpyZXR1cm4gSi5weShuZXcgQXJyYXkoYSksYil9
-LApweTpmdW5jdGlvbihhLGIpe3JldHVybiBKLkVwKEguVk0oYSxiLkMoImpkPDA+IikpKX0sCkVwOmZ1
-bmN0aW9uKGEpe2EuZml4ZWQkbGVuZ3RoPUFycmF5CnJldHVybiBhfSwKekM6ZnVuY3Rpb24oYSl7YS5m
-aXhlZCRsZW5ndGg9QXJyYXkKYS5pbW11dGFibGUkbGlzdD1BcnJheQpyZXR1cm4gYX0sCkdhOmZ1bmN0
-aW9uKGEpe2lmKGE8MjU2KXN3aXRjaChhKXtjYXNlIDk6Y2FzZSAxMDpjYXNlIDExOmNhc2UgMTI6Y2Fz
-ZSAxMzpjYXNlIDMyOmNhc2UgMTMzOmNhc2UgMTYwOnJldHVybiEwCmRlZmF1bHQ6cmV0dXJuITF9c3dp
-dGNoKGEpe2Nhc2UgNTc2MDpjYXNlIDgxOTI6Y2FzZSA4MTkzOmNhc2UgODE5NDpjYXNlIDgxOTU6Y2Fz
-ZSA4MTk2OmNhc2UgODE5NzpjYXNlIDgxOTg6Y2FzZSA4MTk5OmNhc2UgODIwMDpjYXNlIDgyMDE6Y2Fz
-ZSA4MjAyOmNhc2UgODIzMjpjYXNlIDgyMzM6Y2FzZSA4MjM5OmNhc2UgODI4NzpjYXNlIDEyMjg4OmNh
-c2UgNjUyNzk6cmV0dXJuITAKZGVmYXVsdDpyZXR1cm4hMX19LAptbTpmdW5jdGlvbihhLGIpe3ZhciB0
-LHMKZm9yKHQ9YS5sZW5ndGg7Yjx0Oyl7cz1DLnhCLlcoYSxiKQppZihzIT09MzImJnMhPT0xMyYmIUou
-R2EocykpYnJlYWs7KytifXJldHVybiBifSwKYzE6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzCmZvcig7Yj4w
-O2I9dCl7dD1iLTEKcz1DLnhCLm0oYSx0KQppZihzIT09MzImJnMhPT0xMyYmIUouR2EocykpYnJlYWt9
-cmV0dXJuIGJ9LApSRTpmdW5jdGlvbihhKXtpZihhPT1udWxsKXJldHVybiBhCmlmKHR5cGVvZiBhIT0i
-b2JqZWN0Iil7aWYodHlwZW9mIGE9PSJmdW5jdGlvbiIpcmV0dXJuIEouYzUucHJvdG90eXBlCnJldHVy
-biBhfWlmKGEgaW5zdGFuY2VvZiBQLmspcmV0dXJuIGEKcmV0dXJuIEoua3MoYSl9LApUSjpmdW5jdGlv
-bihhKXtpZih0eXBlb2YgYT09Im51bWJlciIpcmV0dXJuIEoucUkucHJvdG90eXBlCmlmKHR5cGVvZiBh
-PT0ic3RyaW5nIilyZXR1cm4gSi5Eci5wcm90b3R5cGUKaWYoYT09bnVsbClyZXR1cm4gYQppZihhLmNv
+IiEiKXtvPUgubCh0KQokLmpbcF09bwpPYmplY3QuZGVmaW5lUHJvcGVydHkoYSx2LmRpc3BhdGNoUHJv
+cGVydHlOYW1lLHt2YWx1ZTpvLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFi
+bGU6dHJ1ZX0pCnJldHVybiBvLml9aWYocj09PSJ+Iil7JC52W3BdPXQKcmV0dXJuIHR9aWYocj09PSIt
+Iil7cT1ILmwodCkKT2JqZWN0LmRlZmluZVByb3BlcnR5KE9iamVjdC5nZXRQcm90b3R5cGVPZihhKSx2
+LmRpc3BhdGNoUHJvcGVydHlOYW1lLHt2YWx1ZTpxLGVudW1lcmFibGU6ZmFsc2Usd3JpdGFibGU6dHJ1
+ZSxjb25maWd1cmFibGU6dHJ1ZX0pCnJldHVybiBxLml9aWYocj09PSIrIilyZXR1cm4gSC5MYyhhLHQp
+CmlmKHI9PT0iKiIpdGhyb3cgSC5iKFAubihwKSkKaWYodi5sZWFmVGFnc1twXT09PXRydWUpe3E9SC5s
+KHQpCk9iamVjdC5kZWZpbmVQcm9wZXJ0eShPYmplY3QuZ2V0UHJvdG90eXBlT2YoYSksdi5kaXNwYXRj
+aFByb3BlcnR5TmFtZSx7dmFsdWU6cSxlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsY29uZmln
+dXJhYmxlOnRydWV9KQpyZXR1cm4gcS5pfWVsc2UgcmV0dXJuIEguTGMoYSx0KX0sCkxjOmZ1bmN0aW9u
+KGEsYil7dmFyIHQ9T2JqZWN0LmdldFByb3RvdHlwZU9mKGEpCk9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0
+LHYuZGlzcGF0Y2hQcm9wZXJ0eU5hbWUse3ZhbHVlOkouUXUoYix0LG51bGwsbnVsbCksZW51bWVyYWJs
+ZTpmYWxzZSx3cml0YWJsZTp0cnVlLGNvbmZpZ3VyYWJsZTp0cnVlfSkKcmV0dXJuIGJ9LApsOmZ1bmN0
+aW9uKGEpe3JldHVybiBKLlF1KGEsITEsbnVsbCwhIWEuJGlYail9LApWRjpmdW5jdGlvbihhLGIsYyl7
+dmFyIHQ9Yi5wcm90b3R5cGUKaWYodi5sZWFmVGFnc1thXT09PXRydWUpcmV0dXJuIEgubCh0KQplbHNl
+IHJldHVybiBKLlF1KHQsYyxudWxsLG51bGwpfSwKTTpmdW5jdGlvbigpe2lmKCEwPT09JC5LKXJldHVy
+bgokLks9ITAKSC5EKCl9LApEOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxvLG4sbQokLmo9T2JqZWN0
+LmNyZWF0ZShudWxsKQokLnY9T2JqZWN0LmNyZWF0ZShudWxsKQpILmEoKQp0PXYuaW50ZXJjZXB0b3Jz
+QnlUYWcKcz1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyh0KQppZih0eXBlb2Ygd2luZG93IT0idW5k
+ZWZpbmVkIil7d2luZG93CnI9ZnVuY3Rpb24oKXt9CmZvcihxPTA7cTxzLmxlbmd0aDsrK3Epe3A9c1tx
+XQpvPSQueDcuJDEocCkKaWYobyE9bnVsbCl7bj1ILlZGKHAsdFtwXSxvKQppZihuIT1udWxsKXtPYmpl
+Y3QuZGVmaW5lUHJvcGVydHkobyx2LmRpc3BhdGNoUHJvcGVydHlOYW1lLHt2YWx1ZTpuLGVudW1lcmFi
+bGU6ZmFsc2Usd3JpdGFibGU6dHJ1ZSxjb25maWd1cmFibGU6dHJ1ZX0pCnIucHJvdG90eXBlPW99fX19
+Zm9yKHE9MDtxPHMubGVuZ3RoOysrcSl7cD1zW3FdCmlmKC9eW0EtWmEtel9dLy50ZXN0KHApKXttPXRb
+cF0KdFsiISIrcF09bQp0WyJ+IitwXT1tCnRbIi0iK3BdPW0KdFsiKyIrcF09bQp0WyIqIitwXT1tfX19
+LAphOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxvLG49Qy5PNCgpCm49SC5GKEMuWXEsSC5GKEMuS1Us
+SC5GKEMuZlEsSC5GKEMuZlEsSC5GKEMuaTcsSC5GKEMueGksSC5GKEMuZGsoQy53YiksbikpKSkpKSkK
+aWYodHlwZW9mIGRhcnROYXRpdmVEaXNwYXRjaEhvb2tzVHJhbnNmb3JtZXIhPSJ1bmRlZmluZWQiKXt0
+PWRhcnROYXRpdmVEaXNwYXRjaEhvb2tzVHJhbnNmb3JtZXIKaWYodHlwZW9mIHQ9PSJmdW5jdGlvbiIp
+dD1bdF0KaWYodC5jb25zdHJ1Y3Rvcj09QXJyYXkpZm9yKHM9MDtzPHQubGVuZ3RoOysrcyl7cj10W3Nd
+CmlmKHR5cGVvZiByPT0iZnVuY3Rpb24iKW49cihuKXx8bn19cT1uLmdldFRhZwpwPW4uZ2V0VW5rbm93
+blRhZwpvPW4ucHJvdG90eXBlRm9yVGFnCiQueT1uZXcgSC5yKHEpCiQudT1uZXcgSC5kQyhwKQokLng3
+PW5ldyBILndOKG8pfSwKRjpmdW5jdGlvbihhLGIpe3JldHVybiBhKGIpfHxifSwKdjQ6ZnVuY3Rpb24o
+YSxiLGMsZCxlLGYpe3ZhciB0PWI/Im0iOiIiLHM9Yz8iIjoiaSIscj1kPyJ1IjoiIixxPWU/InMiOiIi
+LHA9Zj8iZyI6IiIsbz1mdW5jdGlvbihnLGgpe3RyeXtyZXR1cm4gbmV3IFJlZ0V4cChnLGgpfWNhdGNo
+KG4pe3JldHVybiBufX0oYSx0K3MrcitxK3ApCmlmKG8gaW5zdGFuY2VvZiBSZWdFeHApcmV0dXJuIG8K
+dGhyb3cgSC5iKFAucnIoIklsbGVnYWwgUmVnRXhwIHBhdHRlcm4gKCIrU3RyaW5nKG8pKyIpIixhLG51
+bGwpKX0sCm0yOmZ1bmN0aW9uKGEsYixjKXt2YXIgdAppZih0eXBlb2YgYj09InN0cmluZyIpcmV0dXJu
+IGEuaW5kZXhPZihiLGMpPj0wCmVsc2UgaWYoYiBpbnN0YW5jZW9mIEguVlIpe3Q9Qy54Qi5HKGEsYykK
+cmV0dXJuIGIuYi50ZXN0KHQpfWVsc2V7dD1KLkZMKGIsQy54Qi5HKGEsYykpCnJldHVybiF0LmdsMCh0
+KX19LApBNDpmdW5jdGlvbihhKXtpZihhLmluZGV4T2YoIiQiLDApPj0wKXJldHVybiBhLnJlcGxhY2Uo
+L1wkL2csIiQkJCQiKQpyZXR1cm4gYX0sCmVBOmZ1bmN0aW9uKGEpe2lmKC9bW1xde30oKSorPy5cXF4k
+fF0vLnRlc3QoYSkpcmV0dXJuIGEucmVwbGFjZSgvW1tcXXt9KCkqKz8uXFxeJHxdL2csIlxcJCYiKQpy
+ZXR1cm4gYX0sCnlzOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1ILm5NKGEsYixjKQpyZXR1cm4gdH0sCm5N
+OmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscQppZihiPT09IiIpe2lmKGE9PT0iIilyZXR1cm4gYwp0
+PWEubGVuZ3RoCmZvcihzPWMscj0wO3I8dDsrK3Ipcz1zK2Fbcl0rYwpyZXR1cm4gcy5jaGFyQ29kZUF0
+KDApPT0wP3M6c31xPWEuaW5kZXhPZihiLDApCmlmKHE8MClyZXR1cm4gYQppZihhLmxlbmd0aDw1MDB8
+fGMuaW5kZXhPZigiJCIsMCk+PTApcmV0dXJuIGEuc3BsaXQoYikuam9pbihjKQpyZXR1cm4gYS5yZXBs
+YWNlKG5ldyBSZWdFeHAoSC5lQShiKSwnZycpLEguQTQoYykpfSwKUEQ6ZnVuY3Rpb24gUEQoYSxiKXt0
+aGlzLmE9YQp0aGlzLiR0aT1ifSwKV1U6ZnVuY3Rpb24gV1UoKXt9LApMUDpmdW5jdGlvbiBMUChhLGIs
+YyxkKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uJHRpPWR9LApYUjpmdW5jdGlvbiBYUihh
+LGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApMSTpmdW5jdGlvbiBMSShhLGIsYyxkLGUpe3ZhciBfPXRo
+aXMKXy5hPWEKXy5jPWIKXy5kPWMKXy5lPWQKXy5mPWV9LApDajpmdW5jdGlvbiBDaihhLGIsYyl7dGhp
+cy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApmOTpmdW5jdGlvbiBmOShhLGIsYyxkLGUsZil7dmFyIF89
+dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9Zn0sClcwOmZ1bmN0aW9uIFcwKGEs
+Yil7dGhpcy5hPWEKdGhpcy5iPWJ9LAphejpmdW5jdGlvbiBheihhLGIsYyl7dGhpcy5hPWEKdGhpcy5i
+PWIKdGhpcy5jPWN9LAp2VjpmdW5jdGlvbiB2VihhKXt0aGlzLmE9YX0sCmJxOmZ1bmN0aW9uIGJxKGEs
+Yil7dGhpcy5hPWEKdGhpcy5iPWJ9LApBbTpmdW5jdGlvbiBBbShhKXt0aGlzLmE9YX0sClhPOmZ1bmN0
+aW9uIFhPKGEpe3RoaXMuYT1hCnRoaXMuYj1udWxsfSwKVHA6ZnVuY3Rpb24gVHAoKXt9LApsYzpmdW5j
+dGlvbiBsYygpe30sCnp4OmZ1bmN0aW9uIHp4KCl7fSwKank6ZnVuY3Rpb24gankoYSxiLGMsZCl7dmFy
+IF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCkVxOmZ1bmN0aW9uIEVxKGEpe3RoaXMuYT1h
+fSwKa1k6ZnVuY3Rpb24ga1koYSl7dGhpcy5hPWF9LApONTpmdW5jdGlvbiBONShhKXt2YXIgXz10aGlz
+Cl8uYT0wCl8uZj1fLmU9Xy5kPV8uYz1fLmI9bnVsbApfLnI9MApfLiR0aT1hfSwKZGI6ZnVuY3Rpb24g
+ZGIoYSxiKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uZD1fLmM9bnVsbH0sCmk1OmZ1bmN0aW9uIGk1
+KGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCk42OmZ1bmN0aW9uIE42KGEsYixjKXt2YXIgXz10aGlz
+Cl8uYT1hCl8uYj1iCl8uZD1fLmM9bnVsbApfLiR0aT1jfSwKcjpmdW5jdGlvbiByKGEpe3RoaXMuYT1h
+fSwKZEM6ZnVuY3Rpb24gZEMoYSl7dGhpcy5hPWF9LAp3TjpmdW5jdGlvbiB3TihhKXt0aGlzLmE9YX0s
+ClZSOmZ1bmN0aW9uIFZSKGEsYil7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmQ9Xy5jPW51bGx9LApF
+SzpmdW5jdGlvbiBFSyhhKXt0aGlzLmI9YX0sCktXOmZ1bmN0aW9uIEtXKGEsYixjKXt0aGlzLmE9YQp0
+aGlzLmI9Ygp0aGlzLmM9Y30sClBiOmZ1bmN0aW9uIFBiKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8u
+Yj1iCl8uYz1jCl8uZD1udWxsfSwKdFE6ZnVuY3Rpb24gdFEoYSxiKXt0aGlzLmE9YQp0aGlzLmM9Yn0s
+Ck5GOmZ1bmN0aW9uIE5GKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sClNkOmZ1bmN0
+aW9uIFNkKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1udWxsfSwKWEY6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIGF9LApEUTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEludDhBcnJheShhKX0s
+Cm9kOmZ1bmN0aW9uKGEsYixjKXtpZihhPj4+MCE9PWF8fGE+PWMpdGhyb3cgSC5iKEguSFkoYixhKSl9
+LApyTTpmdW5jdGlvbihhLGIsYyl7dmFyIHQKaWYoIShhPj4+MCE9PWEpKXQ9Yj4+PjAhPT1ifHxhPmJ8
+fGI+YwplbHNlIHQ9ITAKaWYodCl0aHJvdyBILmIoSC5hdShhLGIsYykpCnJldHVybiBifSwKZUg6ZnVu
+Y3Rpb24gZUgoKXt9LApMWjpmdW5jdGlvbiBMWigpe30sCkRnOmZ1bmN0aW9uIERnKCl7fSwKUGc6ZnVu
+Y3Rpb24gUGcoKXt9LAp4ajpmdW5jdGlvbiB4aigpe30sCmRFOmZ1bmN0aW9uIGRFKCl7fSwKWkE6ZnVu
+Y3Rpb24gWkEoKXt9LAp3ZjpmdW5jdGlvbiB3Zigpe30sClBxOmZ1bmN0aW9uIFBxKCl7fSwKZUU6ZnVu
+Y3Rpb24gZUUoKXt9LApWNjpmdW5jdGlvbiBWNigpe30sClJHOmZ1bmN0aW9uIFJHKCl7fSwKVlA6ZnVu
+Y3Rpb24gVlAoKXt9LApXQjpmdW5jdGlvbiBXQigpe30sClpHOmZ1bmN0aW9uIFpHKCl7fSwKY3o6ZnVu
+Y3Rpb24oYSxiKXt2YXIgdD1iLmMKcmV0dXJuIHQ9PW51bGw/Yi5jPUguQmMoYSxiLnosITApOnR9LAp4
+WjpmdW5jdGlvbihhLGIpe3ZhciB0PWIuYwpyZXR1cm4gdD09bnVsbD9iLmM9SC5RMihhLCJiOCIsW2Iu
+el0pOnR9LApRMTpmdW5jdGlvbihhKXt2YXIgdD1hLnkKaWYodD09PTZ8fHQ9PT03fHx0PT09OClyZXR1
+cm4gSC5RMShhLnopCnJldHVybiB0PT09MTF8fHQ9PT0xMn0sCm1EOmZ1bmN0aW9uKGEpe3JldHVybiBh
+LmN5fSwKTjA6ZnVuY3Rpb24oYSl7cmV0dXJuIEguRSh2LnR5cGVVbml2ZXJzZSxhLCExKX0sClBMOmZ1
+bmN0aW9uKGEsYixjLGEwKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZSxkPWIueQpz
+d2l0Y2goZCl7Y2FzZSA1OmNhc2UgMTpjYXNlIDI6Y2FzZSAzOmNhc2UgNDpyZXR1cm4gYgpjYXNlIDY6
+dD1iLnoKcz1ILlBMKGEsdCxjLGEwKQppZihzPT09dClyZXR1cm4gYgpyZXR1cm4gSC5TTyhhLHMsITAp
+CmNhc2UgNzp0PWIuegpzPUguUEwoYSx0LGMsYTApCmlmKHM9PT10KXJldHVybiBiCnJldHVybiBILkJj
+KGEscywhMCkKY2FzZSA4OnQ9Yi56CnM9SC5QTChhLHQsYyxhMCkKaWYocz09PXQpcmV0dXJuIGIKcmV0
+dXJuIEguTE4oYSxzLCEwKQpjYXNlIDk6cj1iLlEKcT1ILmJaKGEscixjLGEwKQppZihxPT09cilyZXR1
+cm4gYgpyZXR1cm4gSC5RMihhLGIueixxKQpjYXNlIDEwOnA9Yi56Cm89SC5QTChhLHAsYyxhMCkKbj1i
+LlEKbT1ILmJaKGEsbixjLGEwKQppZihvPT09cCYmbT09PW4pcmV0dXJuIGIKcmV0dXJuIEguYXAoYSxv
+LG0pCmNhc2UgMTE6bD1iLnoKaz1ILlBMKGEsbCxjLGEwKQpqPWIuUQppPUgucVQoYSxqLGMsYTApCmlm
+KGs9PT1sJiZpPT09ailyZXR1cm4gYgpyZXR1cm4gSC5OZihhLGssaSkKY2FzZSAxMjpoPWIuUQphMCs9
+aC5sZW5ndGgKZz1ILmJaKGEsaCxjLGEwKQpwPWIuegpvPUguUEwoYSxwLGMsYTApCmlmKGc9PT1oJiZv
+PT09cClyZXR1cm4gYgpyZXR1cm4gSC5EUyhhLG8sZywhMCkKY2FzZSAxMzpmPWIuegppZihmPGEwKXJl
+dHVybiBiCmU9Y1tmLWEwXQppZihlPT1udWxsKXJldHVybiBiCnJldHVybiBlCmRlZmF1bHQ6dGhyb3cg
+SC5iKFAuaFYoIkF0dGVtcHRlZCB0byBzdWJzdGl0dXRlIHVuZXhwZWN0ZWQgUlRJIGtpbmQgIitkKSl9
+fSwKYlo6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyLHEscD1iLmxlbmd0aCxvPVtdCmZvcih0PSEx
+LHM9MDtzPHA7KytzKXtyPWJbc10KcT1ILlBMKGEscixjLGQpCmlmKHEhPT1yKXQ9ITAKby5wdXNoKHEp
+fXJldHVybiB0P286Yn0sCnZPOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMscixxLHAsbz1iLmxlbmd0
+aCxuPVtdCmZvcih0PSExLHM9MDtzPG87cys9Mil7cj1iW3NdCnE9YltzKzFdCnA9SC5QTChhLHEsYyxk
+KQppZihwIT09cSl0PSEwCm4ucHVzaChyKQpuLnB1c2gocCl9cmV0dXJuIHQ/bjpifSwKcVQ6ZnVuY3Rp
+b24oYSxiLGMsZCl7dmFyIHQscz1iLmEscj1ILmJaKGEscyxjLGQpLHE9Yi5iLHA9SC5iWihhLHEsYyxk
+KSxvPWIuYyxuPUgudk8oYSxvLGMsZCkKaWYocj09PXMmJnA9PT1xJiZuPT09bylyZXR1cm4gYgp0PW5l
+dyBILkVUKCkKdC5hPXIKdC5iPXAKdC5jPW4KcmV0dXJuIHR9LApKUzpmdW5jdGlvbihhKXt2YXIgdD1h
+LiRTCmlmKHQhPW51bGwpe2lmKHR5cGVvZiB0PT0ibnVtYmVyIilyZXR1cm4gSC5CcCh0KQpyZXR1cm4g
+YS4kUygpfXJldHVybiBudWxsfSwKVWU6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihILlExKGIpKWlmKGEg
+aW5zdGFuY2VvZiBILlRwKXt0PUguSlMoYSkKaWYodCE9bnVsbClyZXR1cm4gdH1yZXR1cm4gSC5xKGEp
+fSwKcTpmdW5jdGlvbihhKXt2YXIgdAppZihhIGluc3RhbmNlb2YgUC5NaCl7dD1hLiR0aQpyZXR1cm4g
+dCE9bnVsbD90OkguVlUoYSl9aWYoQXJyYXkuaXNBcnJheShhKSlyZXR1cm4gSC50NihhKQpyZXR1cm4g
+SC5WVShKLmlhKGEpKX0sCnQ2OmZ1bmN0aW9uKGEpe3ZhciB0PWFbdi5hcnJheVJ0aV0scz11LmIKaWYo
+dD09bnVsbClyZXR1cm4gcwppZih0LmNvbnN0cnVjdG9yIT09cy5jb25zdHJ1Y3RvcilyZXR1cm4gcwpy
+ZXR1cm4gdH0sCkxoOmZ1bmN0aW9uKGEpe3ZhciB0PWEuJHRpCnJldHVybiB0IT1udWxsP3Q6SC5WVShh
+KX0sClZVOmZ1bmN0aW9uKGEpe3ZhciB0PWEuY29uc3RydWN0b3Iscz10LiRjY2FjaGUKaWYocyE9bnVs
+bClyZXR1cm4gcwpyZXR1cm4gSC5yOShhLHQpfSwKcjk6ZnVuY3Rpb24oYSxiKXt2YXIgdD1hIGluc3Rh
+bmNlb2YgSC5UcD9hLl9fcHJvdG9fXy5fX3Byb3RvX18uY29uc3RydWN0b3I6YixzPUguYWkodi50eXBl
+VW5pdmVyc2UsdC5uYW1lKQpiLiRjY2FjaGU9cwpyZXR1cm4gc30sCkJwOmZ1bmN0aW9uKGEpe3ZhciB0
+LHM9YSxyPXYudHlwZXMscT1yW3NdCmlmKHR5cGVvZiBxPT0ic3RyaW5nIil7dD1ILkUodi50eXBlVW5p
+dmVyc2UscSwhMSkKcltzXT10CnJldHVybiB0fXJldHVybiBxfSwKSko6ZnVuY3Rpb24oYSl7dmFyIHQ9
+dGhpcyxzPUguWU8scj11LksKaWYodD09PXIpe3M9SC5rZQp0LmE9SC5UaX1lbHNlIGlmKEguQTgodCl8
+fHQ9PT1yKXtzPUguSXcKdC5hPUguaG59ZWxzZSBpZih0PT09dS5wKXM9SC5vawplbHNlIGlmKHQ9PT11
+LmdSKXM9SC5LSAplbHNlIGlmKHQ9PT11LmRpKXM9SC5LSAplbHNlIGlmKHQ9PT11Lk4pcz1ILk1NCmVs
+c2UgaWYodD09PXUueSlzPUguclEKZWxzZSBpZih0Lnk9PT05KXtyPXQuegppZih0LlEuZXZlcnkoSC5j
+Yykpe3Qucj0iJGkiK3IKcz1ILnQ0fX10LmI9cwpyZXR1cm4gdC5iKGEpfSwKWU86ZnVuY3Rpb24oYSl7
+dmFyIHQ9dGhpcwpyZXR1cm4gSC5XZSh2LnR5cGVVbml2ZXJzZSxILlVlKGEsdCksbnVsbCx0LG51bGwp
+fSwKdDQ6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPXQucgppZihhIGluc3RhbmNlb2YgUC5NaClyZXR1
+cm4hIWFbc10KcmV0dXJuISFKLmlhKGEpW3NdfSwKT3o6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcwppZihh
+PT1udWxsKXJldHVybiBhCmVsc2UgaWYodC5iKGEpKXJldHVybiBhCnRocm93IEguYihILlpjKEgucChh
+LEguVWUoYSx0KSxILkoodCxudWxsKSkpKX0sCkRoOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0PW51bGwK
+aWYoSC5XZSh2LnR5cGVVbml2ZXJzZSxhLHQsYix0KSlyZXR1cm4gYQp0aHJvdyBILmIoSC5aYygiVGhl
+IHR5cGUgYXJndW1lbnQgJyIrSC5kKEguSihhLHQpKSsiJyBpcyBub3QgYSBzdWJ0eXBlIG9mIHRoZSB0
+eXBlIHZhcmlhYmxlIGJvdW5kICciK0guZChILkooYix0KSkrIicgb2YgdHlwZSB2YXJpYWJsZSAnIitj
+KyInIGluICciK0guZChkKSsiJy4iKSl9LApwOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1QLmgoYSkscz1I
+LkooYj09bnVsbD9ILnEoYSk6YixudWxsKQpyZXR1cm4gdCsiOiB0eXBlICciK0guZChzKSsiJyBpcyBu
+b3QgYSBzdWJ0eXBlIG9mIHR5cGUgJyIrSC5kKGMpKyInIn0sClpjOmZ1bmN0aW9uKGEpe3JldHVybiBu
+ZXcgSC54KCJUeXBlRXJyb3I6ICIrYSl9LApCOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBILngoIlR5
+cGVFcnJvcjogIitILnAoYSxudWxsLGIpKX0sCmtlOmZ1bmN0aW9uKGEpe3JldHVybiEwfSwKVGk6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIGF9LApJdzpmdW5jdGlvbihhKXtyZXR1cm4hMH0sCmhuOmZ1bmN0aW9uKGEp
+e3JldHVybiBhfSwKclE6ZnVuY3Rpb24oYSl7cmV0dXJuITA9PT1hfHwhMT09PWF9LApFOTpmdW5jdGlv
+bihhKXtpZighMD09PWF8fCExPT09YSlyZXR1cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEgu
+YihILkIoYSwiYm9vbCIpKX0sCmRqOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIilyZXR1
+cm4gYQppZihhPT1udWxsKXJldHVybiBhCnRocm93IEguYihILkIoYSwiZG91YmxlIikpfSwKb2s6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIHR5cGVvZiBhPT0ibnVtYmVyIiYmTWF0aC5mbG9vcihhKT09PWF9LApXWTpm
+dW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJlciImJk1hdGguZmxvb3IoYSk9PT1hKXJldHVybiBh
+CmlmKGE9PW51bGwpcmV0dXJuIGEKdGhyb3cgSC5iKEguQihhLCJpbnQiKSl9LApLSDpmdW5jdGlvbihh
+KXtyZXR1cm4gdHlwZW9mIGE9PSJudW1iZXIifSwKdVU6ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJu
+dW1iZXIiKXJldHVybiBhCmlmKGE9PW51bGwpcmV0dXJuIGEKdGhyb3cgSC5iKEguQihhLCJudW0iKSl9
+LApNTTpmdW5jdGlvbihhKXtyZXR1cm4gdHlwZW9mIGE9PSJzdHJpbmcifSwKYzpmdW5jdGlvbihhKXtp
+Zih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJuIGEKaWYoYT09bnVsbClyZXR1cm4gYQp0aHJvdyBILmIo
+SC5CKGEsIlN0cmluZyIpKX0sCnc6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKZm9yKHQ9IiIscz0iIixy
+PTA7cjxhLmxlbmd0aDsrK3Iscz0iLCAiKXQrPUMueEIuaChzLEguSihhW3JdLGIpKQpyZXR1cm4gdH0s
+CmY6ZnVuY3Rpb24oYTEsYTIsYTMpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoLGcsZixlLGQs
+YyxiLGEsYTA9IiwgIgppZihhMyE9bnVsbCl7dD1hMy5sZW5ndGgKaWYoYTI9PW51bGwpe2EyPUguVk0o
+W10sdS5zKQpzPW51bGx9ZWxzZSBzPWEyLmxlbmd0aApyPWEyLmxlbmd0aApmb3IocT10O3E+MDstLXEp
+Qy5ObS5pKGEyLCJUIisocitxKSkKZm9yKHA9dS5LLG89IjwiLG49IiIscT0wO3E8dDsrK3Esbj1hMCl7
+bys9bgptPWEyLmxlbmd0aApsPW0tMS1xCmlmKGw8MClyZXR1cm4gSC5rKGEyLGwpCm89Qy54Qi5oKG8s
+YTJbbF0pCms9YTNbcV0KaWYoIShILkE4KGspfHxrPT09cCkpbT0hKGs9PT1wKQplbHNlIG09ITEKaWYo
+bSlvKz1DLnhCLmgoIiBleHRlbmRzICIsSC5KKGssYTIpKX1vKz0iPiJ9ZWxzZXtvPSIiCnM9bnVsbH1w
+PWExLnoKaj1hMS5RCmk9ai5hCmg9aS5sZW5ndGgKZz1qLmIKZj1nLmxlbmd0aAplPWouYwpkPWUubGVu
+Z3RoCmM9SC5KKHAsYTIpCmZvcihiPSIiLGE9IiIscT0wO3E8aDsrK3EsYT1hMCliKz1DLnhCLmgoYSxI
+LkooaVtxXSxhMikpCmlmKGY+MCl7Yis9YSsiWyIKZm9yKGE9IiIscT0wO3E8ZjsrK3EsYT1hMCliKz1D
+LnhCLmgoYSxILkooZ1txXSxhMikpCmIrPSJdIn1pZihkPjApe2IrPWErInsiCmZvcihhPSIiLHE9MDtx
+PGQ7cSs9MixhPWEwKWIrPUMueEIuaChhLEguSihlW3ErMV0sYTIpKSsiICIrZVtxXQpiKz0ifSJ9aWYo
+cyE9bnVsbClhMi5sZW5ndGg9cwpyZXR1cm4gbysiKCIrYisiKSA9PiAiK0guZChjKX0sCko6ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtPWEueQppZihtPT09NSlyZXR1cm4iZXJhc2VkIgppZiht
+PT09MilyZXR1cm4iZHluYW1pYyIKaWYobT09PTMpcmV0dXJuInZvaWQiCmlmKG09PT0xKXJldHVybiJO
+ZXZlciIKaWYobT09PTQpcmV0dXJuImFueSIKaWYobT09PTYpe3Q9SC5KKGEueixiKQpyZXR1cm4gdH1p
+ZihtPT09Nyl7cz1hLnoKdD1ILkoocyxiKQpyPXMueQpyZXR1cm4gSi5tKHI9PT0xMXx8cj09PTEyP0Mu
+eEIuaCgiKCIsdCkrIikiOnQsIj8iKX1pZihtPT09OClyZXR1cm4iRnV0dXJlT3I8IitILmQoSC5KKGEu
+eixiKSkrIj4iCmlmKG09PT05KXtxPUguQyhhLnopCnA9YS5RCnJldHVybiBwLmxlbmd0aCE9PTA/cSso
+IjwiK0gudyhwLGIpKyI+Iik6cX1pZihtPT09MTEpcmV0dXJuIEguZihhLGIsbnVsbCkKaWYobT09PTEy
+KXJldHVybiBILmYoYS56LGIsYS5RKQppZihtPT09MTMpe289YS56Cm49Yi5sZW5ndGgKbz1uLTEtbwpp
+ZihvPDB8fG8+PW4pcmV0dXJuIEguayhiLG8pCnJldHVybiBiW29dfXJldHVybiI/In0sCkM6ZnVuY3Rp
+b24oYSl7dmFyIHQscz1ILkpnKGEpCmlmKHMhPW51bGwpcmV0dXJuIHMKdD0ibWluaWZpZWQ6IithCnJl
+dHVybiB0fSwKUW86ZnVuY3Rpb24oYSxiKXt2YXIgdD1hLnRSW2JdCmZvcig7dHlwZW9mIHQ9PSJzdHJp
+bmciOyl0PWEudFJbdF0KcmV0dXJuIHR9LAphaTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbz1h
+LmVULG49b1tiXQppZihuPT1udWxsKXJldHVybiBILkUoYSxiLCExKQplbHNlIGlmKHR5cGVvZiBuPT0i
+bnVtYmVyIil7dD1uCnM9SC5tWihhLDUsIiMiKQpyPVtdCmZvcihxPTA7cTx0OysrcSlyLnB1c2gocykK
+cD1ILlEyKGEsYixyKQpvW2JdPXAKcmV0dXJuIHB9ZWxzZSByZXR1cm4gbn0sCnhiOmZ1bmN0aW9uKGEs
+Yil7cmV0dXJuIEguSXgoYS50UixiKX0sCkZGOmZ1bmN0aW9uKGEsYil7cmV0dXJuIEguSXgoYS5lVCxi
+KX0sCkU6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9YS5lQyxyPXMuZ2V0KGIpCmlmKHIhPW51bGwpcmV0
+dXJuIHIKdD1ILnooYSxudWxsLGIsYykKcy5zZXQoYix0KQpyZXR1cm4gdH0sCmNFOmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdCxzLHI9Yi5jaAppZihyPT1udWxsKXI9Yi5jaD1uZXcgTWFwKCkKdD1yLmdldChjKQpp
+Zih0IT1udWxsKXJldHVybiB0CnM9SC56KGEsYixjLCEwKQpyLnNldChjLHMpCnJldHVybiBzfSwKdjU6
+ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxPWIuY3gKaWYocT09bnVsbClxPWIuY3g9bmV3IE1hcCgp
+CnQ9Yy5jeQpzPXEuZ2V0KHQpCmlmKHMhPW51bGwpcmV0dXJuIHMKcj1ILmFwKGEsYixjLnk9PT0xMD9j
+LlE6W2NdKQpxLnNldCh0LHIpCnJldHVybiByfSwKejpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdD1ILmko
+SC5vKGEsYixjLGQpKQppZih0IT1udWxsKXJldHVybiB0CnRocm93IEguYihQLm4oJ19Vbml2ZXJzZS5f
+cGFyc2VSZWNpcGUoIicrSC5kKGMpKyciKScpKX0sCkJEOmZ1bmN0aW9uKGEsYil7Yi5hPUguT3oKYi5i
+PUguSkoKcmV0dXJuIGJ9LAptWjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyPWEuZUMuZ2V0KGMpCmlm
+KHIhPW51bGwpcmV0dXJuIHIKdD1uZXcgSC5KYyhudWxsLG51bGwpCnQueT1iCnQuY3k9YwpzPUguQkQo
+YSx0KQphLmVDLnNldChjLHMpCnJldHVybiBzfSwKU086ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9Yi5j
+eSsiKiIscj1hLmVDLmdldChzKQppZihyIT1udWxsKXJldHVybiByCnQ9SC5aNyhhLGIscyxjKQphLmVD
+LnNldChzLHQpCnJldHVybiB0fSwKWjc6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscwppZihkKXt0PWIu
+eQppZihILkE4KGIpfHxiPT09dS5LfHxiPT09dS5QfHx0PT09N3x8dD09PTYpcmV0dXJuIGJ9cz1uZXcg
+SC5KYyhudWxsLG51bGwpCnMueT02CnMuej1iCnMuY3k9YwpyZXR1cm4gSC5CRChhLHMpfSwKQmM6ZnVu
+Y3Rpb24oYSxiLGMpe3ZhciB0LHM9Yi5jeSsiPyIscj1hLmVDLmdldChzKQppZihyIT1udWxsKXJldHVy
+biByCnQ9SC5sbChhLGIscyxjKQphLmVDLnNldChzLHQpCnJldHVybiB0fSwKbGw6ZnVuY3Rpb24oYSxi
+LGMsZCl7dmFyIHQscyxyLHEscAppZihkKXt0PWIueQppZighSC5BOChiKSlpZighKGI9PT11LlApKWlm
+KHQhPT03KXM9dD09PTgmJkgubFIoYi56KQplbHNlIHM9ITAKZWxzZSBzPSEwCmVsc2Ugcz0hMAppZihz
+KXJldHVybiBiCmVsc2UgaWYodD09PTEpcmV0dXJuIHUuUAplbHNlIGlmKHQ9PT02KXtyPWIuegpxPXIu
+eQppZihxPT09MSlyZXR1cm4gdS5QCmVsc2UgaWYocT09PTgmJkgubFIoci56KSlyZXR1cm4gcgplbHNl
+IHJldHVybiBILmN6KGEsYil9fXA9bmV3IEguSmMobnVsbCxudWxsKQpwLnk9NwpwLno9YgpwLmN5PWMK
+cmV0dXJuIEguQkQoYSxwKX0sCkxOOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPWIuY3krIi8iLHI9YS5l
+Qy5nZXQocykKaWYociE9bnVsbClyZXR1cm4gcgp0PUguZVYoYSxiLHMsYykKYS5lQy5zZXQocyx0KQpy
+ZXR1cm4gdH0sCmVWOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMKaWYoZCl7dD1iLnkKaWYoSC5BOChi
+KXx8Yj09PXUuS3x8Yj09PXUuSylyZXR1cm4gYgplbHNlIGlmKHQ9PT0xKXJldHVybiBILlEyKGEsImI4
+IixbYl0pCmVsc2UgaWYoYj09PXUuUClyZXR1cm4gdS5hUX1zPW5ldyBILkpjKG51bGwsbnVsbCkKcy55
+PTgKcy56PWIKcy5jeT1jCnJldHVybiBILkJEKGEscyl9LApIYzpmdW5jdGlvbihhLGIpe3ZhciB0LHMs
+cj0iIitiKyJeIixxPWEuZUMuZ2V0KHIpCmlmKHEhPW51bGwpcmV0dXJuIHEKdD1uZXcgSC5KYyhudWxs
+LG51bGwpCnQueT0xMwp0Lno9Ygp0LmN5PXIKcz1ILkJEKGEsdCkKYS5lQy5zZXQocixzKQpyZXR1cm4g
+c30sClV4OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPWEubGVuZ3RoCmZvcih0PSIiLHM9IiIscj0wO3I8
+cTsrK3Iscz0iLCIpdCs9cythW3JdLmN5CnJldHVybiB0fSwKUzQ6ZnVuY3Rpb24oYSl7dmFyIHQscyxy
+LHEscCxvPWEubGVuZ3RoCmZvcih0PSIiLHM9IiIscj0wO3I8bztyKz0yLHM9IiwiKXtxPWFbcl0KcD1h
+W3IrMV0uY3kKdCs9cytxKyI6IitwfXJldHVybiB0fSwKUTI6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMs
+cixxPWIKaWYoYy5sZW5ndGghPT0wKXErPSI8IitILlV4KGMpKyI+Igp0PWEuZUMuZ2V0KHEpCmlmKHQh
+PW51bGwpcmV0dXJuIHQKcz1uZXcgSC5KYyhudWxsLG51bGwpCnMueT05CnMuej1iCnMuUT1jCmlmKGMu
+bGVuZ3RoPjApcy5jPWNbMF0Kcy5jeT1xCnI9SC5CRChhLHMpCmEuZUMuc2V0KHEscikKcmV0dXJuIHJ9
+LAphcDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvCmlmKGIueT09PTEwKXt0PWIuegpzPWIu
+US5jb25jYXQoYyl9ZWxzZXtzPWMKdD1ifXI9dC5jeSsiOyIrKCI8IitILlV4KHMpKyI+IikKcT1hLmVD
+LmdldChyKQppZihxIT1udWxsKXJldHVybiBxCnA9bmV3IEguSmMobnVsbCxudWxsKQpwLnk9MTAKcC56
+PXQKcC5RPXMKcC5jeT1yCm89SC5CRChhLHApCmEuZUMuc2V0KHIsbykKcmV0dXJuIG99LApOZjpmdW5j
+dGlvbihhLGIsYyl7dmFyIHQscyxyLHEscD1iLmN5LG89Yy5hLG49by5sZW5ndGgsbT1jLmIsbD1tLmxl
+bmd0aCxrPWMuYyxqPWsubGVuZ3RoLGk9IigiK0guVXgobykKaWYobD4wKWkrPShuPjA/IiwiOiIiKSsi
+WyIrSC5VeChtKSsiXSIKaWYoaj4wKWkrPShuPjA/IiwiOiIiKSsieyIrSC5TNChrKSsifSIKdD1wKyhp
+KyIpIikKcz1hLmVDLmdldCh0KQppZihzIT1udWxsKXJldHVybiBzCnI9bmV3IEguSmMobnVsbCxudWxs
+KQpyLnk9MTEKci56PWIKci5RPWMKci5jeT10CnE9SC5CRChhLHIpCmEuZUMuc2V0KHQscSkKcmV0dXJu
+IHF9LApEUzpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzPWIuY3krIjwiK0guVXgoYykrIj4iLHI9YS5l
+Qy5nZXQocykKaWYociE9bnVsbClyZXR1cm4gcgp0PUguaHcoYSxiLGMscyxkKQphLmVDLnNldChzLHQp
+CnJldHVybiB0fSwKaHc6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzLHIscSxwLG8sbixtCmlmKGUp
+e3Q9Yy5sZW5ndGgKcz1uZXcgQXJyYXkodCkKZm9yKHI9MCxxPTA7cTx0OysrcSl7cD1jW3FdCmlmKHAu
+eT09PTEpe3NbcV09cDsrK3J9fWlmKHI+MCl7bz1ILlBMKGEsYixzLDApCm49SC5iWihhLGMscywwKQpy
+ZXR1cm4gSC5EUyhhLG8sbixjIT09bil9fW09bmV3IEguSmMobnVsbCxudWxsKQptLnk9MTIKbS56PWIK
+bS5RPWMKbS5jeT1kCnJldHVybiBILkJEKGEsbSl9LApvOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybnt1
+OmEsZTpiLHI6YyxzOltdLHA6MCxuOmR9fSwKaTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixt
+LGwsayxqLGksaD1hLnIsZz1hLnMKZm9yKHQ9aC5sZW5ndGgscz0wO3M8dDspe3I9aC5jaGFyQ29kZUF0
+KHMpCmlmKHI+PTQ4JiZyPD01NylzPUguQWwocysxLHIsaCxnKQplbHNlIGlmKCgoKHJ8MzIpPj4+MCkt
+OTcmNjU1MzUpPDI2fHxyPT09OTV8fHI9PT0zNilzPUguUjgoYSxzLGgsZywhMSkKZWxzZSBpZihyPT09
+NDYpcz1ILlI4KGEscyxoLGcsITApCmVsc2V7KytzCnN3aXRjaChyKXtjYXNlIDQ0OmJyZWFrCmNhc2Ug
+NTg6YnJlYWsKY2FzZSA1OTpnLnB1c2goSC5LUShhLnUsYS5lLGcucG9wKCkpKQpicmVhawpjYXNlIDk0
+OmcucHVzaChILkhjKGEudSxnLnBvcCgpKSkKYnJlYWsKY2FzZSAzNTpnLnB1c2goSC5tWihhLnUsNSwi
+IyIpKQpicmVhawpjYXNlIDY0OmcucHVzaChILm1aKGEudSwyLCJAIikpCmJyZWFrCmNhc2UgMTI2Omcu
+cHVzaChILm1aKGEudSwzLCJ+IikpCmJyZWFrCmNhc2UgNjA6Zy5wdXNoKGEucCkKYS5wPWcubGVuZ3Ro
+CmJyZWFrCmNhc2UgNjI6cT1hLnUKcD1nLnNwbGljZShhLnApCkguclQoYS51LGEuZSxwKQphLnA9Zy5w
+b3AoKQpvPWcucG9wKCkKaWYodHlwZW9mIG89PSJzdHJpbmciKWcucHVzaChILlEyKHEsbyxwKSkKZWxz
+ZXtuPUguS1EocSxhLmUsbykKc3dpdGNoKG4ueSl7Y2FzZSAxMTpnLnB1c2goSC5EUyhxLG4scCxhLm4p
+KQpicmVhawpkZWZhdWx0OmcucHVzaChILmFwKHEsbixwKSkKYnJlYWt9fWJyZWFrCmNhc2UgMzg6SC5J
+MyhhLGcpCmJyZWFrCmNhc2UgNDI6bT1hLnUKZy5wdXNoKEguU08obSxILktRKG0sYS5lLGcucG9wKCkp
+LGEubikpCmJyZWFrCmNhc2UgNjM6bT1hLnUKZy5wdXNoKEguQmMobSxILktRKG0sYS5lLGcucG9wKCkp
+LGEubikpCmJyZWFrCmNhc2UgNDc6bT1hLnUKZy5wdXNoKEguTE4obSxILktRKG0sYS5lLGcucG9wKCkp
+LGEubikpCmJyZWFrCmNhc2UgNDA6Zy5wdXNoKGEucCkKYS5wPWcubGVuZ3RoCmJyZWFrCmNhc2UgNDE6
+cT1hLnUKbD1uZXcgSC5FVCgpCms9cS5zRUEKaj1xLnNFQQpvPWcucG9wKCkKaWYodHlwZW9mIG89PSJu
+dW1iZXIiKXN3aXRjaChvKXtjYXNlLTE6az1nLnBvcCgpCmJyZWFrCmNhc2UtMjpqPWcucG9wKCkKYnJl
+YWsKZGVmYXVsdDpnLnB1c2gobykKYnJlYWt9ZWxzZSBnLnB1c2gobykKcD1nLnNwbGljZShhLnApCkgu
+clQoYS51LGEuZSxwKQphLnA9Zy5wb3AoKQpsLmE9cApsLmI9awpsLmM9agpnLnB1c2goSC5OZihxLEgu
+S1EocSxhLmUsZy5wb3AoKSksbCkpCmJyZWFrCmNhc2UgOTE6Zy5wdXNoKGEucCkKYS5wPWcubGVuZ3Ro
+CmJyZWFrCmNhc2UgOTM6cD1nLnNwbGljZShhLnApCkguclQoYS51LGEuZSxwKQphLnA9Zy5wb3AoKQpn
+LnB1c2gocCkKZy5wdXNoKC0xKQpicmVhawpjYXNlIDEyMzpnLnB1c2goYS5wKQphLnA9Zy5sZW5ndGgK
+YnJlYWsKY2FzZSAxMjU6cD1nLnNwbGljZShhLnApCkguV1MoYS51LGEuZSxwKQphLnA9Zy5wb3AoKQpn
+LnB1c2gocCkKZy5wdXNoKC0yKQpicmVhawpkZWZhdWx0OnRocm93IkJhZCBjaGFyYWN0ZXIgIityfX19
+aT1nLnBvcCgpCnJldHVybiBILktRKGEudSxhLmUsaSl9LApBbDpmdW5jdGlvbihhLGIsYyxkKXt2YXIg
+dCxzLHI9Yi00OApmb3IodD1jLmxlbmd0aDthPHQ7KythKXtzPWMuY2hhckNvZGVBdChhKQppZighKHM+
+PTQ4JiZzPD01NykpYnJlYWsKcj1yKjEwKyhzLTQ4KX1kLnB1c2gocikKcmV0dXJuIGF9LApSODpmdW5j
+dGlvbihhLGIsYyxkLGUpe3ZhciB0LHMscixxLHAsbyxuPWIrMQpmb3IodD1jLmxlbmd0aDtuPHQ7Kytu
+KXtzPWMuY2hhckNvZGVBdChuKQppZihzPT09NDYpe2lmKGUpYnJlYWsKZT0hMH1lbHNle2lmKCEoKCgo
+c3wzMik+Pj4wKS05NyY2NTUzNSk8MjZ8fHM9PT05NXx8cz09PTM2KSlyPXM+PTQ4JiZzPD01NwplbHNl
+IHI9ITAKaWYoIXIpYnJlYWt9fXE9Yy5zdWJzdHJpbmcoYixuKQppZihlKXt0PWEudQpwPWEuZQppZihw
+Lnk9PT0xMClwPXAuegpvPUguUW8odCxwLnopW3FdCmlmKG89PW51bGwpSC52aCgnTm8gIicrcSsnIiBp
+biAiJytILm1EKHApKyciJykKZC5wdXNoKEguY0UodCxwLG8pKX1lbHNlIGQucHVzaChxKQpyZXR1cm4g
+bn0sCkkzOmZ1bmN0aW9uKGEsYil7dmFyIHQ9Yi5wb3AoKQppZigwPT09dCl7Yi5wdXNoKEgubVooYS51
+LDEsIjAmIikpCnJldHVybn1pZigxPT09dCl7Yi5wdXNoKEgubVooYS51LDQsIjEmIikpCnJldHVybn10
+aHJvdyBILmIoUC5oVigiVW5leHBlY3RlZCBleHRlbmRlZCBvcGVyYXRpb24gIitILmQodCkpKX0sCktR
+OmZ1bmN0aW9uKGEsYixjKXtpZih0eXBlb2YgYz09InN0cmluZyIpcmV0dXJuIEguUTIoYSxjLGEuc0VB
+KQplbHNlIGlmKHR5cGVvZiBjPT0ibnVtYmVyIilyZXR1cm4gSC5UVihhLGIsYykKZWxzZSByZXR1cm4g
+Y30sCnJUOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPWMubGVuZ3RoCmZvcih0PTA7dDxzOysrdCljW3Rd
+PUguS1EoYSxiLGNbdF0pfSwKV1M6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9Yy5sZW5ndGgKZm9yKHQ9
+MTt0PHM7dCs9MiljW3RdPUguS1EoYSxiLGNbdF0pfSwKVFY6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMs
+cj1iLnkKaWYocj09PTEwKXtpZihjPT09MClyZXR1cm4gYi56CnQ9Yi5RCnM9dC5sZW5ndGgKaWYoYzw9
+cylyZXR1cm4gdFtjLTFdCmMtPXMKYj1iLnoKcj1iLnl9ZWxzZSBpZihjPT09MClyZXR1cm4gYgppZihy
+IT09OSl0aHJvdyBILmIoUC5oVigiSW5kZXhlZCBiYXNlIG11c3QgYmUgYW4gaW50ZXJmYWNlIHR5cGUi
+KSkKdD1iLlEKaWYoYzw9dC5sZW5ndGgpcmV0dXJuIHRbYy0xXQp0aHJvdyBILmIoUC5oVigiQmFkIGlu
+ZGV4ICIrYysiIGZvciAiK2IuWigwKSkpfSwKV2U6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzLHIs
+cSxwLG8sbixtLGwsawppZihiPT09ZClyZXR1cm4hMAppZihILkE4KGQpfHxkPT09dS5LKXJldHVybiEw
+CnQ9Yi55CmlmKHQ9PT00KXJldHVybiEwCmlmKEguQTgoYikpcmV0dXJuITEKaWYoYj09PXUuUClyZXR1
+cm4hMApzPXQ9PT0xMwppZihzKWlmKEguV2UoYSxjW2Iuel0sYyxkLGUpKXJldHVybiEwCnI9ZC55Cmlm
+KHQ9PT02KXJldHVybiBILldlKGEsYi56LGMsZCxlKQppZihyPT09Nil7cT1kLnoKcmV0dXJuIEguV2Uo
+YSxiLGMscSxlKX1pZih0PT09OCl7aWYoIUguV2UoYSxiLnosYyxkLGUpKXJldHVybiExCnJldHVybiBI
+LldlKGEsSC54WihhLGIpLGMsZCxlKX1pZih0PT09Nyl7cT1ILldlKGEsYi56LGMsZCxlKQpyZXR1cm4g
+cX1pZihyPT09OCl7aWYoSC5XZShhLGIsYyxkLnosZSkpcmV0dXJuITAKcmV0dXJuIEguV2UoYSxiLGMs
+SC54WihhLGQpLGUpfWlmKHI9PT03KXtxPUguV2UoYSxiLGMsZC56LGUpCnJldHVybiBxfWlmKHMpcmV0
+dXJuITEKcT10IT09MTEKaWYoKCFxfHx0PT09MTIpJiZkPT09dS5aKXJldHVybiEwCmlmKHI9PT0xMil7
+aWYoYj09PXUuZylyZXR1cm4hMAppZih0IT09MTIpcmV0dXJuITEKcD1iLlEKbz1kLlEKbj1wLmxlbmd0
+aAppZihuIT09by5sZW5ndGgpcmV0dXJuITEKYz1jPT1udWxsP3A6cC5jb25jYXQoYykKZT1lPT1udWxs
+P286by5jb25jYXQoZSkKZm9yKHE9dS5hdixtPTA7bTxuOysrbSl7bD1wW21dCms9b1ttXQpxLmEobCkK
+cS5hKGspCmlmKCFILldlKGEsbCxjLGssZSl8fCFILldlKGEsayxlLGwsYykpcmV0dXJuITF9cmV0dXJu
+IEguYk8oYSxiLnosYyxkLnosZSl9aWYocj09PTExKXtpZihiPT09dS5nKXJldHVybiEwCmlmKHEpcmV0
+dXJuITEKcmV0dXJuIEguYk8oYSxiLGMsZCxlKX1pZih0PT09OSl7aWYociE9PTkpcmV0dXJuITEKcmV0
+dXJuIEgucEcoYSxiLGMsZCxlKX1yZXR1cm4hMX0sCmJPOmZ1bmN0aW9uKGEwLGExLGEyLGEzLGE0KXt2
+YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZSxkLGMsYixhCmlmKCFILldlKGEwLGExLnos
+YTIsYTMueixhNCkpcmV0dXJuITEKdD1hMS5RCnM9YTMuUQpyPXQuYQpxPXMuYQpwPXIubGVuZ3RoCm89
+cS5sZW5ndGgKaWYocD5vKXJldHVybiExCm49by1wCm09dC5iCmw9cy5iCms9bS5sZW5ndGgKaj1sLmxl
+bmd0aAppZihwK2s8bytqKXJldHVybiExCmZvcihpPTA7aTxwOysraSl7aD1yW2ldCmlmKCFILldlKGEw
+LHFbaV0sYTQsaCxhMikpcmV0dXJuITF9Zm9yKGk9MDtpPG47KytpKXtoPW1baV0KaWYoIUguV2UoYTAs
+cVtwK2ldLGE0LGgsYTIpKXJldHVybiExfWZvcihpPTA7aTxqOysraSl7aD1tW24raV0KaWYoIUguV2Uo
+YTAsbFtpXSxhNCxoLGEyKSlyZXR1cm4hMX1nPXQuYwpmPXMuYwplPWcubGVuZ3RoCmQ9Zi5sZW5ndGgK
+Zm9yKGk9MCxjPTA7YzxkO2MrPTIpe2I9ZltjXQpkb3tpZihpPj1lKXJldHVybiExCmE9Z1tpXQppKz0y
+fXdoaWxlKGE8YikKaWYoYjxhKXJldHVybiExCmg9Z1tpLTFdCmlmKCFILldlKGEwLGZbYysxXSxhNCxo
+LGEyKSlyZXR1cm4hMX1yZXR1cm4hMH0sCnBHOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxyLHEs
+cCxvLG4sbSxsPWIueixrPWQuegppZihsPT09ayl7dD1iLlEKcz1kLlEKcj10Lmxlbmd0aApmb3IocT0w
+O3E8cjsrK3Epe3A9dFtxXQpvPXNbcV0KaWYoIUguV2UoYSxwLGMsbyxlKSlyZXR1cm4hMX1yZXR1cm4h
+MH1pZihkPT09dS5LKXJldHVybiEwCm49SC5RbyhhLGwpCmlmKG49PW51bGwpcmV0dXJuITEKbT1uW2td
+CmlmKG09PW51bGwpcmV0dXJuITEKcj1tLmxlbmd0aApzPWQuUQpmb3IocT0wO3E8cjsrK3EpaWYoIUgu
+V2UoYSxILmNFKGEsYixtW3FdKSxjLHNbcV0sZSkpcmV0dXJuITEKcmV0dXJuITB9LApsUjpmdW5jdGlv
+bihhKXt2YXIgdCxzPWEueQppZighKGE9PT11LlApKWlmKCFILkE4KGEpKWlmKHMhPT03KWlmKCEocz09
+PTYmJkgubFIoYS56KSkpdD1zPT09OCYmSC5sUihhLnopCmVsc2UgdD0hMAplbHNlIHQ9ITAKZWxzZSB0
+PSEwCmVsc2UgdD0hMApyZXR1cm4gdH0sCmNjOmZ1bmN0aW9uKGEpe3JldHVybiBILkE4KGEpfHxhPT09
+dS5LfSwKQTg6ZnVuY3Rpb24oYSl7dmFyIHQscz1hLnkscj1zCmlmKHIhPT0yKWlmKHIhPT0zKWlmKHIh
+PT00KWlmKHIhPT01KXt0PXUuSwppZighKGE9PT10KSlzPXM9PT03JiZhLno9PT10CmVsc2Ugcz0hMH1l
+bHNlIHM9ITAKZWxzZSBzPSEwCmVsc2Ugcz0hMAplbHNlIHM9ITAKcmV0dXJuIHN9LApJeDpmdW5jdGlv
+bihhLGIpe3ZhciB0LHMscj1PYmplY3Qua2V5cyhiKSxxPXIubGVuZ3RoCmZvcih0PTA7dDxxOysrdCl7
+cz1yW3RdCmFbc109YltzXX19LApKYzpmdW5jdGlvbiBKYyhhLGIpe3ZhciBfPXRoaXMKXy5hPWEKXy5i
+PWIKXy54PV8ucj1fLmM9bnVsbApfLnk9MApfLmN5PV8uY3g9Xy5jaD1fLlE9Xy56PW51bGx9LApFVDpm
+dW5jdGlvbiBFVCgpe3RoaXMuYz10aGlzLmI9dGhpcy5hPW51bGx9LAp1OTpmdW5jdGlvbiB1OSgpe30s
+Cng6ZnVuY3Rpb24geChhKXt0aGlzLmE9YX0sClI5OmZ1bmN0aW9uKGEpe3JldHVybiB1LmQuYihhKXx8
+dS5CLmIoYSl8fHUuZHouYihhKXx8dS5JLmIoYSl8fHUuQS5iKGEpfHx1Lmc0LmIoYSl8fHUuZzIuYihh
+KX0sCkpnOmZ1bmN0aW9uKGEpe3JldHVybiB2Lm1hbmdsZWRHbG9iYWxOYW1lc1thXX19LEo9ewpRdTpm
+dW5jdGlvbihhLGIsYyxkKXtyZXR1cm57aTphLHA6YixlOmMseDpkfX0sCmtzOmZ1bmN0aW9uKGEpe3Zh
+ciB0LHMscixxLHA9YVt2LmRpc3BhdGNoUHJvcGVydHlOYW1lXQppZihwPT1udWxsKWlmKCQuSz09bnVs
+bCl7SC5NKCkKcD1hW3YuZGlzcGF0Y2hQcm9wZXJ0eU5hbWVdfWlmKHAhPW51bGwpe3Q9cC5wCmlmKCEx
+PT09dClyZXR1cm4gcC5pCmlmKCEwPT09dClyZXR1cm4gYQpzPU9iamVjdC5nZXRQcm90b3R5cGVPZihh
+KQppZih0PT09cylyZXR1cm4gcC5pCmlmKHAuZT09PXMpdGhyb3cgSC5iKFAubigiUmV0dXJuIGludGVy
+Y2VwdG9yIGZvciAiK0guZCh0KGEscCkpKSl9cj1hLmNvbnN0cnVjdG9yCnE9cj09bnVsbD9udWxsOnJb
+JC5BKCldCmlmKHEhPW51bGwpcmV0dXJuIHEKcT1ILkcoYSkKaWYocSE9bnVsbClyZXR1cm4gcQppZih0
+eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gQy5ERwp0PU9iamVjdC5nZXRQcm90b3R5cGVPZihhKQpp
+Zih0PT1udWxsKXJldHVybiBDLlpRCmlmKHQ9PT1PYmplY3QucHJvdG90eXBlKXJldHVybiBDLlpRCmlm
+KHR5cGVvZiByPT0iZnVuY3Rpb24iKXtPYmplY3QuZGVmaW5lUHJvcGVydHkociwkLkEoKSx7dmFsdWU6
+Qy52QixlbnVtZXJhYmxlOmZhbHNlLHdyaXRhYmxlOnRydWUsY29uZmlndXJhYmxlOnRydWV9KQpyZXR1
+cm4gQy52Qn1yZXR1cm4gQy52Qn0sClFpOmZ1bmN0aW9uKGEsYil7aWYoYTwwfHxhPjQyOTQ5NjcyOTUp
+dGhyb3cgSC5iKFAuVEUoYSwwLDQyOTQ5NjcyOTUsImxlbmd0aCIsbnVsbCkpCnJldHVybiBKLnB5KG5l
+dyBBcnJheShhKSxiKX0sCnB5OmZ1bmN0aW9uKGEsYil7cmV0dXJuIEouRXAoSC5WTShhLGIuQygiamQ8
+MD4iKSkpfSwKRXA6ZnVuY3Rpb24oYSl7YS5maXhlZCRsZW5ndGg9QXJyYXkKcmV0dXJuIGF9LAp1bjpm
+dW5jdGlvbihhKXthLmZpeGVkJGxlbmd0aD1BcnJheQphLmltbXV0YWJsZSRsaXN0PUFycmF5CnJldHVy
+biBhfSwKR2E6ZnVuY3Rpb24oYSl7aWYoYTwyNTYpc3dpdGNoKGEpe2Nhc2UgOTpjYXNlIDEwOmNhc2Ug
+MTE6Y2FzZSAxMjpjYXNlIDEzOmNhc2UgMzI6Y2FzZSAxMzM6Y2FzZSAxNjA6cmV0dXJuITAKZGVmYXVs
+dDpyZXR1cm4hMX1zd2l0Y2goYSl7Y2FzZSA1NzYwOmNhc2UgODE5MjpjYXNlIDgxOTM6Y2FzZSA4MTk0
+OmNhc2UgODE5NTpjYXNlIDgxOTY6Y2FzZSA4MTk3OmNhc2UgODE5ODpjYXNlIDgxOTk6Y2FzZSA4MjAw
+OmNhc2UgODIwMTpjYXNlIDgyMDI6Y2FzZSA4MjMyOmNhc2UgODIzMzpjYXNlIDgyMzk6Y2FzZSA4Mjg3
+OmNhc2UgMTIyODg6Y2FzZSA2NTI3OTpyZXR1cm4hMApkZWZhdWx0OnJldHVybiExfX0sCm1tOmZ1bmN0
+aW9uKGEsYil7dmFyIHQscwpmb3IodD1hLmxlbmd0aDtiPHQ7KXtzPUMueEIuVyhhLGIpCmlmKHMhPT0z
+MiYmcyE9PTEzJiYhSi5HYShzKSlicmVhazsrK2J9cmV0dXJuIGJ9LApjMTpmdW5jdGlvbihhLGIpe3Zh
+ciB0LHMKZm9yKDtiPjA7Yj10KXt0PWItMQpzPUMueEIubShhLHQpCmlmKHMhPT0zMiYmcyE9PTEzJiYh
+Si5HYShzKSlicmVha31yZXR1cm4gYn0sClJFOmZ1bmN0aW9uKGEpe2lmKGE9PW51bGwpcmV0dXJuIGEK
+aWYodHlwZW9mIGEhPSJvYmplY3QiKXtpZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gSi5jNS5w
+cm90b3R5cGUKcmV0dXJuIGF9aWYoYSBpbnN0YW5jZW9mIFAuTWgpcmV0dXJuIGEKcmV0dXJuIEoua3Mo
+YSl9LApUSjpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09Im51bWJlciIpcmV0dXJuIEoucUkucHJvdG90
+eXBlCmlmKHR5cGVvZiBhPT0ic3RyaW5nIilyZXR1cm4gSi5Eci5wcm90b3R5cGUKaWYoYT09bnVsbCly
+ZXR1cm4gYQppZihhLmNvbnN0cnVjdG9yPT1BcnJheSlyZXR1cm4gSi5qZC5wcm90b3R5cGUKaWYodHlw
+ZW9mIGEhPSJvYmplY3QiKXtpZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gSi5jNS5wcm90b3R5
+cGUKcmV0dXJuIGF9aWYoYSBpbnN0YW5jZW9mIFAuTWgpcmV0dXJuIGEKcmV0dXJuIEoua3MoYSl9LApV
+NjpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJuIEouRHIucHJvdG90eXBlCmlm
+KGE9PW51bGwpcmV0dXJuIGEKaWYoYS5jb25zdHJ1Y3Rvcj09QXJyYXkpcmV0dXJuIEouamQucHJvdG90
+eXBlCmlmKHR5cGVvZiBhIT0ib2JqZWN0Iil7aWYodHlwZW9mIGE9PSJmdW5jdGlvbiIpcmV0dXJuIEou
+YzUucHJvdG90eXBlCnJldHVybiBhfWlmKGEgaW5zdGFuY2VvZiBQLk1oKXJldHVybiBhCnJldHVybiBK
+LmtzKGEpfSwKaWE6ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJudW1iZXIiKXtpZihNYXRoLmZsb29y
+KGEpPT1hKXJldHVybiBKLmJVLnByb3RvdHlwZQpyZXR1cm4gSi5WQS5wcm90b3R5cGV9aWYodHlwZW9m
+IGE9PSJzdHJpbmciKXJldHVybiBKLkRyLnByb3RvdHlwZQppZihhPT1udWxsKXJldHVybiBKLllFLnBy
+b3RvdHlwZQppZih0eXBlb2YgYT09ImJvb2xlYW4iKXJldHVybiBKLnlFLnByb3RvdHlwZQppZihhLmNv
bnN0cnVjdG9yPT1BcnJheSlyZXR1cm4gSi5qZC5wcm90b3R5cGUKaWYodHlwZW9mIGEhPSJvYmplY3Qi
KXtpZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gSi5jNS5wcm90b3R5cGUKcmV0dXJuIGF9aWYo
-YSBpbnN0YW5jZW9mIFAuaylyZXR1cm4gYQpyZXR1cm4gSi5rcyhhKX0sClU2OmZ1bmN0aW9uKGEpe2lm
-KHR5cGVvZiBhPT0ic3RyaW5nIilyZXR1cm4gSi5Eci5wcm90b3R5cGUKaWYoYT09bnVsbClyZXR1cm4g
-YQppZihhLmNvbnN0cnVjdG9yPT1BcnJheSlyZXR1cm4gSi5qZC5wcm90b3R5cGUKaWYodHlwZW9mIGEh
-PSJvYmplY3QiKXtpZih0eXBlb2YgYT09ImZ1bmN0aW9uIilyZXR1cm4gSi5jNS5wcm90b3R5cGUKcmV0
-dXJuIGF9aWYoYSBpbnN0YW5jZW9mIFAuaylyZXR1cm4gYQpyZXR1cm4gSi5rcyhhKX0sCmlhOmZ1bmN0
-aW9uKGEpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIil7aWYoTWF0aC5mbG9vcihhKT09YSlyZXR1cm4gSi5i
-VS5wcm90b3R5cGUKcmV0dXJuIEouVkEucHJvdG90eXBlfWlmKHR5cGVvZiBhPT0ic3RyaW5nIilyZXR1
-cm4gSi5Eci5wcm90b3R5cGUKaWYoYT09bnVsbClyZXR1cm4gSi5ZRS5wcm90b3R5cGUKaWYodHlwZW9m
-IGE9PSJib29sZWFuIilyZXR1cm4gSi55RS5wcm90b3R5cGUKaWYoYS5jb25zdHJ1Y3Rvcj09QXJyYXkp
-cmV0dXJuIEouamQucHJvdG90eXBlCmlmKHR5cGVvZiBhIT0ib2JqZWN0Iil7aWYodHlwZW9mIGE9PSJm
-dW5jdGlvbiIpcmV0dXJuIEouYzUucHJvdG90eXBlCnJldHVybiBhfWlmKGEgaW5zdGFuY2VvZiBQLmsp
-cmV0dXJuIGEKcmV0dXJuIEoua3MoYSl9LApyWTpmdW5jdGlvbihhKXtpZih0eXBlb2YgYT09InN0cmlu
-ZyIpcmV0dXJuIEouRHIucHJvdG90eXBlCmlmKGE9PW51bGwpcmV0dXJuIGEKaWYoIShhIGluc3RhbmNl
-b2YgUC5rKSlyZXR1cm4gSi5rZC5wcm90b3R5cGUKcmV0dXJuIGF9LAp3MTpmdW5jdGlvbihhKXtpZihh
-PT1udWxsKXJldHVybiBhCmlmKGEuY29uc3RydWN0b3I9PUFycmF5KXJldHVybiBKLmpkLnByb3RvdHlw
-ZQppZih0eXBlb2YgYSE9Im9iamVjdCIpe2lmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBKLmM1
-LnByb3RvdHlwZQpyZXR1cm4gYX1pZihhIGluc3RhbmNlb2YgUC5rKXJldHVybiBhCnJldHVybiBKLmtz
-KGEpfSwKQ006ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIEouUkUoYSkuZHUoYSxiLGMsZCl9LApGTDpm
-dW5jdGlvbihhLGIpe3JldHVybiBKLnJZKGEpLmRkKGEsYil9LApHQTpmdW5jdGlvbihhLGIpe3JldHVy
-biBKLncxKGEpLkUoYSxiKX0sCkdyOmZ1bmN0aW9uKGEpe3JldHVybiBKLlJFKGEpLmdtVyhhKX0sCkht
-OmZ1bmN0aW9uKGEpe3JldHVybiBKLlU2KGEpLmdBKGEpfSwKSVQ6ZnVuY3Rpb24oYSl7cmV0dXJuIEou
-dzEoYSkuZ2t6KGEpfSwKSnk6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSi5pYShhKS5lNyhhLGIpfSwKS1Y6
-ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSi5yWShhKS5HKGEsYil9LApMdDpmdW5jdGlvbihhKXtyZXR1cm4g
-Si5SRShhKS53ZyhhKX0sCk0xOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gSi53MShhKS5FMihhLGIsYyl9
-LApNdTpmdW5jdGlvbihhLGIpe3JldHVybiBKLlJFKGEpLnNQKGEsYil9LApRejpmdW5jdGlvbihhLGIp
-e3JldHVybiBKLnJZKGEpLlcoYSxiKX0sClJNOmZ1bmN0aW9uKGEsYil7aWYoYT09bnVsbClyZXR1cm4g
-Yj09bnVsbAppZih0eXBlb2YgYSE9Im9iamVjdCIpcmV0dXJuIGIhPW51bGwmJmE9PT1iCnJldHVybiBK
-LmlhKGEpLkROKGEsYil9LApUMDpmdW5jdGlvbihhKXtyZXR1cm4gSi5yWShhKS5iUyhhKX0sCmE2OmZ1
-bmN0aW9uKGEsYil7cmV0dXJuIEouclkoYSkubShhLGIpfSwKYlQ6ZnVuY3Rpb24oYSl7cmV0dXJuIEou
-UkUoYSkuRDQoYSl9LApiYjpmdW5jdGlvbihhLGIpe2lmKHR5cGVvZiBhPT0ibnVtYmVyIiYmdHlwZW9m
-IGI9PSJudW1iZXIiKXJldHVybiBhK2IKcmV0dXJuIEouVEooYSkuaChhLGIpfSwKY0g6ZnVuY3Rpb24o
-YSl7cmV0dXJuIEouclkoYSkuaGMoYSl9LApkUjpmdW5jdGlvbihhKXtyZXR1cm4gSi5SRShhKS5nUChh
-KX0sCmRaOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybiBKLlJFKGEpLk9uKGEsYixjLGQpfSwKZGc6ZnVu
-Y3Rpb24oYSxiLGMsZCl7cmV0dXJuIEouclkoYSkuaTcoYSxiLGMsZCl9LApkaDpmdW5jdGlvbihhKXty
-ZXR1cm4gSi5SRShhKS5GRihhKX0sCmhmOmZ1bmN0aW9uKGEpe3JldHVybiBKLmlhKGEpLmdpTyhhKX0s
-CmlnOmZ1bmN0aW9uKGEpe3JldHVybiBKLlJFKGEpLmdRZyhhKX0sCmo6ZnVuY3Rpb24oYSl7cmV0dXJu
-IEouaWEoYSkudyhhKX0sCmw1OmZ1bmN0aW9uKGEsYil7cmV0dXJuIEouUkUoYSkuc2hmKGEsYil9LAps
-ZDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIEouclkoYSkuTmooYSxiLGMpfSwKcTA6ZnVuY3Rpb24oYSxi
-LGMpe3JldHVybiBKLnJZKGEpLlFpKGEsYixjKX0sCnFGOmZ1bmN0aW9uKGEpe3JldHVybiBKLlJFKGEp
-LmdWbChhKX0sCnRIOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gSi5SRShhKS5wayhhLGIsYyl9LAp1VTpm
-dW5jdGlvbihhKXtyZXR1cm4gSi5VNihhKS5nbDAoYSl9LAp3MjpmdW5jdGlvbihhLGIpe2lmKHR5cGVv
-ZiBiPT09Im51bWJlciIpaWYoYS5jb25zdHJ1Y3Rvcj09QXJyYXl8fHR5cGVvZiBhPT0ic3RyaW5nInx8
-SC53VihhLGFbdi5kaXNwYXRjaFByb3BlcnR5TmFtZV0pKWlmKGI+Pj4wPT09YiYmYjxhLmxlbmd0aCly
-ZXR1cm4gYVtiXQpyZXR1cm4gSi5VNihhKS5xKGEsYil9LAp6bDpmdW5jdGlvbihhLGIpe3JldHVybiBK
-LlU2KGEpLnRnKGEsYil9LAp2QjpmdW5jdGlvbiB2Qigpe30sCnlFOmZ1bmN0aW9uIHlFKCl7fSwKWUU6
-ZnVuY3Rpb24gWUUoKXt9LApNRjpmdW5jdGlvbiBNRigpe30sCmlDOmZ1bmN0aW9uIGlDKCl7fSwKa2Q6
-ZnVuY3Rpb24ga2QoKXt9LApjNTpmdW5jdGlvbiBjNSgpe30sCmpkOmZ1bmN0aW9uIGpkKGEpe3RoaXMu
-JHRpPWF9LApQbzpmdW5jdGlvbiBQbyhhKXt0aGlzLiR0aT1hfSwKbTE6ZnVuY3Rpb24gbTEoYSxiLGMp
-e3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPTAKXy5kPW51bGwKXy4kdGk9Y30sCnFJOmZ1bmN0aW9u
-IHFJKCl7fSwKYlU6ZnVuY3Rpb24gYlUoKXt9LApWQTpmdW5jdGlvbiBWQSgpe30sCkRyOmZ1bmN0aW9u
-IERyKCl7fX0sUD17Ck9qOmZ1bmN0aW9uKCl7dmFyIHQscyxyPXt9CmlmKHNlbGYuc2NoZWR1bGVJbW1l
-ZGlhdGUhPW51bGwpcmV0dXJuIFAuRVgoKQppZihzZWxmLk11dGF0aW9uT2JzZXJ2ZXIhPW51bGwmJnNl
-bGYuZG9jdW1lbnQhPW51bGwpe3Q9c2VsZi5kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJkaXYiKQpzPXNl
-bGYuZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic3BhbiIpCnIuYT1udWxsCm5ldyBzZWxmLk11dGF0aW9u
-T2JzZXJ2ZXIoSC50UihuZXcgUC50aChyKSwxKSkub2JzZXJ2ZSh0LHtjaGlsZExpc3Q6dHJ1ZX0pCnJl
-dHVybiBuZXcgUC5oYShyLHQscyl9ZWxzZSBpZihzZWxmLnNldEltbWVkaWF0ZSE9bnVsbClyZXR1cm4g
-UC55dCgpCnJldHVybiBQLnFXKCl9LApaVjpmdW5jdGlvbihhKXtzZWxmLnNjaGVkdWxlSW1tZWRpYXRl
-KEgudFIobmV3IFAuVnModS5NLmIoYSkpLDApKX0sCm9BOmZ1bmN0aW9uKGEpe3NlbGYuc2V0SW1tZWRp
-YXRlKEgudFIobmV3IFAuRnQodS5NLmIoYSkpLDApKX0sCkJ6OmZ1bmN0aW9uKGEpe3UuTS5iKGEpClAu
-UU4oMCxhKX0sClFOOmZ1bmN0aW9uKGEsYil7dmFyIHQ9bmV3IFAuVzMoKQp0LkNZKGEsYikKcmV0dXJu
-IHR9LApGWDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuaWgobmV3IFAudnMoJC5YMyxhLkMoInZzPDA+
-IikpLGEuQygiaWg8MD4iKSl9LApESTpmdW5jdGlvbihhLGIpe2EuJDIoMCxudWxsKQpiLmI9ITAKcmV0
-dXJuIGIuYX0sCmpROmZ1bmN0aW9uKGEsYil7UC5KZShhLGIpfSwKeUM6ZnVuY3Rpb24oYSxiKXtiLmFN
-KDAsYSl9LApmMzpmdW5jdGlvbihhLGIpe2IudzAoSC5SdShhKSxILnRzKGEpKX0sCkplOmZ1bmN0aW9u
-KGEsYil7dmFyIHQscyxyPW5ldyBQLldNKGIpLHE9bmV3IFAuU1goYikKaWYoYSBpbnN0YW5jZW9mIFAu
-dnMpYS5RZChyLHEsdS56KQplbHNle3Q9dS56CmlmKHUuYy5jKGEpKWEuU3EocixxLHQpCmVsc2V7cz1u
-ZXcgUC52cygkLlgzLHUuXykKcy5hPTQKcy5jPWEKcy5RZChyLG51bGwsdCl9fX0sCmx6OmZ1bmN0aW9u
-KGEpe3ZhciB0PWZ1bmN0aW9uKGIsYyl7cmV0dXJuIGZ1bmN0aW9uKGQsZSl7d2hpbGUodHJ1ZSl0cnl7
-YihkLGUpCmJyZWFrfWNhdGNoKHMpe2U9cwpkPWN9fX0oYSwxKQpyZXR1cm4gJC5YMy5MaihuZXcgUC5H
-cyh0KSx1LlAsdS5lZyx1LnopfSwKR1E6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLkZ5KGEsMSl9LApU
-aDpmdW5jdGlvbigpe3JldHVybiBDLndRfSwKWW06ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLkZ5KGEs
-Myl9LApsMDpmdW5jdGlvbihhLGIpe3JldHVybiBuZXcgUC5xNChhLGIuQygicTQ8MD4iKSl9LAprMzpm
-dW5jdGlvbihhLGIpe3ZhciB0LHMscgpiLmE9MQp0cnl7YS5TcShuZXcgUC5wVihiKSxuZXcgUC5VNyhi
-KSx1LlApfWNhdGNoKHIpe3Q9SC5SdShyKQpzPUgudHMocikKUC5yYihuZXcgUC52cihiLHQscykpfX0s
-CkE5OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCmZvcih0PXUuXztzPWEuYSxzPT09MjspYT10LmIoYS5j
-KQppZihzPj00KXtyPWIuYWgoKQpiLmE9YS5hCmIuYz1hLmMKUC5IWihiLHIpfWVsc2V7cj11LnguYihi
-LmMpCmIuYT0yCmIuYz1hCmEualEocil9fSwKSFo6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8s
-bixtLGwsayxqLGksaCxnLGYsZT1udWxsLGQ9e30sYz1kLmE9YQpmb3IodD11Lm4scz11Lngscj11LmM7
-ITA7KXtxPXt9CnA9Yy5hPT09OAppZihiPT1udWxsKXtpZihwKXtvPXQuYihjLmMpClAuTDIoZSxlLGMu
-YixvLmEsby5iKX1yZXR1cm59Zm9yKDtuPWIuYSxuIT1udWxsO2I9bil7Yi5hPW51bGwKUC5IWihkLmEs
-Yil9Yz1kLmEKbT1jLmMKcS5hPXAKcS5iPW0KbD0hcAppZihsKXtrPWIuYwprPShrJjEpIT09MHx8KGsm
-MTUpPT09OH1lbHNlIGs9ITAKaWYoayl7az1iLmIKaj1rLmIKaWYocCl7aT1jLmI9PT1qCmk9IShpfHxp
-KX1lbHNlIGk9ITEKaWYoaSl7dC5iKG0pClAuTDIoZSxlLGMuYixtLmEsbS5iKQpyZXR1cm59aD0kLlgz
-CmlmKGghPT1qKSQuWDM9agplbHNlIGg9ZQpjPWIuYwppZigoYyYxNSk9PT04KW5ldyBQLlJUKGQscSxi
-LHApLiQwKCkKZWxzZSBpZihsKXtpZigoYyYxKSE9PTApbmV3IFAucnEocSxiLG0pLiQwKCl9ZWxzZSBp
-ZigoYyYyKSE9PTApbmV3IFAuUlcoZCxxLGIpLiQwKCkKaWYoaCE9bnVsbCkkLlgzPWgKYz1xLmIKaWYo
-ci5jKGMpKXtpZihjLmE+PTQpe2c9cy5iKGsuYykKay5jPW51bGwKYj1rLk44KGcpCmsuYT1jLmEKay5j
-PWMuYwpkLmE9Ywpjb250aW51ZX1lbHNlIFAuQTkoYyxrKQpyZXR1cm59fWY9Yi5iCmc9cy5iKGYuYykK
-Zi5jPW51bGwKYj1mLk44KGcpCmM9cS5hCmw9cS5iCmlmKCFjKXtmLiR0aS5kLmIobCkKZi5hPTQKZi5j
-PWx9ZWxzZXt0LmIobCkKZi5hPTgKZi5jPWx9ZC5hPWYKYz1mfX0sClZIOmZ1bmN0aW9uKGEsYil7dmFy
-IHQKaWYodS5FLmMoYSkpcmV0dXJuIGIuTGooYSx1LnosdS5LLHUubCkKdD11LncKaWYodC5jKGEpKXJl
-dHVybiB0LmIoYSkKdGhyb3cgSC5iKFAuTDMoYSwib25FcnJvciIsIkVycm9yIGhhbmRsZXIgbXVzdCBh
-Y2NlcHQgb25lIE9iamVjdCBvciBvbmUgT2JqZWN0IGFuZCBhIFN0YWNrVHJhY2UgYXMgYXJndW1lbnRz
-LCBhbmQgcmV0dXJuIGEgYSB2YWxpZCByZXN1bHQiKSl9LApwdTpmdW5jdGlvbigpe3ZhciB0LHMKZm9y
-KDt0PSQuUzYsdCE9bnVsbDspeyQubWc9bnVsbApzPXQuYgokLlM2PXMKaWYocz09bnVsbCkkLms4PW51
-bGwKdC5hLiQwKCl9fSwKZU46ZnVuY3Rpb24oKXskLlVEPSEwCnRyeXtQLnB1KCl9ZmluYWxseXskLm1n
-PW51bGwKJC5VRD0hMQppZigkLlM2IT1udWxsKSQudXQoKS4kMShQLlVJKCkpfX0sCmVXOmZ1bmN0aW9u
-KGEpe3ZhciB0PW5ldyBQLk9NKGEpCmlmKCQuUzY9PW51bGwpeyQuUzY9JC5rOD10CmlmKCEkLlVEKSQu
-dXQoKS4kMShQLlVJKCkpfWVsc2UgJC5rOD0kLms4LmI9dH0sCnJSOmZ1bmN0aW9uKGEpe3ZhciB0LHMs
-cj0kLlM2CmlmKHI9PW51bGwpe1AuZVcoYSkKJC5tZz0kLms4CnJldHVybn10PW5ldyBQLk9NKGEpCnM9
-JC5tZwppZihzPT1udWxsKXt0LmI9cgokLlM2PSQubWc9dH1lbHNle3QuYj1zLmIKJC5tZz1zLmI9dApp
-Zih0LmI9PW51bGwpJC5rOD10fX0sCnJiOmZ1bmN0aW9uKGEpe3ZhciB0PW51bGwscz0kLlgzCmlmKEMu
-TlU9PT1zKXtQLlRrKHQsdCxDLk5VLGEpCnJldHVybn1QLlRrKHQsdCxzLHUuTS5iKHMuR1koYSkpKX0s
-ClF3OmZ1bmN0aW9uKGEsYil7aWYoYT09bnVsbClILnZoKFAuRWUoInN0cmVhbSIpKQpyZXR1cm4gbmV3
-IFAueEkoYi5DKCJ4STwwPiIpKX0sClRsOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBQLkN3KGEsYil9
-LApMMjpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0PXt9CnQuYT1kClAuclIobmV3IFAucEsodCxlKSl9
-LApUODpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0LHM9JC5YMwppZihzPT09YylyZXR1cm4gZC4kMCgp
-CiQuWDM9Ywp0PXMKdHJ5e3M9ZC4kMCgpCnJldHVybiBzfWZpbmFsbHl7JC5YMz10fX0sCnl2OmZ1bmN0
-aW9uKGEsYixjLGQsZSxmLGcpe3ZhciB0LHM9JC5YMwppZihzPT09YylyZXR1cm4gZC4kMShlKQokLlgz
-PWMKdD1zCnRyeXtzPWQuJDEoZSkKcmV0dXJuIHN9ZmluYWxseXskLlgzPXR9fSwKUXg6ZnVuY3Rpb24o
-YSxiLGMsZCxlLGYsZyxoLGkpe3ZhciB0LHM9JC5YMwppZihzPT09YylyZXR1cm4gZC4kMihlLGYpCiQu
-WDM9Ywp0PXMKdHJ5e3M9ZC4kMihlLGYpCnJldHVybiBzfWZpbmFsbHl7JC5YMz10fX0sClRrOmZ1bmN0
-aW9uKGEsYixjLGQpe3ZhciB0CnUuTS5iKGQpCnQ9Qy5OVSE9PWMKaWYodClkPSEoIXR8fCExKT9jLkdZ
-KGQpOmMuUlQoZCx1LkgpClAuZVcoZCl9LAp0aDpmdW5jdGlvbiB0aChhKXt0aGlzLmE9YX0sCmhhOmZ1
-bmN0aW9uIGhhKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sClZzOmZ1bmN0aW9uIFZz
-KGEpe3RoaXMuYT1hfSwKRnQ6ZnVuY3Rpb24gRnQoYSl7dGhpcy5hPWF9LApXMzpmdW5jdGlvbiBXMygp
-e30sCnlIOmZ1bmN0aW9uIHlIKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAppaDpmdW5jdGlvbiBpaChh
-LGIpe3RoaXMuYT1hCnRoaXMuYj0hMQp0aGlzLiR0aT1ifSwKV006ZnVuY3Rpb24gV00oYSl7dGhpcy5h
-PWF9LApTWDpmdW5jdGlvbiBTWChhKXt0aGlzLmE9YX0sCkdzOmZ1bmN0aW9uIEdzKGEpe3RoaXMuYT1h
-fSwKRnk6ZnVuY3Rpb24gRnkoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkdWOmZ1bmN0aW9uIEdWKGEs
-Yil7dmFyIF89dGhpcwpfLmE9YQpfLmQ9Xy5jPV8uYj1udWxsCl8uJHRpPWJ9LApxNDpmdW5jdGlvbiBx
-NChhLGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApiODpmdW5jdGlvbiBiOCgpe30sClBmOmZ1bmN0aW9u
-IFBmKCl7fSwKWmY6ZnVuY3Rpb24gWmYoYSxiKXt0aGlzLmE9YQp0aGlzLiR0aT1ifSwKRmU6ZnVuY3Rp
-b24gRmUoYSxiLGMsZCxlKXt2YXIgXz10aGlzCl8uYT1udWxsCl8uYj1hCl8uYz1iCl8uZD1jCl8uZT1k
-Cl8uJHRpPWV9LAp2czpmdW5jdGlvbiB2cyhhLGIpe3ZhciBfPXRoaXMKXy5hPTAKXy5iPWEKXy5jPW51
-bGwKXy4kdGk9Yn0sCmRhOmZ1bmN0aW9uIGRhKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApvUTpmdW5j
-dGlvbiBvUShhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKcFY6ZnVuY3Rpb24gcFYoYSl7dGhpcy5hPWF9
-LApVNzpmdW5jdGlvbiBVNyhhKXt0aGlzLmE9YX0sCnZyOmZ1bmN0aW9uIHZyKGEsYixjKXt0aGlzLmE9
-YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCnJIOmZ1bmN0aW9uIHJIKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9
-LApLRjpmdW5jdGlvbiBLRihhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKWkw6ZnVuY3Rpb24gWkwoYSxi
-LGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKUlQ6ZnVuY3Rpb24gUlQoYSxiLGMsZCl7dmFy
-IF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCmpaOmZ1bmN0aW9uIGpaKGEpe3RoaXMuYT1h
-fSwKcnE6ZnVuY3Rpb24gcnEoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKUlc6ZnVu
-Y3Rpb24gUlcoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKT006ZnVuY3Rpb24gT00o
-YSl7dGhpcy5hPWEKdGhpcy5iPW51bGx9LApxaDpmdW5jdGlvbiBxaCgpe30sCkI1OmZ1bmN0aW9uIEI1
-KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAp1TzpmdW5jdGlvbiB1TyhhLGIpe3RoaXMuYT1hCnRoaXMu
-Yj1ifSwKTU86ZnVuY3Rpb24gTU8oKXt9LAprVDpmdW5jdGlvbiBrVCgpe30sCnhJOmZ1bmN0aW9uIHhJ
-KGEpe3RoaXMuJHRpPWF9LApDdzpmdW5jdGlvbiBDdyhhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKbTA6
-ZnVuY3Rpb24gbTAoKXt9LApwSzpmdW5jdGlvbiBwSyhhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKSmk6
-ZnVuY3Rpb24gSmkoKXt9LApoajpmdW5jdGlvbiBoaihhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhp
-cy5jPWN9LApWcDpmdW5jdGlvbiBWcChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKT1I6ZnVuY3Rpb24g
-T1IoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKRUY6ZnVuY3Rpb24oYSxiLGMpe3Jl
-dHVybiBiLkMoIkA8MD4iKS5LcShjKS5DKCJGbzwxLDI+IikuYihILkI3KGEsbmV3IEguTjUoYi5DKCJA
-PDA+IikuS3EoYykuQygiTjU8MSwyPiIpKSkpfSwKRmw6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IEgu
-TjUoYS5DKCJAPDA+IikuS3EoYikuQygiTjU8MSwyPiIpKX0sCkxzOmZ1bmN0aW9uKGEpe3JldHVybiBu
-ZXcgUC5iNihhLkMoImI2PDA+IikpfSwKVDI6ZnVuY3Rpb24oKXt2YXIgdD1PYmplY3QuY3JlYXRlKG51
-bGwpCnRbIjxub24taWRlbnRpZmllci1rZXk+Il09dApkZWxldGUgdFsiPG5vbi1pZGVudGlmaWVyLWtl
-eT4iXQpyZXR1cm4gdH0sCnJqOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1uZXcgUC5sbShhLGIsYy5DKCJs
-bTwwPiIpKQp0LmM9YS5lCnJldHVybiB0fSwKRVA6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKaWYoUC5o
-QihhKSl7aWYoYj09PSIoIiYmYz09PSIpIilyZXR1cm4iKC4uLikiCnJldHVybiBiKyIuLi4iK2N9dD1I
-LlZNKFtdLHUucykKQy5ObS5pKCQueGcsYSkKdHJ5e1AuVnIoYSx0KX1maW5hbGx5e2lmKDA+PSQueGcu
-bGVuZ3RoKXJldHVybiBILk9IKCQueGcsLTEpCiQueGcucG9wKCl9cz1QLnZnKGIsdS5SLmIodCksIiwg
-IikrYwpyZXR1cm4gcy5jaGFyQ29kZUF0KDApPT0wP3M6c30sCldFOmZ1bmN0aW9uKGEsYixjKXt2YXIg
-dCxzCmlmKFAuaEIoYSkpcmV0dXJuIGIrIi4uLiIrYwp0PW5ldyBQLlJuKGIpCkMuTm0uaSgkLnhnLGEp
-CnRyeXtzPXQKcy5hPVAudmcocy5hLGEsIiwgIil9ZmluYWxseXtpZigwPj0kLnhnLmxlbmd0aClyZXR1
-cm4gSC5PSCgkLnhnLC0xKQokLnhnLnBvcCgpfXQuYSs9YwpzPXQuYQpyZXR1cm4gcy5jaGFyQ29kZUF0
-KDApPT0wP3M6c30sCmhCOmZ1bmN0aW9uKGEpe3ZhciB0LHMKZm9yKHQ9JC54Zy5sZW5ndGgscz0wO3M8
-dDsrK3MpaWYoYT09PSQueGdbc10pcmV0dXJuITAKcmV0dXJuITF9LApWcjpmdW5jdGlvbihhLGIpe3Zh
-ciB0LHMscixxLHAsbyxuLG09YS5na3ooYSksbD0wLGs9MAp3aGlsZSghMCl7aWYoIShsPDgwfHxrPDMp
-KWJyZWFrCmlmKCFtLkYoKSlyZXR1cm4KdD1ILmQobS5nbCgpKQpDLk5tLmkoYix0KQpsKz10Lmxlbmd0
-aCsyOysra31pZighbS5GKCkpe2lmKGs8PTUpcmV0dXJuCmlmKDA+PWIubGVuZ3RoKXJldHVybiBILk9I
-KGIsLTEpCnM9Yi5wb3AoKQppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5PSChiLC0xKQpyPWIucG9wKCl9
-ZWxzZXtxPW0uZ2woKTsrK2sKaWYoIW0uRigpKXtpZihrPD00KXtDLk5tLmkoYixILmQocSkpCnJldHVy
-bn1zPUguZChxKQppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5PSChiLC0xKQpyPWIucG9wKCkKbCs9cy5s
-ZW5ndGgrMn1lbHNle3A9bS5nbCgpOysrawpmb3IoO20uRigpO3E9cCxwPW8pe289bS5nbCgpOysrawpp
-ZihrPjEwMCl7d2hpbGUoITApe2lmKCEobD43NSYmaz4zKSlicmVhawppZigwPj1iLmxlbmd0aClyZXR1
-cm4gSC5PSChiLC0xKQpsLT1iLnBvcCgpLmxlbmd0aCsyOy0ta31DLk5tLmkoYiwiLi4uIikKcmV0dXJu
-fX1yPUguZChxKQpzPUguZChwKQpsKz1zLmxlbmd0aCtyLmxlbmd0aCs0fX1pZihrPmIubGVuZ3RoKzIp
-e2wrPTUKbj0iLi4uIn1lbHNlIG49bnVsbAp3aGlsZSghMCl7aWYoIShsPjgwJiZiLmxlbmd0aD4zKSli
-cmVhawppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5PSChiLC0xKQpsLT1iLnBvcCgpLmxlbmd0aCsyCmlm
-KG49PW51bGwpe2wrPTUKbj0iLi4uIn19aWYobiE9bnVsbClDLk5tLmkoYixuKQpDLk5tLmkoYixyKQpD
-Lk5tLmkoYixzKX0sCnRNOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyPVAuTHMoYikKZm9yKHQ9YS5sZW5n
-dGgscz0wO3M8YS5sZW5ndGg7YS5sZW5ndGg9PT10fHwoMCxILmxrKShhKSwrK3Mpci5pKDAsYi5iKGFb
-c10pKQpyZXR1cm4gcn0sCm5POmZ1bmN0aW9uKGEpe3ZhciB0LHM9e30KaWYoUC5oQihhKSlyZXR1cm4i
-ey4uLn0iCnQ9bmV3IFAuUm4oIiIpCnRyeXtDLk5tLmkoJC54ZyxhKQp0LmErPSJ7IgpzLmE9ITAKYS5L
-KDAsbmV3IFAucmEocyx0KSkKdC5hKz0ifSJ9ZmluYWxseXtpZigwPj0kLnhnLmxlbmd0aClyZXR1cm4g
-SC5PSCgkLnhnLC0xKQokLnhnLnBvcCgpfXM9dC5hCnJldHVybiBzLmNoYXJDb2RlQXQoMCk9PTA/czpz
-fSwKYjY6ZnVuY3Rpb24gYjYoYSl7dmFyIF89dGhpcwpfLmE9MApfLmY9Xy5lPV8uZD1fLmM9Xy5iPW51
-bGwKXy5yPTAKXy4kdGk9YX0sCmJuOmZ1bmN0aW9uIGJuKGEpe3RoaXMuYT1hCnRoaXMuYz10aGlzLmI9
-bnVsbH0sCmxtOmZ1bmN0aW9uIGxtKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uZD1fLmM9
-bnVsbApfLiR0aT1jfSwKbVc6ZnVuY3Rpb24gbVcoKXt9LAp1eTpmdW5jdGlvbiB1eSgpe30sCmxEOmZ1
-bmN0aW9uIGxEKCl7fSwKaWw6ZnVuY3Rpb24gaWwoKXt9LApyYTpmdW5jdGlvbiByYShhLGIpe3RoaXMu
-YT1hCnRoaXMuYj1ifSwKWWs6ZnVuY3Rpb24gWWsoKXt9LAp5UTpmdW5jdGlvbiB5UShhKXt0aGlzLmE9
-YX0sCktQOmZ1bmN0aW9uIEtQKCl7fSwKUG46ZnVuY3Rpb24gUG4oKXt9LApHajpmdW5jdGlvbiBHaihh
-LGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApsZjpmdW5jdGlvbiBsZigpe30sClZqOmZ1bmN0aW9uIFZq
-KCl7fSwKWHY6ZnVuY3Rpb24gWHYoKXt9LApuWTpmdW5jdGlvbiBuWSgpe30sClRDOmZ1bmN0aW9uIFRD
-KCl7fSwKUlU6ZnVuY3Rpb24gUlUoKXt9LApCUzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxCmlmKHR5
-cGVvZiBhIT0ic3RyaW5nIil0aHJvdyBILmIoSC50TChhKSkKdD1udWxsCnRyeXt0PUpTT04ucGFyc2Uo
-YSl9Y2F0Y2gocil7cz1ILlJ1KHIpCnE9UC5ycihTdHJpbmcocyksbnVsbCxudWxsKQp0aHJvdyBILmIo
-cSl9cT1QLlFlKHQpCnJldHVybiBxfSwKUWU6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT09bnVsbClyZXR1
-cm4gbnVsbAppZih0eXBlb2YgYSE9Im9iamVjdCIpcmV0dXJuIGEKaWYoT2JqZWN0LmdldFByb3RvdHlw
-ZU9mKGEpIT09QXJyYXkucHJvdG90eXBlKXJldHVybiBuZXcgUC51dyhhLE9iamVjdC5jcmVhdGUobnVs
-bCkpCmZvcih0PTA7dDxhLmxlbmd0aDsrK3QpYVt0XT1QLlFlKGFbdF0pCnJldHVybiBhfSwKa3k6ZnVu
-Y3Rpb24oYSxiLGMsZCl7aWYoYiBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpcmV0dXJuIFAuUlAoITEsYixj
-LGQpCnJldHVybiBudWxsfSwKUlA6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyPSQucmYoKQppZihy
-PT1udWxsKXJldHVybiBudWxsCnQ9MD09PWMKaWYodCYmITApcmV0dXJuIFAuT1EocixiKQpzPWIubGVu
-Z3RoCmQ9UC5qQihjLGQscykKaWYodCYmZD09PXMpcmV0dXJuIFAuT1EocixiKQpyZXR1cm4gUC5PUShy
-LGIuc3ViYXJyYXkoYyxkKSl9LApPUTpmdW5jdGlvbihhLGIpe2lmKFAuQmUoYikpcmV0dXJuIG51bGwK
-cmV0dXJuIFAuSmgoYSxiKX0sCkpoOmZ1bmN0aW9uKGEsYil7dmFyIHQscwp0cnl7dD1hLmRlY29kZShi
-KQpyZXR1cm4gdH1jYXRjaChzKXtILlJ1KHMpfXJldHVybiBudWxsfSwKQmU6ZnVuY3Rpb24oYSl7dmFy
-IHQscz1hLmxlbmd0aC0yCmZvcih0PTA7dDxzOysrdClpZihhW3RdPT09MjM3KWlmKChhW3QrMV0mMjI0
-KT09PTE2MClyZXR1cm4hMApyZXR1cm4hMX0sCldJOmZ1bmN0aW9uKCl7dmFyIHQscwp0cnl7dD1uZXcg
-VGV4dERlY29kZXIoInV0Zi04Iix7ZmF0YWw6dHJ1ZX0pCnJldHVybiB0fWNhdGNoKHMpe0guUnUocyl9
-cmV0dXJuIG51bGx9LApjUDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyCmZvcih0PUouVTYoYSkscz1i
-O3M8YzsrK3Mpe3I9dC5xKGEscykKaWYodHlwZW9mIHIhPT0ibnVtYmVyIilyZXR1cm4gci56TSgpCmlm
-KChyJjEyNykhPT1yKXJldHVybiBzLWJ9cmV0dXJuIGMtYn0sCnhNOmZ1bmN0aW9uKGEsYixjLGQsZSxm
-KXtpZihDLmpuLnpZKGYsNCkhPT0wKXRocm93IEguYihQLnJyKCJJbnZhbGlkIGJhc2U2NCBwYWRkaW5n
-LCBwYWRkZWQgbGVuZ3RoIG11c3QgYmUgbXVsdGlwbGUgb2YgZm91ciwgaXMgIitmLGEsYykpCmlmKGQr
-ZSE9PWYpdGhyb3cgSC5iKFAucnIoIkludmFsaWQgYmFzZTY0IHBhZGRpbmcsICc9JyBub3QgYXQgdGhl
-IGVuZCIsYSxiKSkKaWYoZT4yKXRocm93IEguYihQLnJyKCJJbnZhbGlkIGJhc2U2NCBwYWRkaW5nLCBt
-b3JlIHRoYW4gdHdvICc9JyBjaGFyYWN0ZXJzIixhLGIpKX0sCkd5OmZ1bmN0aW9uKGEsYixjKXtyZXR1
-cm4gbmV3IFAuVWQoYSxiKX0sCk5DOmZ1bmN0aW9uKGEpe3JldHVybiBhLkx0KCl9LAp1WDpmdW5jdGlv
-bihhLGIsYyl7dmFyIHQscz1uZXcgUC5SbigiIikscj1uZXcgUC50dShzLFtdLFAuQ3koKSkKci5pVShh
-KQp0PXMuYQpyZXR1cm4gdC5jaGFyQ29kZUF0KDApPT0wP3Q6dH0sCnV3OmZ1bmN0aW9uIHV3KGEsYil7
-dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPW51bGx9LAppODpmdW5jdGlvbiBpOChhKXt0aGlzLmE9YX0s
-CkNWOmZ1bmN0aW9uIENWKCl7fSwKVTg6ZnVuY3Rpb24gVTgoKXt9LApVazpmdW5jdGlvbiBVaygpe30s
-CndJOmZ1bmN0aW9uIHdJKCl7fSwKWmk6ZnVuY3Rpb24gWmkoKXt9LApVZDpmdW5jdGlvbiBVZChhLGIp
-e3RoaXMuYT1hCnRoaXMuYj1ifSwKSzg6ZnVuY3Rpb24gSzgoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0s
-CmJ5OmZ1bmN0aW9uIGJ5KCl7fSwKb2o6ZnVuY3Rpb24gb2ooYSl7dGhpcy5iPWF9LApNeDpmdW5jdGlv
-biBNeChhKXt0aGlzLmE9YX0sClNoOmZ1bmN0aW9uIFNoKCl7fSwKdGk6ZnVuY3Rpb24gdGkoYSxiKXt0
-aGlzLmE9YQp0aGlzLmI9Yn0sCnR1OmZ1bmN0aW9uIHR1KGEsYixjKXt0aGlzLmM9YQp0aGlzLmE9Ygp0
-aGlzLmI9Y30sCnU1OmZ1bmN0aW9uIHU1KCl7fSwKRTM6ZnVuY3Rpb24gRTMoKXt9LApSdzpmdW5jdGlv
-biBSdyhhKXt0aGlzLmI9MAp0aGlzLmM9YX0sCkdZOmZ1bmN0aW9uIEdZKGEpe3RoaXMuYT1hfSwKYno6
-ZnVuY3Rpb24gYnooYSxiKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz0hMApfLmY9Xy5lPV8uZD0w
-fSwKUUE6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PUguSHAoYSxjKQppZih0IT1udWxsKXJldHVybiB0Cmlm
-KGIhPW51bGwpcmV0dXJuIGIuJDEoYSkKdGhyb3cgSC5iKFAucnIoYSxudWxsLG51bGwpKX0sCkY6ZnVu
-Y3Rpb24oYSl7aWYoYSBpbnN0YW5jZW9mIEguVHApcmV0dXJuIGEudygwKQpyZXR1cm4iSW5zdGFuY2Ug
-b2YgJyIrSC5kKEguTShhKSkrIicifSwKTzg6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscwppZihjKXQ9
-SC5WTShuZXcgQXJyYXkoYSksZC5DKCJqZDwwPiIpKQplbHNlIHQ9Si5RaShhLGQpCmlmKGEhPT0wJiYh
-MClmb3Iocz0wO3M8dC5sZW5ndGg7KytzKUMuTm0uWSh0LHMsYikKcmV0dXJuIHR9LApDSDpmdW5jdGlv
-bihhLGIsYyl7dmFyIHQscz1ILlZNKFtdLGMuQygiamQ8MD4iKSkKZm9yKHQ9Si5JVChhKTt0LkYoKTsp
-Qy5ObS5pKHMsYy5iKHQuZ2woKSkpCmlmKGIpcmV0dXJuIHMKcmV0dXJuIGMuQygiek08MD4iKS5iKEou
-RXAocykpfSwKQUY6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYi5DKCJ6TTwwPiIpLmIoSi56QyhQLkNIKGEs
-ITEsYikpKX0sCkhNOmZ1bmN0aW9uKGEsYixjKXt2YXIgdAppZihBcnJheS5pc0FycmF5KGEpKXt1LnQu
-YihhKQp0PWEubGVuZ3RoCmM9UC5qQihiLGMsdCkKcmV0dXJuIEguZVQoYj4wfHxjPHQ/Qy5ObS5ENihh
-LGIsYyk6YSl9aWYodS5ibS5jKGEpKXJldHVybiBILmZ3KGEsYixQLmpCKGIsYyxhLmxlbmd0aCkpCnJl
-dHVybiBQLmJ3KGEsYixjKX0sCk9vOmZ1bmN0aW9uKGEpe3JldHVybiBILkx3KGEpfSwKYnc6ZnVuY3Rp
-b24oYSxiLGMpe3ZhciB0LHMscixxLHA9bnVsbAppZihiPDApdGhyb3cgSC5iKFAuVEUoYiwwLEouSG0o
-YSkscCxwKSkKdD1jPT1udWxsCmlmKCF0JiZjPGIpdGhyb3cgSC5iKFAuVEUoYyxiLEouSG0oYSkscCxw
-KSkKcz1KLklUKGEpCmZvcihyPTA7cjxiOysrcilpZighcy5GKCkpdGhyb3cgSC5iKFAuVEUoYiwwLHIs
-cCxwKSkKcT1bXQppZih0KWZvcig7cy5GKCk7KXEucHVzaChzLmdsKCkpCmVsc2UgZm9yKHI9YjtyPGM7
-KytyKXtpZighcy5GKCkpdGhyb3cgSC5iKFAuVEUoYyxiLHIscCxwKSkKcS5wdXNoKHMuZ2woKSl9cmV0
-dXJuIEguZVQocSl9LApudTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEguVlIoYSxILnY0KGEsITEsITAs
-ITEsITEsITEpKX0sCnZnOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1KLklUKGIpCmlmKCF0LkYoKSlyZXR1
-cm4gYQppZihjLmxlbmd0aD09PTApe2RvIGErPUguZCh0LmdsKCkpCndoaWxlKHQuRigpKX1lbHNle2Er
-PUguZCh0LmdsKCkpCmZvcig7dC5GKCk7KWE9YStjK0guZCh0LmdsKCkpfXJldHVybiBhfSwKbHI6ZnVu
-Y3Rpb24oYSxiLGMsZCl7cmV0dXJuIG5ldyBQLm1wKGEsYixjLGQpfSwKdW86ZnVuY3Rpb24oKXt2YXIg
-dD1ILk0wKCkKaWYodCE9bnVsbClyZXR1cm4gUC5oSyh0KQp0aHJvdyBILmIoUC5MNCgiJ1VyaS5iYXNl
-JyBpcyBub3Qgc3VwcG9ydGVkIikpfSwKZVA6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyLHEscCxv
-LG49IjAxMjM0NTY3ODlBQkNERUYiCmlmKGM9PT1DLnhNKXt0PSQuejQoKS5iCmlmKHR5cGVvZiBiIT0i
-c3RyaW5nIilILnZoKEgudEwoYikpCnQ9dC50ZXN0KGIpfWVsc2UgdD0hMQppZih0KXJldHVybiBiCkgu
-TGgoYykuQygiVWsuUyIpLmIoYikKcz1jLmdaRSgpLldKKGIpCmZvcih0PXMubGVuZ3RoLHI9MCxxPSIi
-O3I8dDsrK3Ipe3A9c1tyXQppZihwPDEyOCl7bz1wPj4+NAppZihvPj04KXJldHVybiBILk9IKGEsbykK
-bz0oYVtvXSYxPDwocCYxNSkpIT09MH1lbHNlIG89ITEKaWYobylxKz1ILkx3KHApCmVsc2UgcT1kJiZw
-PT09MzI/cSsiKyI6cSsiJSIrbltwPj4+NCYxNV0rbltwJjE1XX1yZXR1cm4gcS5jaGFyQ29kZUF0KDAp
-PT0wP3E6cX0sCkdxOmZ1bmN0aW9uKGEpe3ZhciB0PU1hdGguYWJzKGEpLHM9YTwwPyItIjoiIgppZih0
-Pj0xMDAwKXJldHVybiIiK2EKaWYodD49MTAwKXJldHVybiBzKyIwIit0CmlmKHQ+PTEwKXJldHVybiBz
-KyIwMCIrdApyZXR1cm4gcysiMDAwIit0fSwKVng6ZnVuY3Rpb24oYSl7aWYoYT49MTAwKXJldHVybiIi
-K2EKaWYoYT49MTApcmV0dXJuIjAiK2EKcmV0dXJuIjAwIithfSwKaDA6ZnVuY3Rpb24oYSl7aWYoYT49
-MTApcmV0dXJuIiIrYQpyZXR1cm4iMCIrYX0sCnA6ZnVuY3Rpb24oYSl7aWYodHlwZW9mIGE9PSJudW1i
-ZXIifHxILmwoYSl8fG51bGw9PWEpcmV0dXJuIEouaihhKQppZih0eXBlb2YgYT09InN0cmluZyIpcmV0
-dXJuIEpTT04uc3RyaW5naWZ5KGEpCnJldHVybiBQLkYoYSl9LApoVjpmdW5jdGlvbihhKXtyZXR1cm4g
-bmV3IFAuQzYoYSl9LAp4WTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAudSghMSxudWxsLG51bGwsYSl9
-LApMMzpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG5ldyBQLnUoITAsYSxiLGMpfSwKRWU6ZnVuY3Rpb24o
-YSl7cmV0dXJuIG5ldyBQLnUoITEsbnVsbCxhLCJNdXN0IG5vdCBiZSBudWxsIil9LAp4OmZ1bmN0aW9u
-KGEsYil7cmV0dXJuIG5ldyBQLmJKKG51bGwsbnVsbCwhMCxhLGIsIlZhbHVlIG5vdCBpbiByYW5nZSIp
-fSwKVEU6ZnVuY3Rpb24oYSxiLGMsZCxlKXtyZXR1cm4gbmV3IFAuYkooYixjLCEwLGEsZCwiSW52YWxp
-ZCB2YWx1ZSIpfSwKd0E6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYTxifHxhPmMpdGhyb3cgSC5iKFAuVEUo
-YSxiLGMsZCxudWxsKSl9LApqQjpmdW5jdGlvbihhLGIsYyl7aWYoMD5hfHxhPmMpdGhyb3cgSC5iKFAu
-VEUoYSwwLGMsInN0YXJ0IixudWxsKSkKaWYoYiE9bnVsbCl7aWYoYT5ifHxiPmMpdGhyb3cgSC5iKFAu
-VEUoYixhLGMsImVuZCIsbnVsbCkpCnJldHVybiBifXJldHVybiBjfSwKazE6ZnVuY3Rpb24oYSxiKXtp
-Zih0eXBlb2YgYSE9PSJudW1iZXIiKXJldHVybiBhLkooKQppZihhPDApdGhyb3cgSC5iKFAuVEUoYSww
-LG51bGwsYixudWxsKSl9LApDZjpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0PUguU2MoZT09bnVsbD9K
-LkhtKGIpOmUpCnJldHVybiBuZXcgUC5lWSh0LCEwLGEsYywiSW5kZXggb3V0IG9mIHJhbmdlIil9LApM
-NDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAudWIoYSl9LApTWTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3
-IFAuZHMoYSl9LApQVjpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAubGooYSl9LAphNDpmdW5jdGlvbihh
-KXtyZXR1cm4gbmV3IFAuVVYoYSl9LApycjpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG5ldyBQLmFFKGEs
-YixjKX0sCmRIOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPUguVk0oW10sYy5DKCJqZDwwPiIpKQpDLk5t
-LnNBKHMsYSkKZm9yKHQ9MDt0PGE7Kyt0KUMuTm0uWShzLHQsYi4kMSh0KSkKcmV0dXJuIHN9LApoSzpm
-dW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZT1udWxsLGQ9YS5sZW5n
-dGgKaWYoZD49NSl7dD0oKEouUXooYSw0KV41OCkqM3xDLnhCLlcoYSwwKV4xMDB8Qy54Qi5XKGEsMSle
-OTd8Qy54Qi5XKGEsMileMTE2fEMueEIuVyhhLDMpXjk3KT4+PjAKaWYodD09PTApcmV0dXJuIFAuS0Qo
-ZDxkP0MueEIuTmooYSwwLGQpOmEsNSxlKS5nbFIoKQplbHNlIGlmKHQ9PT0zMilyZXR1cm4gUC5LRChD
-LnhCLk5qKGEsNSxkKSwwLGUpLmdsUigpfXM9bmV3IEFycmF5KDgpCnMuZml4ZWQkbGVuZ3RoPUFycmF5
-CnI9SC5WTShzLHUudCkKQy5ObS5ZKHIsMCwwKQpDLk5tLlkociwxLC0xKQpDLk5tLlkociwyLC0xKQpD
-Lk5tLlkociw3LC0xKQpDLk5tLlkociwzLDApCkMuTm0uWShyLDQsMCkKQy5ObS5ZKHIsNSxkKQpDLk5t
-Llkociw2LGQpCmlmKFAuVUIoYSwwLGQsMCxyKT49MTQpQy5ObS5ZKHIsNyxkKQpxPXJbMV0KaWYodHlw
-ZW9mIHEhPT0ibnVtYmVyIilyZXR1cm4gcS50QigpCmlmKHE+PTApaWYoUC5VQihhLDAscSwyMCxyKT09
-PTIwKXJbN109cQpzPXJbMl0KaWYodHlwZW9mIHMhPT0ibnVtYmVyIilyZXR1cm4gcy5oKCkKcD1zKzEK
-bz1yWzNdCm49cls0XQptPXJbNV0KbD1yWzZdCmlmKHR5cGVvZiBsIT09Im51bWJlciIpcmV0dXJuIGwu
-SigpCmlmKHR5cGVvZiBtIT09Im51bWJlciIpcmV0dXJuIEgucFkobSkKaWYobDxtKW09bAppZih0eXBl
-b2YgbiE9PSJudW1iZXIiKXJldHVybiBuLkooKQppZihuPHApbj1tCmVsc2UgaWYobjw9cSluPXErMQpp
-Zih0eXBlb2YgbyE9PSJudW1iZXIiKXJldHVybiBvLkooKQppZihvPHApbz1uCnM9cls3XQppZih0eXBl
-b2YgcyE9PSJudW1iZXIiKXJldHVybiBzLkooKQprPXM8MAppZihrKWlmKHA+cSszKXtqPWUKaz0hMX1l
-bHNle3M9bz4wCmlmKHMmJm8rMT09PW4pe2o9ZQprPSExfWVsc2V7aWYoIShtPGQmJm09PT1uKzImJkou
-cTAoYSwiLi4iLG4pKSlpPW0+bisyJiZKLnEwKGEsIi8uLiIsbS0zKQplbHNlIGk9ITAKaWYoaSl7aj1l
-Cms9ITF9ZWxzZXtpZihxPT09NClpZihKLnEwKGEsImZpbGUiLDApKXtpZihwPD0wKXtpZighQy54Qi5R
-aShhLCIvIixuKSl7aD0iZmlsZTovLy8iCnQ9M31lbHNle2g9ImZpbGU6Ly8iCnQ9Mn1hPWgrQy54Qi5O
-aihhLG4sZCkKcS09MApzPXQtMAptKz1zCmwrPXMKZD1hLmxlbmd0aApwPTcKbz03Cm49N31lbHNlIGlm
-KG49PT1tKXtnPW0rMTsrK2wKYT1DLnhCLmk3KGEsbixtLCIvIik7KytkCm09Z31qPSJmaWxlIn1lbHNl
-IGlmKEMueEIuUWkoYSwiaHR0cCIsMCkpe2lmKHMmJm8rMz09PW4mJkMueEIuUWkoYSwiODAiLG8rMSkp
-e2Y9bi0zCm0tPTMKbC09MwphPUMueEIuaTcoYSxvLG4sIiIpCmQtPTMKbj1mfWo9Imh0dHAifWVsc2Ug
-aj1lCmVsc2UgaWYocT09PTUmJkoucTAoYSwiaHR0cHMiLDApKXtpZihzJiZvKzQ9PT1uJiZKLnEwKGEs
-IjQ0MyIsbysxKSl7Zj1uLTQKbS09NApsLT00CmE9Si5kZyhhLG8sbiwiIikKZC09MwpuPWZ9aj0iaHR0
-cHMifWVsc2Ugaj1lCms9ITB9fX1lbHNlIGo9ZQppZihrKXtzPWEubGVuZ3RoCmlmKGQ8cyl7YT1KLmxk
-KGEsMCxkKQpxLT0wCnAtPTAKby09MApuLT0wCm0tPTAKbC09MH1yZXR1cm4gbmV3IFAuVWYoYSxxLHAs
-byxuLG0sbCxqKX1yZXR1cm4gUC5qdihhLDAsZCxxLHAsbyxuLG0sbCxqKX0sCk10OmZ1bmN0aW9uKGEp
-e0gueShhKQpyZXR1cm4gUC5rdShhLDAsYS5sZW5ndGgsQy54TSwhMSl9LApXWDpmdW5jdGlvbihhKXt2
-YXIgdD11Lk4KcmV0dXJuIEMuTm0uTjAoSC5WTShhLnNwbGl0KCImIiksdS5zKSxQLkZsKHQsdCksbmV3
-IFAubjEoQy54TSksdS5mKX0sCkhoOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbixtPW51
-bGwsbD0iSVB2NCBhZGRyZXNzIHNob3VsZCBjb250YWluIGV4YWN0bHkgNCBwYXJ0cyIsaz0iZWFjaCBw
-YXJ0IG11c3QgYmUgaW4gdGhlIHJhbmdlIDAuLjI1NSIsaj1uZXcgUC5jUyhhKSxpPW5ldyBVaW50OEFy
-cmF5KDQpCmZvcih0PWkubGVuZ3RoLHM9YixyPXMscT0wO3M8YzsrK3Mpe3A9Qy54Qi5tKGEscykKaWYo
-cCE9PTQ2KXtpZigocF40OCk+OSlqLiQyKCJpbnZhbGlkIGNoYXJhY3RlciIscyl9ZWxzZXtpZihxPT09
-MylqLiQyKGwscykKbz1QLlFBKEMueEIuTmooYSxyLHMpLG0sbSkKaWYodHlwZW9mIG8hPT0ibnVtYmVy
-IilyZXR1cm4gby5vcygpCmlmKG8+MjU1KWouJDIoayxyKQpuPXErMQppZihxPj10KXJldHVybiBILk9I
-KGkscSkKaVtxXT1vCnI9cysxCnE9bn19aWYocSE9PTMpai4kMihsLGMpCm89UC5RQShDLnhCLk5qKGEs
-cixjKSxtLG0pCmlmKHR5cGVvZiBvIT09Im51bWJlciIpcmV0dXJuIG8ub3MoKQppZihvPjI1NSlqLiQy
-KGsscikKaWYocT49dClyZXR1cm4gSC5PSChpLHEpCmlbcV09bwpyZXR1cm4gaX0sCmVnOmZ1bmN0aW9u
-KGEsYixhMCl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaixpLGgsZyxmLGUsZD1uZXcgUC5WQyhhKSxj
-PW5ldyBQLkpUKGQsYSkKaWYoYS5sZW5ndGg8MilkLiQxKCJhZGRyZXNzIGlzIHRvbyBzaG9ydCIpCnQ9
-SC5WTShbXSx1LnQpCmZvcihzPWIscj1zLHE9ITEscD0hMTtzPGEwOysrcyl7bz1DLnhCLm0oYSxzKQpp
-ZihvPT09NTgpe2lmKHM9PT1iKXsrK3MKaWYoQy54Qi5tKGEscykhPT01OClkLiQyKCJpbnZhbGlkIHN0
-YXJ0IGNvbG9uLiIscykKcj1zfWlmKHM9PT1yKXtpZihxKWQuJDIoIm9ubHkgb25lIHdpbGRjYXJkIGA6
-OmAgaXMgYWxsb3dlZCIscykKQy5ObS5pKHQsLTEpCnE9ITB9ZWxzZSBDLk5tLmkodCxjLiQyKHIscykp
-CnI9cysxfWVsc2UgaWYobz09PTQ2KXA9ITB9aWYodC5sZW5ndGg9PT0wKWQuJDEoInRvbyBmZXcgcGFy
-dHMiKQpuPXI9PT1hMAptPUMuTm0uZ3JaKHQpCmlmKG4mJm0hPT0tMSlkLiQyKCJleHBlY3RlZCBhIHBh
-cnQgYWZ0ZXIgbGFzdCBgOmAiLGEwKQppZighbilpZighcClDLk5tLmkodCxjLiQyKHIsYTApKQplbHNl
-e2w9UC5IaChhLHIsYTApCkMuTm0uaSh0LChsWzBdPDw4fGxbMV0pPj4+MCkKQy5ObS5pKHQsKGxbMl08
-PDh8bFszXSk+Pj4wKX1pZihxKXtpZih0Lmxlbmd0aD43KWQuJDEoImFuIGFkZHJlc3Mgd2l0aCBhIHdp
-bGRjYXJkIG11c3QgaGF2ZSBsZXNzIHRoYW4gNyBwYXJ0cyIpfWVsc2UgaWYodC5sZW5ndGghPT04KWQu
-JDEoImFuIGFkZHJlc3Mgd2l0aG91dCBhIHdpbGRjYXJkIG11c3QgY29udGFpbiBleGFjdGx5IDggcGFy
-dHMiKQprPW5ldyBVaW50OEFycmF5KDE2KQpmb3IobT10Lmxlbmd0aCxqPWsubGVuZ3RoLGk9OS1tLHM9
-MCxoPTA7czxtOysrcyl7Zz10W3NdCmlmKGc9PT0tMSlmb3IoZj0wO2Y8aTsrK2Ype2lmKGg8MHx8aD49
-ailyZXR1cm4gSC5PSChrLGgpCmtbaF09MAplPWgrMQppZihlPj1qKXJldHVybiBILk9IKGssZSkKa1tl
-XT0wCmgrPTJ9ZWxzZXtlPUMuam4ud0coZyw4KQppZihoPDB8fGg+PWopcmV0dXJuIEguT0goayxoKQpr
-W2hdPWUKZT1oKzEKaWYoZT49ailyZXR1cm4gSC5PSChrLGUpCmtbZV09ZyYyNTUKaCs9Mn19cmV0dXJu
-IGt9LApqdjpmdW5jdGlvbihhLGIsYyxkLGUsZixnLGgsaSxqKXt2YXIgdCxzLHIscSxwLG8sbixtPW51
-bGwKaWYoaj09bnVsbClpZihkPmIpaj1QLlBpKGEsYixkKQplbHNle2lmKGQ9PT1iKVAuUjMoYSxiLCJJ
-bnZhbGlkIGVtcHR5IHNjaGVtZSIpCmo9IiJ9aWYoZT5iKXt0PWQrMwpzPXQ8ZT9QLnpSKGEsdCxlLTEp
-OiIiCnI9UC5PZShhLGUsZiwhMSkKaWYodHlwZW9mIGYhPT0ibnVtYmVyIilyZXR1cm4gZi5oKCkKcT1m
-KzEKaWYodHlwZW9mIGchPT0ibnVtYmVyIilyZXR1cm4gSC5wWShnKQpwPXE8Zz9QLndCKFAuUUEoSi5s
-ZChhLHEsZyksbmV3IFAuZTEoYSxmKSxtKSxqKTptfWVsc2V7cD1tCnI9cApzPSIifW89UC5rYShhLGcs
-aCxtLGosciE9bnVsbCkKaWYodHlwZW9mIGghPT0ibnVtYmVyIilyZXR1cm4gaC5KKCkKbj1oPGk/UC5s
-ZShhLGgrMSxpLG0pOm0KcmV0dXJuIG5ldyBQLkRuKGoscyxyLHAsbyxuLGk8Yz9QLnRHKGEsaSsxLGMp
-Om0pfSwKS0w6ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyl7dmFyIHQscyxyLHEscCxvCmY9UC5QaShmLDAs
-Zj09bnVsbD8wOmYubGVuZ3RoKQpnPVAuelIoZywwLGc9PW51bGw/MDpnLmxlbmd0aCkKYT1QLk9lKGEs
-MCxhPT1udWxsPzA6YS5sZW5ndGgsITEpCnQ9UC5sZShudWxsLDAsMCxlKQpzPVAudEcobnVsbCwwLDAp
-CmQ9UC53QihkLGYpCnI9Zj09PSJmaWxlIgppZihhPT1udWxsKXE9Zy5sZW5ndGghPT0wfHxkIT1udWxs
-fHxyCmVsc2UgcT0hMQppZihxKWE9IiIKcT1hPT1udWxsCnA9IXEKYj1QLmthKGIsMCxiPT1udWxsPzA6
-Yi5sZW5ndGgsYyxmLHApCm89Zi5sZW5ndGg9PT0wCmlmKG8mJnEmJiFDLnhCLm4oYiwiLyIpKWI9UC53
-RihiLCFvfHxwKQplbHNlIGI9UC54ZShiKQpyZXR1cm4gbmV3IFAuRG4oZixnLHEmJkMueEIubihiLCIv
-LyIpPyIiOmEsZCxiLHQscyl9LAp3SzpmdW5jdGlvbihhKXtpZihhPT09Imh0dHAiKXJldHVybiA4MApp
-ZihhPT09Imh0dHBzIilyZXR1cm4gNDQzCnJldHVybiAwfSwKUjM6ZnVuY3Rpb24oYSxiLGMpe3Rocm93
-IEguYihQLnJyKGMsYSxiKSl9LApYZDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscSxwLG8sbixt
-LGwsayxqLGk9bnVsbCxoPWIubGVuZ3RoCmlmKGghPT0wKXtyPTAKd2hpbGUoITApe2lmKCEocjxoKSl7
-dD0iIgpzPTAKYnJlYWt9aWYoQy54Qi5XKGIscik9PT02NCl7dD1DLnhCLk5qKGIsMCxyKQpzPXIrMQpi
-cmVha30rK3J9aWYoczxoJiZDLnhCLlcoYixzKT09PTkxKXtmb3IocT1zLHA9LTE7cTxoOysrcSl7bz1D
-LnhCLlcoYixxKQppZihvPT09MzcmJnA8MCl7bj1DLnhCLlFpKGIsIjI1IixxKzEpP3ErMjpxCnA9cQpx
-PW59ZWxzZSBpZihvPT09OTMpYnJlYWt9aWYocT09PWgpdGhyb3cgSC5iKFAucnIoIkludmFsaWQgSVB2
-NiBob3N0IGVudHJ5LiIsYixzKSkKbT1wPDA/cTpwClAuZWcoYixzKzEsbSk7KytxCmlmKHEhPT1oJiZD
-LnhCLlcoYixxKSE9PTU4KXRocm93IEguYihQLnJyKCJJbnZhbGlkIGVuZCBvZiBhdXRob3JpdHkiLGIs
-cSkpfWVsc2UgcT1zCndoaWxlKCEwKXtpZighKHE8aCkpe2w9aQpicmVha31pZihDLnhCLlcoYixxKT09
-PTU4KXtrPUMueEIuRyhiLHErMSkKbD1rLmxlbmd0aCE9PTA/UC5RQShrLGksaSk6aQpicmVha30rK3F9
-aj1DLnhCLk5qKGIscyxxKX1lbHNle2w9aQpqPWwKdD0iIn1yZXR1cm4gUC5LTChqLGksSC5WTShjLnNw
-bGl0KCIvIiksdS5zKSxsLGQsYSx0KX0sCmtFOmZ1bmN0aW9uKGEsYil7Qy5ObS5LKGEsbmV3IFAuTlko
-ITEpKX0sCkhOOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIKZm9yKHQ9SC5xQyhhLGMsbnVsbCxILnQ2
-KGEpLmQpLHQ9bmV3IEguYTcodCx0LmdBKHQpLHQuJHRpLkMoImE3PGFMLkU+IikpO3QuRigpOyl7cz10
-LmQKcj1QLm51KCdbIiovOjw+P1xcXFx8XScpCnMudG9TdHJpbmcKaWYoSC5tMihzLHIsMCkpe3Q9UC5M
-NCgiSWxsZWdhbCBjaGFyYWN0ZXIgaW4gcGF0aDogIitzKQp0aHJvdyBILmIodCl9fX0sCnJnOmZ1bmN0
-aW9uKGEsYil7dmFyIHQKaWYoISg2NTw9YSYmYTw9OTApKXQ9OTc8PWEmJmE8PTEyMgplbHNlIHQ9ITAK
-aWYodClyZXR1cm4KdD1QLkw0KCJJbGxlZ2FsIGRyaXZlIGxldHRlciAiK1AuT28oYSkpCnRocm93IEgu
-Yih0KX0sCndCOmZ1bmN0aW9uKGEsYil7aWYoYSE9bnVsbCYmYT09PVAud0soYikpcmV0dXJuIG51bGwK
-cmV0dXJuIGF9LApPZTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscSxwLG8KaWYoYT09bnVsbCly
-ZXR1cm4gbnVsbAppZihiPT09YylyZXR1cm4iIgppZihDLnhCLm0oYSxiKT09PTkxKXtpZih0eXBlb2Yg
-YyE9PSJudW1iZXIiKXJldHVybiBjLkhOKCkKdD1jLTEKaWYoQy54Qi5tKGEsdCkhPT05MylQLlIzKGEs
-YiwiTWlzc2luZyBlbmQgYF1gIHRvIG1hdGNoIGBbYCBpbiBob3N0IikKcz1iKzEKcj1QLnRvKGEscyx0
-KQppZih0eXBlb2YgciE9PSJudW1iZXIiKXJldHVybiByLkooKQppZihyPHQpe3E9cisxCnA9UC5PQShh
-LEMueEIuUWkoYSwiMjUiLHEpP3IrMzpxLHQsIiUyNSIpfWVsc2UgcD0iIgpQLmVnKGEscyxyKQpyZXR1
-cm4gQy54Qi5OaihhLGIscikudG9Mb3dlckNhc2UoKStwKyJdIn1pZih0eXBlb2YgYyE9PSJudW1iZXIi
-KXJldHVybiBILnBZKGMpCm89Ygpmb3IoO288YzsrK28paWYoQy54Qi5tKGEsbyk9PT01OCl7cj1DLnhC
-LlhVKGEsIiUiLGIpCmlmKCEocj49YiYmcjxjKSlyPWMKaWYocjxjKXtxPXIrMQpwPVAuT0EoYSxDLnhC
-LlFpKGEsIjI1IixxKT9yKzM6cSxjLCIlMjUiKX1lbHNlIHA9IiIKUC5lZyhhLGIscikKcmV0dXJuIlsi
-K0MueEIuTmooYSxiLHIpK3ArIl0ifXJldHVybiBQLk9MKGEsYixjKX0sCnRvOmZ1bmN0aW9uKGEsYixj
-KXt2YXIgdCxzPUMueEIuWFUoYSwiJSIsYikKaWYocz49Yil7aWYodHlwZW9mIGMhPT0ibnVtYmVyIily
-ZXR1cm4gSC5wWShjKQp0PXM8Y31lbHNlIHQ9ITEKcmV0dXJuIHQ/czpjfSwKT0E6ZnVuY3Rpb24oYSxi
-LGMsZCl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGs9ZCE9PSIiP25ldyBQLlJuKGQpOm51bGwKaWYodHlw
-ZW9mIGMhPT0ibnVtYmVyIilyZXR1cm4gSC5wWShjKQp0PWIKcz10CnI9ITAKZm9yKDt0PGM7KXtxPUMu
-eEIubShhLHQpCmlmKHE9PT0zNyl7cD1QLnJ2KGEsdCwhMCkKbz1wPT1udWxsCmlmKG8mJnIpe3QrPTMK
-Y29udGludWV9aWYoaz09bnVsbClrPW5ldyBQLlJuKCIiKQpuPWsuYSs9Qy54Qi5OaihhLHMsdCkKaWYo
-bylwPUMueEIuTmooYSx0LHQrMykKZWxzZSBpZihwPT09IiUiKVAuUjMoYSx0LCJab25lSUQgc2hvdWxk
-IG5vdCBjb250YWluICUgYW55bW9yZSIpCmsuYT1uK3AKdCs9MwpzPXQKcj0hMH1lbHNle2lmKHE8MTI3
-KXtvPXE+Pj40CmlmKG8+PTgpcmV0dXJuIEguT0goQy5GMyxvKQpvPShDLkYzW29dJjE8PChxJjE1KSkh
-PT0wfWVsc2Ugbz0hMQppZihvKXtpZihyJiY2NTw9cSYmOTA+PXEpe2lmKGs9PW51bGwpaz1uZXcgUC5S
-bigiIikKaWYoczx0KXtrLmErPUMueEIuTmooYSxzLHQpCnM9dH1yPSExfSsrdH1lbHNle2lmKChxJjY0
-NTEyKT09PTU1Mjk2JiZ0KzE8Yyl7bT1DLnhCLm0oYSx0KzEpCmlmKChtJjY0NTEyKT09PTU2MzIwKXtx
-PTY1NTM2fChxJjEwMjMpPDwxMHxtJjEwMjMKbD0yfWVsc2UgbD0xfWVsc2UgbD0xCmlmKGs9PW51bGwp
-az1uZXcgUC5SbigiIikKay5hKz1DLnhCLk5qKGEscyx0KQprLmErPVAuelgocSkKdCs9bApzPXR9fX1p
-ZihrPT1udWxsKXJldHVybiBDLnhCLk5qKGEsYixjKQppZihzPGMpay5hKz1DLnhCLk5qKGEscyxjKQpv
-PWsuYQpyZXR1cm4gby5jaGFyQ29kZUF0KDApPT0wP286b30sCk9MOmZ1bmN0aW9uKGEsYixjKXt2YXIg
-dCxzLHIscSxwLG8sbixtLGwsayxqCmlmKHR5cGVvZiBjIT09Im51bWJlciIpcmV0dXJuIEgucFkoYykK
-dD1iCnM9dApyPW51bGwKcT0hMApmb3IoO3Q8Yzspe3A9Qy54Qi5tKGEsdCkKaWYocD09PTM3KXtvPVAu
-cnYoYSx0LCEwKQpuPW89PW51bGwKaWYobiYmcSl7dCs9Mwpjb250aW51ZX1pZihyPT1udWxsKXI9bmV3
-IFAuUm4oIiIpCm09Qy54Qi5OaihhLHMsdCkKbD1yLmErPSFxP20udG9Mb3dlckNhc2UoKTptCmlmKG4p
-e289Qy54Qi5OaihhLHQsdCszKQprPTN9ZWxzZSBpZihvPT09IiUiKXtvPSIlMjUiCms9MX1lbHNlIGs9
-MwpyLmE9bCtvCnQrPWsKcz10CnE9ITB9ZWxzZXtpZihwPDEyNyl7bj1wPj4+NAppZihuPj04KXJldHVy
-biBILk9IKEMuZWEsbikKbj0oQy5lYVtuXSYxPDwocCYxNSkpIT09MH1lbHNlIG49ITEKaWYobil7aWYo
-cSYmNjU8PXAmJjkwPj1wKXtpZihyPT1udWxsKXI9bmV3IFAuUm4oIiIpCmlmKHM8dCl7ci5hKz1DLnhC
-Lk5qKGEscyx0KQpzPXR9cT0hMX0rK3R9ZWxzZXtpZihwPD05Myl7bj1wPj4+NAppZihuPj04KXJldHVy
-biBILk9IKEMuYWssbikKbj0oQy5ha1tuXSYxPDwocCYxNSkpIT09MH1lbHNlIG49ITEKaWYobilQLlIz
-KGEsdCwiSW52YWxpZCBjaGFyYWN0ZXIiKQplbHNle2lmKChwJjY0NTEyKT09PTU1Mjk2JiZ0KzE8Yyl7
-aj1DLnhCLm0oYSx0KzEpCmlmKChqJjY0NTEyKT09PTU2MzIwKXtwPTY1NTM2fChwJjEwMjMpPDwxMHxq
-JjEwMjMKaz0yfWVsc2Ugaz0xfWVsc2Ugaz0xCmlmKHI9PW51bGwpcj1uZXcgUC5SbigiIikKbT1DLnhC
-Lk5qKGEscyx0KQpyLmErPSFxP20udG9Mb3dlckNhc2UoKTptCnIuYSs9UC56WChwKQp0Kz1rCnM9dH19
-fX1pZihyPT1udWxsKXJldHVybiBDLnhCLk5qKGEsYixjKQppZihzPGMpe209Qy54Qi5OaihhLHMsYykK
-ci5hKz0hcT9tLnRvTG93ZXJDYXNlKCk6bX1uPXIuYQpyZXR1cm4gbi5jaGFyQ29kZUF0KDApPT0wP246
-bn0sClBpOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscQppZihiPT09YylyZXR1cm4iIgppZighUC5F
-dChKLnJZKGEpLlcoYSxiKSkpUC5SMyhhLGIsIlNjaGVtZSBub3Qgc3RhcnRpbmcgd2l0aCBhbHBoYWJl
-dGljIGNoYXJhY3RlciIpCmZvcih0PWIscz0hMTt0PGM7Kyt0KXtyPUMueEIuVyhhLHQpCmlmKHI8MTI4
-KXtxPXI+Pj40CmlmKHE+PTgpcmV0dXJuIEguT0goQy5tSyxxKQpxPShDLm1LW3FdJjE8PChyJjE1KSkh
-PT0wfWVsc2UgcT0hMQppZighcSlQLlIzKGEsdCwiSWxsZWdhbCBzY2hlbWUgY2hhcmFjdGVyIikKaWYo
-NjU8PXImJnI8PTkwKXM9ITB9YT1DLnhCLk5qKGEsYixjKQpyZXR1cm4gUC5ZYShzP2EudG9Mb3dlckNh
-c2UoKTphKX0sCllhOmZ1bmN0aW9uKGEpe2lmKGE9PT0iaHR0cCIpcmV0dXJuImh0dHAiCmlmKGE9PT0i
-ZmlsZSIpcmV0dXJuImZpbGUiCmlmKGE9PT0iaHR0cHMiKXJldHVybiJodHRwcyIKaWYoYT09PSJwYWNr
-YWdlIilyZXR1cm4icGFja2FnZSIKcmV0dXJuIGF9LAp6UjpmdW5jdGlvbihhLGIsYyl7aWYoYT09bnVs
-bClyZXR1cm4iIgpyZXR1cm4gUC5QSShhLGIsYyxDLnRvLCExKX0sCmthOmZ1bmN0aW9uKGEsYixjLGQs
-ZSxmKXt2YXIgdCxzPWU9PT0iZmlsZSIscj1zfHxmLHE9YT09bnVsbAppZihxJiZkPT1udWxsKXJldHVy
-biBzPyIvIjoiIgpxPSFxCmlmKHEmJmQhPW51bGwpdGhyb3cgSC5iKFAueFkoIkJvdGggcGF0aCBhbmQg
-cGF0aFNlZ21lbnRzIHNwZWNpZmllZCIpKQppZihxKXQ9UC5QSShhLGIsYyxDLldkLCEwKQplbHNle2Qu
-dG9TdHJpbmcKcT1ILnQ2KGQpCnQ9bmV3IEguQTgoZCxxLkMoInFVKDEpIikuYihuZXcgUC5SWigpKSxx
-LkMoIkE4PDEscVU+IikpLkgoMCwiLyIpfWlmKHQubGVuZ3RoPT09MCl7aWYocylyZXR1cm4iLyJ9ZWxz
-ZSBpZihyJiYhQy54Qi5uKHQsIi8iKSl0PSIvIit0CnJldHVybiBQLkpyKHQsZSxmKX0sCkpyOmZ1bmN0
-aW9uKGEsYixjKXt2YXIgdD1iLmxlbmd0aD09PTAKaWYodCYmIWMmJiFDLnhCLm4oYSwiLyIpKXJldHVy
-biBQLndGKGEsIXR8fGMpCnJldHVybiBQLnhlKGEpfSwKbGU6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQs
-cz17fQppZihhIT1udWxsKXtpZihkIT1udWxsKXRocm93IEguYihQLnhZKCJCb3RoIHF1ZXJ5IGFuZCBx
-dWVyeVBhcmFtZXRlcnMgc3BlY2lmaWVkIikpCnJldHVybiBQLlBJKGEsYixjLEMuVkMsITApfWlmKGQ9
-PW51bGwpcmV0dXJuIG51bGwKdD1uZXcgUC5SbigiIikKcy5hPSIiCmQuSygwLG5ldyBQLnk1KG5ldyBQ
-Lk1FKHMsdCkpKQpzPXQuYQpyZXR1cm4gcy5jaGFyQ29kZUF0KDApPT0wP3M6c30sCnRHOmZ1bmN0aW9u
-KGEsYixjKXtpZihhPT1udWxsKXJldHVybiBudWxsCnJldHVybiBQLlBJKGEsYixjLEMuVkMsITApfSwK
-cnY6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbz1iKzIKaWYobz49YS5sZW5ndGgpcmV0dXJu
-IiUiCnQ9Qy54Qi5tKGEsYisxKQpzPUMueEIubShhLG8pCnI9SC5vbyh0KQpxPUgub28ocykKaWYocjww
-fHxxPDApcmV0dXJuIiUiCnA9cioxNitxCmlmKHA8MTI3KXtvPUMuam4ud0cocCw0KQppZihvPj04KXJl
-dHVybiBILk9IKEMuRjMsbykKbz0oQy5GM1tvXSYxPDwocCYxNSkpIT09MH1lbHNlIG89ITEKaWYobyly
-ZXR1cm4gSC5MdyhjJiY2NTw9cCYmOTA+PXA/KHB8MzIpPj4+MDpwKQppZih0Pj05N3x8cz49OTcpcmV0
-dXJuIEMueEIuTmooYSxiLGIrMykudG9VcHBlckNhc2UoKQpyZXR1cm4gbnVsbH0sCnpYOmZ1bmN0aW9u
-KGEpe3ZhciB0LHMscixxLHAsbyxuPSIwMTIzNDU2Nzg5QUJDREVGIgppZihhPDEyOCl7dD1uZXcgQXJy
-YXkoMykKdC5maXhlZCRsZW5ndGg9QXJyYXkKcz1ILlZNKHQsdS50KQpDLk5tLlkocywwLDM3KQpDLk5t
-LlkocywxLEMueEIuVyhuLGE+Pj40KSkKQy5ObS5ZKHMsMixDLnhCLlcobixhJjE1KSl9ZWxzZXtpZihh
-PjIwNDcpaWYoYT42NTUzNSl7cj0yNDAKcT00fWVsc2V7cj0yMjQKcT0zfWVsc2V7cj0xOTIKcT0yfXQ9
-bmV3IEFycmF5KDMqcSkKdC5maXhlZCRsZW5ndGg9QXJyYXkKcz1ILlZNKHQsdS50KQpmb3IocD0wOy0t
-cSxxPj0wO3I9MTI4KXtvPUMuam4uYmYoYSw2KnEpJjYzfHIKQy5ObS5ZKHMscCwzNykKQy5ObS5ZKHMs
-cCsxLEMueEIuVyhuLG8+Pj40KSkKQy5ObS5ZKHMscCsyLEMueEIuVyhuLG8mMTUpKQpwKz0zfX1yZXR1
-cm4gUC5ITShzLDAsbnVsbCl9LApQSTpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0PVAuVWwoYSxiLGMs
-ZCxlKQpyZXR1cm4gdD09bnVsbD9DLnhCLk5qKGEsYixjKTp0fSwKVWw6ZnVuY3Rpb24oYSxiLGMsZCxl
-KXt2YXIgdCxzLHIscSxwLG89bnVsbCxuPSFlLG09YixsPW0saz1vCndoaWxlKCEwKXtpZih0eXBlb2Yg
-bSE9PSJudW1iZXIiKXJldHVybiBtLkooKQppZih0eXBlb2YgYyE9PSJudW1iZXIiKXJldHVybiBILnBZ
-KGMpCmlmKCEobTxjKSlicmVhawpjJDA6e3Q9Qy54Qi5tKGEsbSkKaWYodDwxMjcpe3M9dD4+PjQKaWYo
-cz49OClyZXR1cm4gSC5PSChkLHMpCnM9KGRbc10mMTw8KHQmMTUpKSE9PTB9ZWxzZSBzPSExCmlmKHMp
-KyttCmVsc2V7aWYodD09PTM3KXtyPVAucnYoYSxtLCExKQppZihyPT1udWxsKXttKz0zCmJyZWFrIGMk
-MH1pZigiJSI9PT1yKXtyPSIlMjUiCnE9MX1lbHNlIHE9M31lbHNle2lmKG4paWYodDw9OTMpe3M9dD4+
-PjQKaWYocz49OClyZXR1cm4gSC5PSChDLmFrLHMpCnM9KEMuYWtbc10mMTw8KHQmMTUpKSE9PTB9ZWxz
-ZSBzPSExCmVsc2Ugcz0hMQppZihzKXtQLlIzKGEsbSwiSW52YWxpZCBjaGFyYWN0ZXIiKQpxPW8Kcj1x
-fWVsc2V7aWYoKHQmNjQ1MTIpPT09NTUyOTYpe3M9bSsxCmlmKHM8Yyl7cD1DLnhCLm0oYSxzKQppZigo
-cCY2NDUxMik9PT01NjMyMCl7dD02NTUzNnwodCYxMDIzKTw8MTB8cCYxMDIzCnE9Mn1lbHNlIHE9MX1l
-bHNlIHE9MX1lbHNlIHE9MQpyPVAuelgodCl9fWlmKGs9PW51bGwpaz1uZXcgUC5SbigiIikKay5hKz1D
-LnhCLk5qKGEsbCxtKQprLmErPUguZChyKQppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBILnBZ
-KHEpCm0rPXEKbD1tfX19aWYoaz09bnVsbClyZXR1cm4gbwppZih0eXBlb2YgbCE9PSJudW1iZXIiKXJl
-dHVybiBsLkooKQppZihsPGMpay5hKz1DLnhCLk5qKGEsbCxjKQpuPWsuYQpyZXR1cm4gbi5jaGFyQ29k
-ZUF0KDApPT0wP246bn0sCnlCOmZ1bmN0aW9uKGEpe2lmKEMueEIubihhLCIuIikpcmV0dXJuITAKcmV0
-dXJuIEMueEIuT1koYSwiLy4iKSE9PS0xfSwKeGU6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG4K
-aWYoIVAueUIoYSkpcmV0dXJuIGEKdD1ILlZNKFtdLHUucykKZm9yKHM9YS5zcGxpdCgiLyIpLHI9cy5s
-ZW5ndGgscT0hMSxwPTA7cDxyOysrcCl7bz1zW3BdCmlmKEouUk0obywiLi4iKSl7bj10Lmxlbmd0aApp
-ZihuIT09MCl7aWYoMD49bilyZXR1cm4gSC5PSCh0LC0xKQp0LnBvcCgpCmlmKHQubGVuZ3RoPT09MClD
-Lk5tLmkodCwiIil9cT0hMH1lbHNlIGlmKCIuIj09PW8pcT0hMAplbHNle0MuTm0uaSh0LG8pCnE9ITF9
-fWlmKHEpQy5ObS5pKHQsIiIpCnJldHVybiBDLk5tLkgodCwiLyIpfSwKd0Y6ZnVuY3Rpb24oYSxiKXt2
-YXIgdCxzLHIscSxwLG8KaWYoIVAueUIoYSkpcmV0dXJuIWI/UC5DMShhKTphCnQ9SC5WTShbXSx1LnMp
-CmZvcihzPWEuc3BsaXQoIi8iKSxyPXMubGVuZ3RoLHE9ITEscD0wO3A8cjsrK3Ape289c1twXQppZigi
-Li4iPT09bylpZih0Lmxlbmd0aCE9PTAmJkMuTm0uZ3JaKHQpIT09Ii4uIil7aWYoMD49dC5sZW5ndGgp
-cmV0dXJuIEguT0godCwtMSkKdC5wb3AoKQpxPSEwfWVsc2V7Qy5ObS5pKHQsIi4uIikKcT0hMX1lbHNl
-IGlmKCIuIj09PW8pcT0hMAplbHNle0MuTm0uaSh0LG8pCnE9ITF9fXM9dC5sZW5ndGgKaWYocyE9PTAp
-aWYocz09PTEpe2lmKDA+PXMpcmV0dXJuIEguT0godCwwKQpzPXRbMF0ubGVuZ3RoPT09MH1lbHNlIHM9
-ITEKZWxzZSBzPSEwCmlmKHMpcmV0dXJuIi4vIgppZihxfHxDLk5tLmdyWih0KT09PSIuLiIpQy5ObS5p
-KHQsIiIpCmlmKCFiKXtpZigwPj10Lmxlbmd0aClyZXR1cm4gSC5PSCh0LDApCkMuTm0uWSh0LDAsUC5D
-MSh0WzBdKSl9cmV0dXJuIEMuTm0uSCh0LCIvIil9LApDMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1h
-Lmxlbmd0aAppZihxPj0yJiZQLkV0KEouUXooYSwwKSkpZm9yKHQ9MTt0PHE7Kyt0KXtzPUMueEIuVyhh
-LHQpCmlmKHM9PT01OClyZXR1cm4gQy54Qi5OaihhLDAsdCkrIiUzQSIrQy54Qi5HKGEsdCsxKQppZihz
-PD0xMjcpe3I9cz4+PjQKaWYocj49OClyZXR1cm4gSC5PSChDLm1LLHIpCnI9KEMubUtbcl0mMTw8KHMm
-MTUpKT09PTB9ZWxzZSByPSEwCmlmKHIpYnJlYWt9cmV0dXJuIGF9LAptbjpmdW5jdGlvbihhKXt2YXIg
-dCxzLHIscT1hLmdGaigpLHA9cS5sZW5ndGgKaWYocD4wJiZKLkhtKHFbMF0pPT09MiYmSi5hNihxWzBd
-LDEpPT09NTgpe2lmKDA+PXApcmV0dXJuIEguT0gocSwwKQpQLnJnKEouYTYocVswXSwwKSwhMSkKUC5I
-TihxLCExLDEpCnQ9ITB9ZWxzZXtQLkhOKHEsITEsMCkKdD0hMX1zPWEuZ3RUKCkmJiF0PyJcXCI6IiIK
-aWYoYS5nY2ooKSl7cj1hLmdKZihhKQppZihyLmxlbmd0aCE9PTApcz1zKyJcXCIrcisiXFwifXM9UC52
-ZyhzLHEsIlxcIikKcD10JiZwPT09MT9zKyJcXCI6cwpyZXR1cm4gcC5jaGFyQ29kZUF0KDApPT0wP3A6
-cH0sCkloOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCmZvcih0PTAscz0wO3M8MjsrK3Mpe3I9Qy54Qi5X
-KGEsYitzKQppZig0ODw9ciYmcjw9NTcpdD10KjE2K3ItNDgKZWxzZXtyfD0zMgppZig5Nzw9ciYmcjw9
-MTAyKXQ9dCoxNityLTg3CmVsc2UgdGhyb3cgSC5iKFAueFkoIkludmFsaWQgVVJMIGVuY29kaW5nIikp
-fX1yZXR1cm4gdH0sCmt1OmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxyLHEscD1KLnJZKGEpLG89
-Ygp3aGlsZSghMCl7aWYoIShvPGMpKXt0PSEwCmJyZWFrfXM9cC5XKGEsbykKaWYoczw9MTI3KWlmKHMh
-PT0zNylyPWUmJnM9PT00MwplbHNlIHI9ITAKZWxzZSByPSEwCmlmKHIpe3Q9ITEKYnJlYWt9KytvfWlm
-KHQpe2lmKEMueE0hPT1kKXI9ITEKZWxzZSByPSEwCmlmKHIpcmV0dXJuIHAuTmooYSxiLGMpCmVsc2Ug
-cT1uZXcgSC5xaihwLk5qKGEsYixjKSl9ZWxzZXtxPUguVk0oW10sdS50KQpmb3Iobz1iO288YzsrK28p
-e3M9cC5XKGEsbykKaWYocz4xMjcpdGhyb3cgSC5iKFAueFkoIklsbGVnYWwgcGVyY2VudCBlbmNvZGlu
-ZyBpbiBVUkkiKSkKaWYocz09PTM3KXtpZihvKzM+YS5sZW5ndGgpdGhyb3cgSC5iKFAueFkoIlRydW5j
-YXRlZCBVUkkiKSkKQy5ObS5pKHEsUC5JaChhLG8rMSkpCm8rPTJ9ZWxzZSBpZihlJiZzPT09NDMpQy5O
-bS5pKHEsMzIpCmVsc2UgQy5ObS5pKHEscyl9fXUuTC5iKHEpCnJldHVybiBuZXcgUC5HWSghMSkuV0oo
-cSl9LApFdDpmdW5jdGlvbihhKXt2YXIgdD1hfDMyCnJldHVybiA5Nzw9dCYmdDw9MTIyfSwKS0Q6ZnVu
-Y3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG0sbD0iSW52YWxpZCBNSU1FIHR5cGUiLGs9SC5W
-TShbYi0xXSx1LnQpCmZvcih0PWEubGVuZ3RoLHM9YixyPS0xLHE9bnVsbDtzPHQ7KytzKXtxPUMueEIu
-VyhhLHMpCmlmKHE9PT00NHx8cT09PTU5KWJyZWFrCmlmKHE9PT00Nyl7aWYocjwwKXtyPXMKY29udGlu
-dWV9dGhyb3cgSC5iKFAucnIobCxhLHMpKX19aWYocjwwJiZzPmIpdGhyb3cgSC5iKFAucnIobCxhLHMp
-KQpmb3IoO3EhPT00NDspe0MuTm0uaShrLHMpOysrcwpmb3IocD0tMTtzPHQ7KytzKXtxPUMueEIuVyhh
-LHMpCmlmKHE9PT02MSl7aWYocDwwKXA9c31lbHNlIGlmKHE9PT01OXx8cT09PTQ0KWJyZWFrfWlmKHA+
-PTApQy5ObS5pKGsscCkKZWxzZXtvPUMuTm0uZ3JaKGspCmlmKHEhPT00NHx8cyE9PW8rN3x8IUMueEIu
-UWkoYSwiYmFzZTY0IixvKzEpKXRocm93IEguYihQLnJyKCJFeHBlY3RpbmcgJz0nIixhLHMpKQpicmVh
-a319Qy5ObS5pKGsscykKbj1zKzEKaWYoKGsubGVuZ3RoJjEpPT09MSlhPUMuaDkueXIoYSxuLHQpCmVs
-c2V7bT1QLlVsKGEsbix0LEMuVkMsITApCmlmKG0hPW51bGwpYT1DLnhCLmk3KGEsbix0LG0pfXJldHVy
-biBuZXcgUC5QRShhLGssYyl9LAp1eDpmdW5jdGlvbigpe3ZhciB0PSIwMTIzNDU2Nzg5QUJDREVGR0hJ
-SktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ei0uX34hJCYnKCkqKyw7PSIs
-cz0iLiIscj0iOiIscT0iLyIscD0iPyIsbz0iIyIsbj11LmdjLG09UC5kSCgyMixuZXcgUC5xMygpLG4p
-LGw9bmV3IFAueUkobSksaz1uZXcgUC5jNigpLGo9bmV3IFAucWQoKSxpPW4uYihsLiQyKDAsMjI1KSkK
-ay4kMyhpLHQsMSkKay4kMyhpLHMsMTQpCmsuJDMoaSxyLDM0KQprLiQzKGkscSwzKQprLiQzKGkscCwx
-NzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxNCwyMjUpKQprLiQzKGksdCwxKQprLiQzKGkscywx
-NSkKay4kMyhpLHIsMzQpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9
-bi5iKGwuJDIoMTUsMjI1KSkKay4kMyhpLHQsMSkKay4kMyhpLCIlIiwyMjUpCmsuJDMoaSxyLDM0KQpr
-LiQzKGkscSw5KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxLDIyNSkpCmsu
-JDMoaSx0LDEpCmsuJDMoaSxyLDM0KQprLiQzKGkscSwxMCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywy
-MDUpCmk9bi5iKGwuJDIoMiwyMzUpKQprLiQzKGksdCwxMzkpCmsuJDMoaSxxLDEzMSkKay4kMyhpLHMs
-MTQ2KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigzLDIzNSkpCmsuJDMoaSx0
-LDExKQprLiQzKGkscSw2OCkKay4kMyhpLHMsMTgpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQpp
-PW4uYihsLiQyKDQsMjI5KSkKay4kMyhpLHQsNSkKai4kMyhpLCJBWiIsMjI5KQprLiQzKGksciwxMDIp
-CmsuJDMoaSwiQCIsNjgpCmsuJDMoaSwiWyIsMjMyKQprLiQzKGkscSwxMzgpCmsuJDMoaSxwLDE3MikK
-ay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDUsMjI5KSkKay4kMyhpLHQsNSkKai4kMyhpLCJBWiIsMjI5
-KQprLiQzKGksciwxMDIpCmsuJDMoaSwiQCIsNjgpCmsuJDMoaSxxLDEzOCkKay4kMyhpLHAsMTcyKQpr
-LiQzKGksbywyMDUpCmk9bi5iKGwuJDIoNiwyMzEpKQpqLiQzKGksIjE5Iiw3KQprLiQzKGksIkAiLDY4
-KQprLiQzKGkscSwxMzgpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQyKDcsMjMx
-KSkKai4kMyhpLCIwOSIsNykKay4kMyhpLCJAIiw2OCkKay4kMyhpLHEsMTM4KQprLiQzKGkscCwxNzIp
-CmsuJDMoaSxvLDIwNSkKay4kMyhuLmIobC4kMig4LDgpKSwiXSIsNSkKaT1uLmIobC4kMig5LDIzNSkp
-CmsuJDMoaSx0LDExKQprLiQzKGkscywxNikKay4kMyhpLHEsMjM0KQprLiQzKGkscCwxNzIpCmsuJDMo
-aSxvLDIwNSkKaT1uLmIobC4kMigxNiwyMzUpKQprLiQzKGksdCwxMSkKay4kMyhpLHMsMTcpCmsuJDMo
-aSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5iKGwuJDIoMTcsMjM1KSkKay4k
-MyhpLHQsMTEpCmsuJDMoaSxxLDkpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYihsLiQy
-KDEwLDIzNSkpCmsuJDMoaSx0LDExKQprLiQzKGkscywxOCkKay4kMyhpLHEsMjM0KQprLiQzKGkscCwx
-NzIpCmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxOCwyMzUpKQprLiQzKGksdCwxMSkKay4kMyhpLHMs
-MTkpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5iKGwuJDIoMTks
-MjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUp
-Cmk9bi5iKGwuJDIoMTEsMjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxxLDEwKQprLiQzKGkscCwxNzIp
-CmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxMiwyMzYpKQprLiQzKGksdCwxMikKay4kMyhpLHAsMTIp
-CmsuJDMoaSxvLDIwNSkKaT1uLmIobC4kMigxMywyMzcpKQprLiQzKGksdCwxMykKay4kMyhpLHAsMTMp
-CmouJDMobi5iKGwuJDIoMjAsMjQ1KSksImF6IiwyMSkKbD1uLmIobC4kMigyMSwyNDUpKQpqLiQzKGws
-ImF6IiwyMSkKai4kMyhsLCIwOSIsMjEpCmsuJDMobCwiKy0uIiwyMSkKcmV0dXJuIG19LApVQjpmdW5j
-dGlvbihhLGIsYyxkLGUpe3ZhciB0LHMscixxLHAsbz0kLnZaKCkKZm9yKHQ9Si5yWShhKSxzPWI7czxj
-Oysrcyl7aWYoZDwwfHxkPj1vLmxlbmd0aClyZXR1cm4gSC5PSChvLGQpCnI9b1tkXQpxPXQuVyhhLHMp
-Xjk2CmlmKHE+OTUpcT0zMQppZihxPj1yLmxlbmd0aClyZXR1cm4gSC5PSChyLHEpCnA9cltxXQpkPXAm
-MzEKQy5ObS5ZKGUscD4+PjUscyl9cmV0dXJuIGR9LApXRjpmdW5jdGlvbiBXRihhLGIpe3RoaXMuYT1h
-CnRoaXMuYj1ifSwKYTI6ZnVuY3Rpb24gYTIoKXt9LAppUDpmdW5jdGlvbiBpUChhLGIpe3RoaXMuYT1h
-CnRoaXMuYj1ifSwKQ1A6ZnVuY3Rpb24gQ1AoKXt9LApYUzpmdW5jdGlvbiBYUygpe30sCkM2OmZ1bmN0
-aW9uIEM2KGEpe3RoaXMuYT1hfSwKbjpmdW5jdGlvbiBuKCl7fSwKdTpmdW5jdGlvbiB1KGEsYixjLGQp
-e3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWR9LApiSjpmdW5jdGlvbiBiSihhLGIsYyxk
-LGUsZil7dmFyIF89dGhpcwpfLmU9YQpfLmY9YgpfLmE9YwpfLmI9ZApfLmM9ZQpfLmQ9Zn0sCmVZOmZ1
-bmN0aW9uIGVZKGEsYixjLGQsZSl7dmFyIF89dGhpcwpfLmY9YQpfLmE9YgpfLmI9YwpfLmM9ZApfLmQ9
-ZX0sCm1wOmZ1bmN0aW9uIG1wKGEsYixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5k
-PWR9LAp1YjpmdW5jdGlvbiB1YihhKXt0aGlzLmE9YX0sCmRzOmZ1bmN0aW9uIGRzKGEpe3RoaXMuYT1h
-fSwKbGo6ZnVuY3Rpb24gbGooYSl7dGhpcy5hPWF9LApVVjpmdW5jdGlvbiBVVihhKXt0aGlzLmE9YX0s
-Cms1OmZ1bmN0aW9uIGs1KCl7fSwKS1k6ZnVuY3Rpb24gS1koKXt9LApjOmZ1bmN0aW9uIGMoYSl7dGhp
-cy5hPWF9LApDRDpmdW5jdGlvbiBDRChhKXt0aGlzLmE9YX0sCmFFOmZ1bmN0aW9uIGFFKGEsYixjKXt0
-aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCkVIOmZ1bmN0aW9uIEVIKCl7fSwKS046ZnVuY3Rpb24g
-S04oKXt9LApjWDpmdW5jdGlvbiBjWCgpe30sCkFuOmZ1bmN0aW9uIEFuKCl7fSwKek06ZnVuY3Rpb24g
-ek0oKXt9LApaMDpmdW5jdGlvbiBaMCgpe30sCk4zOmZ1bmN0aW9uIE4zKGEsYixjKXt0aGlzLmE9YQp0
-aGlzLmI9Ygp0aGlzLiR0aT1jfSwKYzg6ZnVuY3Rpb24gYzgoKXt9LApGSzpmdW5jdGlvbiBGSygpe30s
-Cms6ZnVuY3Rpb24gaygpe30sCk9kOmZ1bmN0aW9uIE9kKCl7fSwKaWI6ZnVuY3Rpb24gaWIoKXt9LAp4
-dTpmdW5jdGlvbiB4dSgpe30sCkd6OmZ1bmN0aW9uIEd6KCl7fSwKcVU6ZnVuY3Rpb24gcVUoKXt9LApS
-bjpmdW5jdGlvbiBSbihhKXt0aGlzLmE9YX0sCkdEOmZ1bmN0aW9uIEdEKCl7fSwKbjE6ZnVuY3Rpb24g
-bjEoYSl7dGhpcy5hPWF9LApjUzpmdW5jdGlvbiBjUyhhKXt0aGlzLmE9YX0sClZDOmZ1bmN0aW9uIFZD
-KGEpe3RoaXMuYT1hfSwKSlQ6ZnVuY3Rpb24gSlQoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkRuOmZ1
-bmN0aW9uIERuKGEsYixjLGQsZSxmLGcpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWQK
-Xy5lPWUKXy5mPWYKXy5yPWcKXy5RPV8uej1fLnk9Xy54PW51bGx9LAplMTpmdW5jdGlvbiBlMShhLGIp
-e3RoaXMuYT1hCnRoaXMuYj1ifSwKTlk6ZnVuY3Rpb24gTlkoYSl7dGhpcy5hPWF9LApSWjpmdW5jdGlv
-biBSWigpe30sCk1FOmZ1bmN0aW9uIE1FKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAp5NTpmdW5jdGlv
-biB5NShhKXt0aGlzLmE9YX0sClBFOmZ1bmN0aW9uIFBFKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0
-aGlzLmM9Y30sCnEzOmZ1bmN0aW9uIHEzKCl7fSwKeUk6ZnVuY3Rpb24geUkoYSl7dGhpcy5hPWF9LApj
-NjpmdW5jdGlvbiBjNigpe30sCnFkOmZ1bmN0aW9uIHFkKCl7fSwKVWY6ZnVuY3Rpb24gVWYoYSxiLGMs
-ZCxlLGYsZyxoKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1kCl8uZT1lCl8uZj1mCl8u
-cj1nCl8ueD1oCl8ueT1udWxsfSwKcWU6ZnVuY3Rpb24gcWUoYSxiLGMsZCxlLGYsZyl7dmFyIF89dGhp
-cwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9ZgpfLnI9ZwpfLlE9Xy56PV8ueT1fLng9
-bnVsbH0sCmlKOmZ1bmN0aW9uIGlKKCl7fSwKbFI6ZnVuY3Rpb24gbFIoYSxiKXt0aGlzLmE9YQp0aGlz
-LmI9Yn0sCmpnOmZ1bmN0aW9uIGpnKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApCZjpmdW5jdGlvbiBC
-ZihhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKQXM6ZnVuY3Rpb24gQXMoKXt9LApHRTpmdW5jdGlvbiBH
-RShhKXt0aGlzLmE9YX0sCk43OmZ1bmN0aW9uIE43KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAp1UTpm
-dW5jdGlvbiB1USgpe30sCmhGOmZ1bmN0aW9uIGhGKCl7fSwKUjQ6ZnVuY3Rpb24oYSxiLGMsZCl7dmFy
-IHQscyxyCkgueGQoYikKdS5qLmIoZCkKaWYoSC5vVChiKSl7dD1bY10KQy5ObS5GVih0LGQpCmQ9dH1z
-PXUuegpyPVAuQ0goSi5NMShkLFAudzAoKSxzKSwhMCxzKQp1LlouYihhKQpyZXR1cm4gUC53WShILkVr
-KGEscixudWxsKSl9LApEbTpmdW5jdGlvbihhLGIsYyl7dmFyIHQKdHJ5e2lmKE9iamVjdC5pc0V4dGVu
-c2libGUoYSkmJiFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYSxiKSl7T2JqZWN0
-LmRlZmluZVByb3BlcnR5KGEsYix7dmFsdWU6Y30pCnJldHVybiEwfX1jYXRjaCh0KXtILlJ1KHQpfXJl
-dHVybiExfSwKT206ZnVuY3Rpb24oYSxiKXtpZihPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5
-LmNhbGwoYSxiKSlyZXR1cm4gYVtiXQpyZXR1cm4gbnVsbH0sCndZOmZ1bmN0aW9uKGEpe2lmKGE9PW51
-bGx8fHR5cGVvZiBhPT0ic3RyaW5nInx8dHlwZW9mIGE9PSJudW1iZXIifHxILmwoYSkpcmV0dXJuIGEK
-aWYoYSBpbnN0YW5jZW9mIFAuRTQpcmV0dXJuIGEuYQppZihILlI5KGEpKXJldHVybiBhCmlmKHUudS5j
-KGEpKXJldHVybiBhCmlmKGEgaW5zdGFuY2VvZiBQLmlQKXJldHVybiBILm8yKGEpCmlmKHUuWi5jKGEp
-KXJldHVybiBQLmhFKGEsIiRkYXJ0X2pzRnVuY3Rpb24iLG5ldyBQLlBDKCkpCnJldHVybiBQLmhFKGEs
-Il8kZGFydF9qc09iamVjdCIsbmV3IFAubXQoJC5rSSgpKSl9LApoRTpmdW5jdGlvbihhLGIsYyl7dmFy
-IHQ9UC5PbShhLGIpCmlmKHQ9PW51bGwpe3Q9Yy4kMShhKQpQLkRtKGEsYix0KX1yZXR1cm4gdH0sCkw3
-OmZ1bmN0aW9uKGEpe3ZhciB0LHMKaWYoYT09bnVsbHx8dHlwZW9mIGE9PSJzdHJpbmcifHx0eXBlb2Yg
-YT09Im51bWJlciJ8fHR5cGVvZiBhPT0iYm9vbGVhbiIpcmV0dXJuIGEKZWxzZSBpZihhIGluc3RhbmNl
-b2YgT2JqZWN0JiZILlI5KGEpKXJldHVybiBhCmVsc2UgaWYoYSBpbnN0YW5jZW9mIE9iamVjdCYmdS51
-LmMoYSkpcmV0dXJuIGEKZWxzZSBpZihhIGluc3RhbmNlb2YgRGF0ZSl7dD1ILlNjKGEuZ2V0VGltZSgp
-KQppZihNYXRoLmFicyh0KTw9ODY0ZTEzKXM9ITEKZWxzZSBzPSEwCmlmKHMpSC52aChQLnhZKCJEYXRl
-VGltZSBpcyBvdXRzaWRlIHZhbGlkIHJhbmdlOiAiK3QpKQpyZXR1cm4gbmV3IFAuaVAodCwhMSl9ZWxz
-ZSBpZihhLmNvbnN0cnVjdG9yPT09JC5rSSgpKXJldHVybiBhLm8KZWxzZSByZXR1cm4gUC5ORChhKX0s
-Ck5EOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBQLmlRKGEsJC53KCks
-bmV3IFAuTnooKSkKaWYoYSBpbnN0YW5jZW9mIEFycmF5KXJldHVybiBQLmlRKGEsJC5SOCgpLG5ldyBQ
-LlFTKCkpCnJldHVybiBQLmlRKGEsJC5SOCgpLG5ldyBQLm5wKCkpfSwKaVE6ZnVuY3Rpb24oYSxiLGMp
-e3ZhciB0PVAuT20oYSxiKQppZih0PT1udWxsfHwhKGEgaW5zdGFuY2VvZiBPYmplY3QpKXt0PWMuJDEo
-YSkKUC5EbShhLGIsdCl9cmV0dXJuIHR9LApQQzpmdW5jdGlvbiBQQygpe30sCm10OmZ1bmN0aW9uIG10
-KGEpe3RoaXMuYT1hfSwKTno6ZnVuY3Rpb24gTnooKXt9LApRUzpmdW5jdGlvbiBRUygpe30sCm5wOmZ1
-bmN0aW9uIG5wKCl7fSwKRTQ6ZnVuY3Rpb24gRTQoYSl7dGhpcy5hPWF9LApyNzpmdW5jdGlvbiByNyhh
-KXt0aGlzLmE9YX0sClR6OmZ1bmN0aW9uIFR6KGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCmNvOmZ1
-bmN0aW9uIGNvKCl7fSwKbmQ6ZnVuY3Rpb24gbmQoKXt9LApLZTpmdW5jdGlvbiBLZShhKXt0aGlzLmE9
-YX0sCmQ1OmZ1bmN0aW9uIGQ1KCl7fSwKbjY6ZnVuY3Rpb24gbjYoKXt9fSxXPXsKeDM6ZnVuY3Rpb24o
-KXtyZXR1cm4gd2luZG93fSwKWnI6ZnVuY3Rpb24oKXtyZXR1cm4gZG9jdW1lbnR9LApKNjpmdW5jdGlv
-bihhKXt2YXIgdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikKaWYoYSE9bnVsbCl0LmhyZWY9YQpy
-ZXR1cm4gdH0sClU5OmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1kb2N1bWVudC5ib2R5LHM9KHQmJkMuUlkp
-LnI2KHQsYSxiLGMpCnMudG9TdHJpbmcKdD11LmFjCnQ9bmV3IEguVTUobmV3IFcuZTcocyksdC5DKCJh
-MihsRC5FKSIpLmIobmV3IFcuQ3YoKSksdC5DKCJVNTxsRC5FPiIpKQpyZXR1cm4gdS5oLmIodC5ncjgo
-dCkpfSwKclM6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPSJlbGVtZW50IHRhZyB1bmF2YWlsYWJsZSIKdHJ5
-e3Q9Si5SRShhKQppZih0eXBlb2YgdC5nbnMoYSk9PSJzdHJpbmciKXI9dC5nbnMoYSl9Y2F0Y2gocyl7
-SC5SdShzKX1yZXR1cm4gcn0sCkMwOmZ1bmN0aW9uKGEsYil7YT01MzY4NzA5MTEmYStiCmE9NTM2ODcw
-OTExJmErKCg1MjQyODcmYSk8PDEwKQpyZXR1cm4gYV5hPj4+Nn0sCnJFOmZ1bmN0aW9uKGEsYixjLGQp
-e3ZhciB0PVcuQzAoVy5DMChXLkMwKFcuQzAoMCxhKSxiKSxjKSxkKSxzPTUzNjg3MDkxMSZ0KygoNjcx
-MDg4NjMmdCk8PDMpCnNePXM+Pj4xMQpyZXR1cm4gNTM2ODcwOTExJnMrKCgxNjM4MyZzKTw8MTUpfSwK
-VE46ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9YS5jbGFzc0xpc3QKZm9yKHQ9Yi5sZW5ndGgscz0wO3M8
-Yi5sZW5ndGg7Yi5sZW5ndGg9PT10fHwoMCxILmxrKShiKSwrK3Mpci5hZGQoYltzXSl9LApKRTpmdW5j
-dGlvbihhLGIsYyxkLGUpe3ZhciB0PVcuYUYobmV3IFcudk4oYyksdS5CKQppZih0IT1udWxsJiYhMClK
-LmRaKGEsYix0LCExKQpyZXR1cm4gbmV3IFcueEMoYSxiLHQsITEsZS5DKCJ4QzwwPiIpKX0sClR3OmZ1
-bmN0aW9uKGEpe3ZhciB0PVcuSjYobnVsbCkscz13aW5kb3cubG9jYXRpb24KdD1uZXcgVy5KUShuZXcg
-Vy5tayh0LHMpKQp0LkNZKGEpCnJldHVybiB0fSwKcUQ6ZnVuY3Rpb24oYSxiLGMsZCl7dS5oLmIoYSkK
-SC55KGIpCkgueShjKQp1Lk8uYihkKQpyZXR1cm4hMH0sClFXOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0
-LHMscgp1LmguYihhKQpILnkoYikKSC55KGMpCnQ9dS5PLmIoZCkuYQpzPXQuYQpzLmhyZWY9YwpyPXMu
-aG9zdG5hbWUKdD10LmIKaWYoIShyPT10Lmhvc3RuYW1lJiZzLnBvcnQ9PXQucG9ydCYmcy5wcm90b2Nv
-bD09dC5wcm90b2NvbCkpaWYocj09PSIiKWlmKHMucG9ydD09PSIiKXt0PXMucHJvdG9jb2wKdD10PT09
-IjoifHx0PT09IiJ9ZWxzZSB0PSExCmVsc2UgdD0hMQplbHNlIHQ9ITAKcmV0dXJuIHR9LApCbDpmdW5j
-dGlvbigpe3ZhciB0PXUuTixzPVAudE0oQy5ReCx0KSxyPXUuZEcuYihuZXcgVy5JQSgpKSxxPUguVk0o
-WyJURU1QTEFURSJdLHUucykKdD1uZXcgVy5jdChzLFAuTHModCksUC5Mcyh0KSxQLkxzKHQpLG51bGwp
-CnQuQ1kobnVsbCxuZXcgSC5BOChDLlF4LHIsdS5kdikscSxudWxsKQpyZXR1cm4gdH0sCnVWOmZ1bmN0
-aW9uKGEpe2lmKGE9PW51bGwpcmV0dXJuIG51bGwKcmV0dXJuIFcuUDEoYSl9LApxYzpmdW5jdGlvbihh
-KXt2YXIgdAppZihhPT1udWxsKXJldHVybiBudWxsCmlmKCJwb3N0TWVzc2FnZSIgaW4gYSl7dD1XLlAx
-KGEpCmlmKHUuci5jKHQpKXJldHVybiB0CnJldHVybiBudWxsfWVsc2UgcmV0dXJuIHUuci5iKGEpfSwK
-UDE6ZnVuY3Rpb24oYSl7aWYoYT09PXdpbmRvdylyZXR1cm4gdS5jaS5iKGEpCmVsc2UgcmV0dXJuIG5l
-dyBXLmRXKGEpfSwKSEg6ZnVuY3Rpb24oYSl7aWYoYT09PXdpbmRvdy5sb2NhdGlvbilyZXR1cm4gYQpl
-bHNlIHJldHVybiBuZXcgVy5GYigpfSwKYUY6ZnVuY3Rpb24oYSxiKXt2YXIgdD0kLlgzCmlmKHQ9PT1D
-Lk5VKXJldHVybiBhCnJldHVybiB0LlB5KGEsYil9LApxRTpmdW5jdGlvbiBxRSgpe30sCkdoOmZ1bmN0
-aW9uIEdoKCl7fSwKZlk6ZnVuY3Rpb24gZlkoKXt9LApuQjpmdW5jdGlvbiBuQigpe30sCkF6OmZ1bmN0
-aW9uIEF6KCl7fSwKUVA6ZnVuY3Rpb24gUVAoKXt9LApueDpmdW5jdGlvbiBueCgpe30sCm9KOmZ1bmN0
-aW9uIG9KKCl7fSwKaWQ6ZnVuY3Rpb24gaWQoKXt9LApRRjpmdW5jdGlvbiBRRigpe30sCk5oOmZ1bmN0
-aW9uIE5oKCl7fSwKSUI6ZnVuY3Rpb24gSUIoKXt9LApuNzpmdW5jdGlvbiBuNygpe30sCnd6OmZ1bmN0
-aW9uIHd6KGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9Yn0sCmN2OmZ1bmN0aW9uIGN2KCl7fSwKQ3Y6ZnVu
-Y3Rpb24gQ3YoKXt9LAplYTpmdW5jdGlvbiBlYSgpe30sCkQwOmZ1bmN0aW9uIEQwKCl7fSwKaEg6ZnVu
-Y3Rpb24gaEgoKXt9LApoNDpmdW5jdGlvbiBoNCgpe30sCmJyOmZ1bmN0aW9uIGJyKCl7fSwKVmI6ZnVu
-Y3Rpb24gVmIoKXt9LApPNzpmdW5jdGlvbiBPNygpe30sCndhOmZ1bmN0aW9uIHdhKCl7fSwKU2c6ZnVu
-Y3Rpb24gU2coKXt9LAp1ODpmdW5jdGlvbiB1OCgpe30sCkFqOmZ1bmN0aW9uIEFqKCl7fSwKZTc6ZnVu
-Y3Rpb24gZTcoYSl7dGhpcy5hPWF9LAp1SDpmdW5jdGlvbiB1SCgpe30sCkJIOmZ1bmN0aW9uIEJIKCl7
-fSwKU046ZnVuY3Rpb24gU04oKXt9LApldzpmdW5jdGlvbiBldygpe30sCmxwOmZ1bmN0aW9uIGxwKCl7
-fSwKVGI6ZnVuY3Rpb24gVGIoKXt9LApJdjpmdW5jdGlvbiBJdigpe30sCldQOmZ1bmN0aW9uIFdQKCl7
-fSwKeVk6ZnVuY3Rpb24geVkoKXt9LAp3NjpmdW5jdGlvbiB3Nigpe30sCks1OmZ1bmN0aW9uIEs1KCl7
-fSwKQ206ZnVuY3Rpb24gQ20oKXt9LApDUTpmdW5jdGlvbiBDUSgpe30sCnc0OmZ1bmN0aW9uIHc0KCl7
-fSwKcmg6ZnVuY3Rpb24gcmgoKXt9LApjZjpmdW5jdGlvbiBjZigpe30sCmk3OmZ1bmN0aW9uIGk3KGEp
-e3RoaXMuYT1hfSwKU3k6ZnVuY3Rpb24gU3koYSl7dGhpcy5hPWF9LApLUzpmdW5jdGlvbiBLUyhhLGIp
-e3RoaXMuYT1hCnRoaXMuYj1ifSwKQTM6ZnVuY3Rpb24gQTMoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0s
-Ckk0OmZ1bmN0aW9uIEk0KGEpe3RoaXMuYT1hfSwKRms6ZnVuY3Rpb24gRmsoYSxiKXt0aGlzLmE9YQp0
-aGlzLiR0aT1ifSwKUk86ZnVuY3Rpb24gUk8oYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9Ygpf
-LmM9YwpfLiR0aT1kfSwKZXU6ZnVuY3Rpb24gZXUoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9
-YgpfLmM9YwpfLiR0aT1kfSwKeEM6ZnVuY3Rpb24geEMoYSxiLGMsZCxlKXt2YXIgXz10aGlzCl8uYj1h
-Cl8uYz1iCl8uZD1jCl8uZT1kCl8uJHRpPWV9LAp2TjpmdW5jdGlvbiB2TihhKXt0aGlzLmE9YX0sCkpR
-OmZ1bmN0aW9uIEpRKGEpe3RoaXMuYT1hfSwKR206ZnVuY3Rpb24gR20oKXt9LAp2RDpmdW5jdGlvbiB2
-RChhKXt0aGlzLmE9YX0sClV2OmZ1bmN0aW9uIFV2KGEpe3RoaXMuYT1hfSwKRWc6ZnVuY3Rpb24gRWco
-YSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKbTY6ZnVuY3Rpb24gbTYoKXt9LApFbzpm
-dW5jdGlvbiBFbygpe30sCldrOmZ1bmN0aW9uIFdrKCl7fSwKY3Q6ZnVuY3Rpb24gY3QoYSxiLGMsZCxl
-KXt2YXIgXz10aGlzCl8uZT1hCl8uYT1iCl8uYj1jCl8uYz1kCl8uZD1lfSwKSUE6ZnVuY3Rpb24gSUEo
-KXt9LApPdzpmdW5jdGlvbiBPdygpe30sClc5OmZ1bmN0aW9uIFc5KGEsYixjKXt2YXIgXz10aGlzCl8u
-YT1hCl8uYj1iCl8uYz0tMQpfLmQ9bnVsbApfLiR0aT1jfSwKZFc6ZnVuY3Rpb24gZFcoYSl7dGhpcy5h
-PWF9LApGYjpmdW5jdGlvbiBGYigpe30sCmtGOmZ1bmN0aW9uIGtGKCl7fSwKbWs6ZnVuY3Rpb24gbWso
-YSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCktvOmZ1bmN0aW9uIEtvKGEpe3RoaXMuYT1hfSwKZm06ZnVu
-Y3Rpb24gZm0oYSl7dGhpcy5hPWF9LApMZTpmdW5jdGlvbiBMZSgpe30sCks3OmZ1bmN0aW9uIEs3KCl7
-fSwKckI6ZnVuY3Rpb24gckIoKXt9LApYVzpmdW5jdGlvbiBYVygpe30sCm9hOmZ1bmN0aW9uIG9hKCl7
-fX0sTT17Ck9YOmZ1bmN0aW9uKGEpe3N3aXRjaChhKXtjYXNlIEMuQWQ6cmV0dXJuIkFkZCAvKj8qLyBo
-aW50IgpjYXNlIEMubmU6cmV0dXJuIkFkZCAvKiEqLyBoaW50IgpjYXNlIEMud1Y6cmV0dXJuIlJlbW92
-ZSAvKj8qLyBoaW50IgpjYXNlIEMuZlI6cmV0dXJuIlJlbW92ZSAvKiEqLyBoaW50IgpjYXNlIEMubXk6
-cmV0dXJuIkNoYW5nZSB0byAvKj8qLyBoaW50IgpjYXNlIEMucng6cmV0dXJuIkNoYW5nZSB0byAvKiEq
-LyBoaW50In1yZXR1cm4gbnVsbH0sCkg3OmZ1bmN0aW9uIEg3KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9
-LApZRjpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbyxuCmZvcih0PWIubGVuZ3RoLHM9MTtzPHQ7
-KytzKXtpZihiW3NdPT1udWxsfHxiW3MtMV0hPW51bGwpY29udGludWUKZm9yKDt0Pj0xO3Q9cil7cj10
-LTEKaWYoYltyXSE9bnVsbClicmVha31xPW5ldyBQLlJuKCIiKQpwPWErIigiCnEuYT1wCm89SC5xQyhi
-LDAsdCxILnQ2KGIpLmQpCm49by4kdGkKbj1wK25ldyBILkE4KG8sbi5DKCJxVShhTC5FKSIpLmIobmV3
-IE0uTm8oKSksbi5DKCJBODxhTC5FLHFVPiIpKS5IKDAsIiwgIikKcS5hPW4KcS5hPW4rKCIpOiBwYXJ0
-ICIrKHMtMSkrIiB3YXMgbnVsbCwgYnV0IHBhcnQgIitzKyIgd2FzIG5vdC4iKQp0aHJvdyBILmIoUC54
-WShxLncoMCkpKX19LApsSTpmdW5jdGlvbiBsSShhKXt0aGlzLmE9YX0sCk1pOmZ1bmN0aW9uIE1pKCl7
-fSwKcTc6ZnVuY3Rpb24gcTcoKXt9LApObzpmdW5jdGlvbiBObygpe319LFU9ewpuejpmdW5jdGlvbihh
-KXt2YXIgdD1ILldZKGEucSgwLCJub2RlSWQiKSkKcmV0dXJuIG5ldyBVLkxMKEMuTm0uSHQoQy5yayxu
-ZXcgVS5NRChhKSksdCl9LApMTDpmdW5jdGlvbiBMTChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKTUQ6
-ZnVuY3Rpb24gTUQoYSl7dGhpcy5hPWF9LApqZjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscQppZihhPT1u
-dWxsKXQ9bnVsbAplbHNle3Q9SC5WTShbXSx1LmZBKQpmb3Iocz1KLklUKHUuUi5iKGEpKTtzLkYoKTsp
-e3I9cy5nbCgpCnE9Si5VNihyKQpDLk5tLmkodCxuZXcgVS5TZShILmMwKHEucShyLCJkZXNjcmlwdGlv
-biIpKSxILmMwKHEucShyLCJocmVmIikpKSl9fXJldHVybiB0fSwKTmQ6ZnVuY3Rpb24oYSl7dmFyIHQs
-cwppZihhPT1udWxsKXQ9bnVsbAplbHNle3Q9SC5WTShbXSx1LmhoKQpmb3Iocz1KLklUKHUuUi5iKGEp
-KTtzLkYoKTspQy5ObS5pKHQsVS5OZihzLmdsKCkpKX1yZXR1cm4gdH0sCk5mOmZ1bmN0aW9uKGEpe3Zh
-ciB0PUouVTYoYSkscz1ILmMwKHQucShhLCJkZXNjcmlwdGlvbiIpKSxyPUguVk0oW10sdS5hSikKZm9y
-KHQ9Si5JVCh1LlIuYih0LnEoYSwiZW50cmllcyIpKSk7dC5GKCk7KUMuTm0uaShyLFUuUmoodC5nbCgp
-KSkKcmV0dXJuIG5ldyBVLnlEKHMscil9LApSajpmdW5jdGlvbihhKXt2YXIgdCxzPUouVTYoYSkscj1I
-LmMwKHMucShhLCJkZXNjcmlwdGlvbiIpKSxxPUguYzAocy5xKGEsImZ1bmN0aW9uIikpLHA9cy5xKGEs
-ImxpbmsiKQppZihwPT1udWxsKXA9bnVsbAplbHNle3Q9Si5VNihwKQpwPW5ldyBVLk1sKEguYzAodC5x
-KHAsImhyZWYiKSksSC5XWSh0LnEocCwibGluZSIpKSxILmMwKHQucShwLCJwYXRoIikpKX1zPXUuai5h
-KHMucShhLCJoaW50QWN0aW9ucyIpKQpzPXM9PW51bGw/bnVsbDpKLk0xKHMsbmV3IFUuYU4oKSx1LkQp
-CnM9cz09bnVsbD9udWxsOnMuYnIoMCkKcmV0dXJuIG5ldyBVLndiKHIscSxwLHM9PW51bGw/Qy5kbjpz
-KX0sCmQyOmZ1bmN0aW9uIGQyKGEsYixjLGQsZSxmKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1j
-Cl8uZD1kCl8uZT1lCl8uZj1mfSwKU2U6ZnVuY3Rpb24gU2UoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0s
-Ck1sOmZ1bmN0aW9uIE1sKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCnlEOmZ1bmN0
-aW9uIHlEKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAp3YjpmdW5jdGlvbiB3YihhLGIsYyxkKXt2YXIg
-Xz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1kfSwKYU46ZnVuY3Rpb24gYU4oKXt9LApiMDpmdW5j
-dGlvbiBiMCgpe319LEI9ewpZZjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGw9SC5jMChh
-LnEoMCwicmVnaW9ucyIpKSxrPUguYzAoYS5xKDAsIm5hdmlnYXRpb25Db250ZW50IikpLGo9SC5jMChh
-LnEoMCwic291cmNlQ29kZSIpKSxpPVAuRmwodS5OLHUuZjQpCmZvcih0PXUuUy5hKGEucSgwLCJlZGl0
-cyIpKSx0PXQuZ1B1KHQpLHQ9dC5na3oodCkscz11LlIscj11LmdpO3QuRigpOyl7cT10LmdsKCkKcD1x
-LmEKbz1ILlZNKFtdLHIpCmZvcihxPUouSVQocy5iKHEuYikpO3EuRigpOyl7bj1xLmdsKCkKbT1KLlU2
-KG4pCkMuTm0uaShvLG5ldyBCLmo4KEguV1kobS5xKG4sImxpbmUiKSksSC5jMChtLnEobiwiZXhwbGFu
-YXRpb24iKSksSC5XWShtLnEobiwib2Zmc2V0IikpKSl9aS5ZKDAscCxvKX1yZXR1cm4gbmV3IEIucXAo
-bCxrLGosaSl9LApqODpmdW5jdGlvbiBqOChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9
-LApxcDpmdW5jdGlvbiBxcChhLGIsYyxkKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1k
-fSwKZnY6ZnVuY3Rpb24gZnYoKXt9LApPUzpmdW5jdGlvbihhKXt2YXIgdAppZighKGE+PTY1JiZhPD05
-MCkpdD1hPj05NyYmYTw9MTIyCmVsc2UgdD0hMApyZXR1cm4gdH0sCll1OmZ1bmN0aW9uKGEsYil7dmFy
-IHQ9YS5sZW5ndGgscz1iKzIKaWYodDxzKXJldHVybiExCmlmKCFCLk9TKEMueEIubShhLGIpKSlyZXR1
-cm4hMQppZihDLnhCLm0oYSxiKzEpIT09NTgpcmV0dXJuITEKaWYodD09PXMpcmV0dXJuITAKcmV0dXJu
-IEMueEIubShhLHMpPT09NDd9fSxUPXttUTpmdW5jdGlvbiBtUSgpe319LEw9ewpJcTpmdW5jdGlvbigp
-e0MuQlouQihkb2N1bWVudCwiRE9NQ29udGVudExvYWRlZCIsbmV3IEwuZSgpKQpDLm9sLkIod2luZG93
-LCJwb3BzdGF0ZSIsbmV3IEwuTCgpKX0sCmt6OmZ1bmN0aW9uKGEpe3ZhciB0LHM9dS5oLmEoYS5wYXJl
-bnROb2RlKS5xdWVyeVNlbGVjdG9yKCI6c2NvcGUgPiB1bCIpLHI9cy5zdHlsZSxxPSIiK0MuQ0QuelEo
-cy5vZmZzZXRIZWlnaHQpKjIrInB4IgpyLm1heEhlaWdodD1xCnI9Si5xRihhKQpxPXIuJHRpCnQ9cS5D
-KCJ+KDEpIikuYihuZXcgTC5XeChzLGEpKQp1Lk0uYihudWxsKQpXLkpFKHIuYSxyLmIsdCwhMSxxLmQp
-fSwKeVg6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG89InF1ZXJ5U2VsZWN0b3JBbGwiLG49ZG9j
-dW1lbnQucXVlcnlTZWxlY3RvcihhKSxtPXUuaApuLnRvU3RyaW5nCkguRGgobSxtLCJUIixvKQp0PXUu
-VApzPW5ldyBXLnd6KG4ucXVlcnlTZWxlY3RvckFsbCgiLm5hdi1saW5rIiksdCkKcy5LKHMsbmV3IEwu
-QU8oYikpCkguRGgobSxtLCJUIixvKQpyPW5ldyBXLnd6KG4ucXVlcnlTZWxlY3RvckFsbCgiLnJlZ2lv
-biIpLHQpCmlmKHIuZ0EocikhPT0wKXtxPW4ucXVlcnlTZWxlY3RvcigidGFibGVbZGF0YS1wYXRoXSIp
-CnEudG9TdHJpbmcKci5LKHIsbmV3IEwuSG8ocS5nZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5TeShu
-ZXcgVy5pNyhxKSkuTygicGF0aCIpKSkpfUguRGgobSxtLCJUIixvKQpwPW5ldyBXLnd6KG4ucXVlcnlT
-ZWxlY3RvckFsbCgiLmFkZC1oaW50LWxpbmsiKSx0KQpwLksocCxuZXcgTC5JQygpKX0sClE2OmZ1bmN0
-aW9uKGEsYixjKXt2YXIgdD1uZXcgWE1MSHR0cFJlcXVlc3QoKQpDLkR0LmVvKHQsIkdFVCIsTC5RNChh
-LGIpLCEwKQp0LnNldFJlcXVlc3RIZWFkZXIoIkNvbnRlbnQtVHlwZSIsImFwcGxpY2F0aW9uL2pzb247
-IGNoYXJzZXQ9VVRGLTgiKQpyZXR1cm4gTC5MVSh0LG51bGwsYyl9LAp0eTpmdW5jdGlvbihhLGIpe3Zh
-ciB0PW5ldyBYTUxIdHRwUmVxdWVzdCgpLHM9dS5OCkMuRHQuZW8odCwiUE9TVCIsTC5RNChhLFAuRmwo
-cyxzKSksITApCnQuc2V0UmVxdWVzdEhlYWRlcigiQ29udGVudC1UeXBlIiwiYXBwbGljYXRpb24vanNv
-bjsgY2hhcnNldD1VVEYtOCIpCnJldHVybiBMLkxVKHQsYix1LlMpfSwKTFU6ZnVuY3Rpb24oYSxiLGMp
-e3JldHVybiBMLlRnKGEsYixjLGMpfSwKVGc6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQ9MCxzPVAuRlgo
-ZCkscixxPTIscCxvPVtdLG4sbSxsLGssaixpLGgsZwp2YXIgJGFzeW5jJExVPVAubHooZnVuY3Rpb24o
-ZSxmKXtpZihlPT09MSl7cD1mCnQ9cX13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6aj1uZXcgUC5a
-ZihuZXcgUC52cygkLlgzLHUuYW8pLHUuYmopCmk9dS5hbgpoPWkuYihuZXcgTC5mQyhqLGEpKQp1Lk0u
-YihudWxsKQptPXUucApXLkpFKGEsImxvYWQiLGgsITEsbSkKVy5KRShhLCJlcnJvciIsaS5iKGouZ1lK
-KCkpLCExLG0pCmEuc2VuZChiPT1udWxsP251bGw6Qy5DdC5PQihiLG51bGwpKQpxPTQKdD03CnJldHVy
-biBQLmpRKGouYSwkYXN5bmMkTFUpCmNhc2UgNzpxPTIKdD02CmJyZWFrCmNhc2UgNDpxPTMKZz1wCkgu
-UnUoZykKbj1ILnRzKGcpCmk9UC5UbCgiRXJyb3IgcmVhY2hpbmcgbWlncmF0aW9uIHByZXZpZXcgc2Vy
-dmVyLiIsbikKdGhyb3cgSC5iKGkpCnQ9NgpicmVhawpjYXNlIDM6dD0yCmJyZWFrCmNhc2UgNjprPUMu
-Q3QucFcoMCxhLnJlc3BvbnNlVGV4dCxudWxsKQppZihhLnN0YXR1cz09PTIwMCl7cj1jLmEoaykKdD0x
-CmJyZWFrfWVsc2UgdGhyb3cgSC5iKGspCmNhc2UgMTpyZXR1cm4gUC55QyhyLHMpCmNhc2UgMjpyZXR1
-cm4gUC5mMyhwLHMpfX0pCnJldHVybiBQLkRJKCRhc3luYyRMVSxzKX0sCmFLOmZ1bmN0aW9uKGEpe3Zh
-ciB0PVAuaEsoYSkuZ2hZKCkucSgwLCJsaW5lIikKcmV0dXJuIHQ9PW51bGw/bnVsbDpILkhwKHQsbnVs
-bCl9LApHNjpmdW5jdGlvbihhKXt2YXIgdD1QLmhLKGEpLmdoWSgpLnEoMCwib2Zmc2V0IikKcmV0dXJu
-IHQ9PW51bGw/bnVsbDpILkhwKHQsbnVsbCl9LAppNjpmdW5jdGlvbihhKXtyZXR1cm4gTC5uVyh1LlYu
-YihhKSl9LApuVzpmdW5jdGlvbihhKXt2YXIgdD0wLHM9UC5GWCh1LnopLHI9MSxxLHA9W10sbyxuLG0s
-bCxrCnZhciAkYXN5bmMkaTY9UC5seihmdW5jdGlvbihiLGMpe2lmKGI9PT0xKXtxPWMKdD1yfXdoaWxl
-KHRydWUpc3dpdGNoKHQpe2Nhc2UgMDpsPXUuaC5hKFcucWMoYS5jdXJyZW50VGFyZ2V0KSkuZ2V0QXR0
-cmlidXRlKCJocmVmIikKYS5wcmV2ZW50RGVmYXVsdCgpCnI9Mwp0PTYKcmV0dXJuIFAualEoTC50eShs
-LG51bGwpLCRhc3luYyRpNikKY2FzZSA2OnUuYV8uYShKLkdyKFcudVYoZG9jdW1lbnQuZGVmYXVsdFZp
-ZXcpKSkucmVsb2FkKCkKcj0xCnQ9NQpicmVhawpjYXNlIDM6cj0yCms9cQpvPUguUnUoaykKbj1ILnRz
-KGspCkwuQzIoIkNvdWxkIG5vdCBhZGQvcmVtb3ZlIGhpbnQiLG8sbikKdD01CmJyZWFrCmNhc2UgMjp0
-PTEKYnJlYWsKY2FzZSA1OnJldHVybiBQLnlDKG51bGwscykKY2FzZSAxOnJldHVybiBQLmYzKHEscyl9
-fSkKcmV0dXJuIFAuREkoJGFzeW5jJGk2LHMpfSwKQzI6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscj0i
-ZXhjZXB0aW9uIixxPSJzdGFja1RyYWNlIixwPXUuUy5jKGIpJiZKLlJNKGIucSgwLCJzdWNjZXNzIiks
-ITEpJiZILm9UKGIueDQocikpJiZILm9UKGIueDQocSkpLG89Si5pYShiKQppZihwKXt0PUguYzAoby5x
-KGIscikpCmM9by5xKGIscSl9ZWxzZSB0PW8udyhiKQpwPWRvY3VtZW50CnM9cC5xdWVyeVNlbGVjdG9y
-KCIucG9wdXAtcGFuZSIpCnMucXVlcnlTZWxlY3RvcigiaDIiKS5pbm5lclRleHQ9YQpzLnF1ZXJ5U2Vs
-ZWN0b3IoInAiKS5pbm5lclRleHQ9dApzLnF1ZXJ5U2VsZWN0b3IoInByZSIpLmlubmVyVGV4dD1KLmoo
-YykKbz11Lk4KdS5icS5hKHMucXVlcnlTZWxlY3RvcigiYS5ib3R0b20iKSkuaHJlZj1QLlhkKCJodHRw
-cyIsImdpdGh1Yi5jb20iLCJkYXJ0LWxhbmcvc2RrL2lzc3Vlcy9uZXciLFAuRUYoWyJ0aXRsZSIsIkN1
-c3RvbWVyLXJlcG9ydGVkIGlzc3VlIHdpdGggTk5CRCBtaWdyYXRpb24gdG9vbDogIithLCJsYWJlbHMi
-LCJhcmVhLWFuYWx5emVyLGFuYWx5emVyLW5uYmQtbWlncmF0aW9uLHR5cGUtYnVnIiwiYm9keSIsYSsi
-XG5cbkVycm9yOiAiK0guZCh0KSsiXG5cblBsZWFzZSBmaWxsIGluIHRoZSBmb2xsb3dpbmc6XG5cbioq
-TmFtZSBvZiBwYWNrYWdlIGJlaW5nIG1pZ3JhdGVkIChpZiBwdWJsaWMpKio6XG4qKldoYXQgSSB3YXMg
-ZG9pbmcgd2hlbiB0aGlzIGlzc3VlIG9jY3VycmVkKio6XG4qKklzIGl0IHBvc3NpYmxlIHRvIHdvcmsg
-YXJvdW5kIHRoaXMgaXNzdWUqKjpcbioqSGFzIHRoaXMgaXNzdWUgaGFwcGVuZWQgYmVmb3JlLCBhbmQg
-aWYgc28sIGhvdyBvZnRlbioqOlxuKipEYXJ0IFNESyB2ZXJzaW9uKio6ICIrSC5kKHAuZ2V0RWxlbWVu
-dEJ5SWQoInNkay12ZXJzaW9uIikudGV4dENvbnRlbnQpKyJcbioqQWRkaXRpb25hbCBkZXRhaWxzKio6
-XG5cblRoYW5rcyBmb3IgZmlsaW5nIVxuXG5TdGFja3RyYWNlOiBfYXV0byBwb3B1bGF0ZWQgYnkgbWln
-cmF0aW9uIHByZXZpZXcgdG9vbC5fXG5cbmBgYFxuIitILmQoYykrIlxuYGBgXG4iXSxvLG8pKS53KDAp
-Cm89cy5zdHlsZQpvLmRpc3BsYXk9ImluaXRpYWwiCnA9YSsiOiAiK0guZChiKQp3aW5kb3cKaWYodHlw
-ZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLmVycm9yKHApCndpbmRvdwpwPUgu
-ZChjKQppZih0eXBlb2YgY29uc29sZSE9InVuZGVmaW5lZCIpd2luZG93LmNvbnNvbGUuZXJyb3IocCl9
-LAp0MjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscD17fSxvPXUuaC5hKFcucWMoYS5jdXJyZW50
-VGFyZ2V0KSkKYS5wcmV2ZW50RGVmYXVsdCgpCnQ9cC5hPW8uZ2V0QXR0cmlidXRlKCJocmVmIikKcz1K
-LnpsKHQsIj8iKT9wLmE9Qy54Qi5Oaih0LDAsQy54Qi5PWSh0LCI/IikpOnQKcj1MLkc2KHQpCnE9TC5h
-Syh0KQppZihyIT1udWxsKUwuYWYocyxyLHEsYixuZXcgTC5uVChwLHIscSkpCmVsc2UgTC5hZihzLG51
-bGwsbnVsbCxiLG5ldyBMLkJaKHApKX0sCnZVOmZ1bmN0aW9uKCl7dmFyIHQ9ZG9jdW1lbnQscz11LmgK
-SC5EaChzLHMsIlQiLCJxdWVyeVNlbGVjdG9yQWxsIikKdD1uZXcgVy53eih0LnF1ZXJ5U2VsZWN0b3JB
-bGwoIi5jb2RlIiksdS5UKQp0LksodCxuZXcgTC5HSCgpKX0sCmhYOmZ1bmN0aW9uKGEsYixjKXtyZXR1
-cm4gTC5ZdyhhLGIsYyl9LApZdzpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9MCxzPVAuRlgodS56KSxyPTEs
-cSxwPVtdLG8sbixtLGwsayxqLGksaAp2YXIgJGFzeW5jJGhYPVAubHooZnVuY3Rpb24oZCxlKXtpZihk
-PT09MSl7cT1lCnQ9cn13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6cj0zCms9dS5OCnQ9NgpyZXR1
-cm4gUC5qUShMLlE2KGEsUC5FRihbInJlZ2lvbiIsInJlZ2lvbiIsIm9mZnNldCIsSC5kKGIpXSxrLGsp
-LHUuUyksJGFzeW5jJGhYKQpjYXNlIDY6bz1lCms9bwpqPUouVTYoaykKbj1uZXcgVS5kMihVLmpmKGou
-cShrLCJlZGl0cyIpKSxILmMwKGoucShrLCJleHBsYW5hdGlvbiIpKSxILldZKGoucShrLCJsaW5lIikp
-LEguYzAoai5xKGssImRpc3BsYXlQYXRoIikpLEguYzAoai5xKGssInVyaVBhdGgiKSksVS5OZChqLnEo
+YSBpbnN0YW5jZW9mIFAuTWgpcmV0dXJuIGEKcmV0dXJuIEoua3MoYSl9LApyWTpmdW5jdGlvbihhKXtp
+Zih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJuIEouRHIucHJvdG90eXBlCmlmKGE9PW51bGwpcmV0dXJu
+IGEKaWYoIShhIGluc3RhbmNlb2YgUC5NaCkpcmV0dXJuIEoua2QucHJvdG90eXBlCnJldHVybiBhfSwK
+dzE6ZnVuY3Rpb24oYSl7aWYoYT09bnVsbClyZXR1cm4gYQppZihhLmNvbnN0cnVjdG9yPT1BcnJheSly
+ZXR1cm4gSi5qZC5wcm90b3R5cGUKaWYodHlwZW9mIGEhPSJvYmplY3QiKXtpZih0eXBlb2YgYT09ImZ1
+bmN0aW9uIilyZXR1cm4gSi5jNS5wcm90b3R5cGUKcmV0dXJuIGF9aWYoYSBpbnN0YW5jZW9mIFAuTWgp
+cmV0dXJuIGEKcmV0dXJuIEoua3MoYSl9LApBYzpmdW5jdGlvbihhKXtyZXR1cm4gSi5pYShhKS5aKGEp
+fSwKQ006ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIEouUkUoYSkuZHUoYSxiLGMsZCl9LApDaTpmdW5j
+dGlvbihhKXtyZXR1cm4gSi5VNihhKS5nbDAoYSl9LApGTDpmdW5jdGlvbihhLGIpe3JldHVybiBKLnJZ
+KGEpLmRkKGEsYil9LApHQTpmdW5jdGlvbihhLGIpe3JldHVybiBKLncxKGEpLkUoYSxiKX0sCkdyOmZ1
+bmN0aW9uKGEpe3JldHVybiBKLlJFKGEpLmdtVyhhKX0sCkg6ZnVuY3Rpb24oYSl7cmV0dXJuIEouVTYo
+YSkuZ0EoYSl9LApJVDpmdW5jdGlvbihhKXtyZXR1cm4gSi53MShhKS5na3ooYSl9LApKeTpmdW5jdGlv
+bihhLGIpe3JldHVybiBKLmlhKGEpLmU3KGEsYil9LApLVjpmdW5jdGlvbihhLGIpe3JldHVybiBKLnJZ
+KGEpLkcoYSxiKX0sCkx0OmZ1bmN0aW9uKGEpe3JldHVybiBKLlJFKGEpLndnKGEpfSwKTTE6ZnVuY3Rp
+b24oYSxiLGMpe3JldHVybiBKLncxKGEpLkUyKGEsYixjKX0sCk11OmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IEouUkUoYSkuc1AoYSxiKX0sClF6OmZ1bmN0aW9uKGEsYil7cmV0dXJuIEouclkoYSkuVyhhLGIpfSwK
+Uk06ZnVuY3Rpb24oYSxiKXtpZihhPT1udWxsKXJldHVybiBiPT1udWxsCmlmKHR5cGVvZiBhIT0ib2Jq
+ZWN0IilyZXR1cm4gYiE9bnVsbCYmYT09PWIKcmV0dXJuIEouaWEoYSkuRE4oYSxiKX0sClQwOmZ1bmN0
+aW9uKGEpe3JldHVybiBKLnJZKGEpLmJTKGEpfSwKYTY6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gSi5yWShh
+KS5tKGEsYil9LApiVDpmdW5jdGlvbihhKXtyZXR1cm4gSi5SRShhKS5ENChhKX0sCmNIOmZ1bmN0aW9u
+KGEpe3JldHVybiBKLnJZKGEpLmhjKGEpfSwKZFI6ZnVuY3Rpb24oYSl7cmV0dXJuIEouUkUoYSkuZ1Ao
+YSl9LApkWjpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gSi5SRShhKS5PbihhLGIsYyxkKX0sCmRnOmZ1
+bmN0aW9uKGEsYixjLGQpe3JldHVybiBKLnJZKGEpLmk3KGEsYixjLGQpfSwKZGg6ZnVuY3Rpb24oYSl7
+cmV0dXJuIEouUkUoYSkuRkYoYSl9LApoZjpmdW5jdGlvbihhKXtyZXR1cm4gSi5pYShhKS5naU8oYSl9
+LAppZzpmdW5jdGlvbihhKXtyZXR1cm4gSi5SRShhKS5nUWcoYSl9LApsNTpmdW5jdGlvbihhLGIpe3Jl
+dHVybiBKLlJFKGEpLnNoZihhLGIpfSwKbGQ6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBKLnJZKGEpLk5q
+KGEsYixjKX0sCm06ZnVuY3Rpb24oYSxiKXtpZih0eXBlb2YgYT09Im51bWJlciImJnR5cGVvZiBiPT0i
+bnVtYmVyIilyZXR1cm4gYStiCnJldHVybiBKLlRKKGEpLmgoYSxiKX0sCnEwOmZ1bmN0aW9uKGEsYixj
+KXtyZXR1cm4gSi5yWShhKS5RaShhLGIsYyl9LApxRjpmdW5jdGlvbihhKXtyZXR1cm4gSi5SRShhKS5n
+VmwoYSl9LAp0SDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIEouUkUoYSkucGsoYSxiLGMpfSwKeDk6ZnVu
+Y3Rpb24oYSxiKXtpZih0eXBlb2YgYj09PSJudW1iZXIiKWlmKGEuY29uc3RydWN0b3I9PUFycmF5fHx0
+eXBlb2YgYT09InN0cmluZyJ8fEgud1YoYSxhW3YuZGlzcGF0Y2hQcm9wZXJ0eU5hbWVdKSlpZihiPj4+
+MD09PWImJmI8YS5sZW5ndGgpcmV0dXJuIGFbYl0KcmV0dXJuIEouVTYoYSkucShhLGIpfSwKemw6ZnVu
+Y3Rpb24oYSxiKXtyZXR1cm4gSi5VNihhKS50ZyhhLGIpfSwKdkI6ZnVuY3Rpb24gdkIoKXt9LAp5RTpm
+dW5jdGlvbiB5RSgpe30sCllFOmZ1bmN0aW9uIFlFKCl7fSwKTUY6ZnVuY3Rpb24gTUYoKXt9LAppQzpm
+dW5jdGlvbiBpQygpe30sCmtkOmZ1bmN0aW9uIGtkKCl7fSwKYzU6ZnVuY3Rpb24gYzUoKXt9LApqZDpm
+dW5jdGlvbiBqZChhKXt0aGlzLiR0aT1hfSwKUG86ZnVuY3Rpb24gUG8oYSl7dGhpcy4kdGk9YX0sCm0x
+OmZ1bmN0aW9uIG0xKGEsYixjKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz0wCl8uZD1udWxsCl8u
+JHRpPWN9LApxSTpmdW5jdGlvbiBxSSgpe30sCmJVOmZ1bmN0aW9uIGJVKCl7fSwKVkE6ZnVuY3Rpb24g
+VkEoKXt9LApEcjpmdW5jdGlvbiBEcigpe319LFA9ewpPajpmdW5jdGlvbigpe3ZhciB0LHMscj17fQpp
+ZihzZWxmLnNjaGVkdWxlSW1tZWRpYXRlIT1udWxsKXJldHVybiBQLkVYKCkKaWYoc2VsZi5NdXRhdGlv
+bk9ic2VydmVyIT1udWxsJiZzZWxmLmRvY3VtZW50IT1udWxsKXt0PXNlbGYuZG9jdW1lbnQuY3JlYXRl
+RWxlbWVudCgiZGl2IikKcz1zZWxmLmRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInNwYW4iKQpyLmE9bnVs
+bApuZXcgc2VsZi5NdXRhdGlvbk9ic2VydmVyKEgudFIobmV3IFAudGgociksMSkpLm9ic2VydmUodCx7
+Y2hpbGRMaXN0OnRydWV9KQpyZXR1cm4gbmV3IFAuaGEocix0LHMpfWVsc2UgaWYoc2VsZi5zZXRJbW1l
+ZGlhdGUhPW51bGwpcmV0dXJuIFAueXQoKQpyZXR1cm4gUC5xVygpfSwKWlY6ZnVuY3Rpb24oYSl7c2Vs
+Zi5zY2hlZHVsZUltbWVkaWF0ZShILnRSKG5ldyBQLlZzKHUuTS5hKGEpKSwwKSl9LApvQTpmdW5jdGlv
+bihhKXtzZWxmLnNldEltbWVkaWF0ZShILnRSKG5ldyBQLkZ0KHUuTS5hKGEpKSwwKSl9LApCejpmdW5j
+dGlvbihhKXt1Lk0uYShhKQpQLlFOKDAsYSl9LApRTjpmdW5jdGlvbihhLGIpe3ZhciB0PW5ldyBQLlcz
+KCkKdC5DWShhLGIpCnJldHVybiB0fSwKRlg6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLmloKG5ldyBQ
+LnZzKCQuWDMsYS5DKCJ2czwwPiIpKSxhLkMoImloPDA+IikpfSwKREk6ZnVuY3Rpb24oYSxiKXthLiQy
+KDAsbnVsbCkKYi5iPSEwCnJldHVybiBiLmF9LApqUTpmdW5jdGlvbihhLGIpe1AuSmUoYSxiKX0sCnlD
+OmZ1bmN0aW9uKGEsYil7Yi5hTSgwLGEpfSwKZjM6ZnVuY3Rpb24oYSxiKXtiLncwKEguUnUoYSksSC50
+cyhhKSl9LApKZTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj1uZXcgUC5XTShiKSxxPW5ldyBQLlNYKGIp
+CmlmKGEgaW5zdGFuY2VvZiBQLnZzKWEuUWQocixxLHUueikKZWxzZXt0PXUuegppZih1LmMuYihhKSlh
+LlNxKHIscSx0KQplbHNle3M9bmV3IFAudnMoJC5YMyx1Ll8pCnMuYT00CnMuYz1hCnMuUWQocixxLHQp
+fX19LApsejpmdW5jdGlvbihhKXt2YXIgdD1mdW5jdGlvbihiLGMpe3JldHVybiBmdW5jdGlvbihkLGUp
+e3doaWxlKHRydWUpdHJ5e2IoZCxlKQpicmVha31jYXRjaChzKXtlPXMKZD1jfX19KGEsMSkKcmV0dXJu
+ICQuWDMuTGoobmV3IFAuR3ModCksdS5QLHUucCx1LnopfSwKR1E6ZnVuY3Rpb24oYSl7cmV0dXJuIG5l
+dyBQLkZ5KGEsMSl9LApUaDpmdW5jdGlvbigpe3JldHVybiBDLndRfSwKWW06ZnVuY3Rpb24oYSl7cmV0
+dXJuIG5ldyBQLkZ5KGEsMyl9LApsMDpmdW5jdGlvbihhLGIpe3JldHVybiBuZXcgUC5xNChhLGIuQygi
+cTQ8MD4iKSl9LAprMzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscgpiLmE9MQp0cnl7YS5TcShuZXcgUC5w
+VihiKSxuZXcgUC5VNyhiKSx1LlApfWNhdGNoKHIpe3Q9SC5SdShyKQpzPUgudHMocikKUC5yYihuZXcg
+UC52cihiLHQscykpfX0sCkE5OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCmZvcih0PXUuXztzPWEuYSxz
+PT09MjspYT10LmEoYS5jKQppZihzPj00KXtyPWIuYWgoKQpiLmE9YS5hCmIuYz1hLmMKUC5IWihiLHIp
+fWVsc2V7cj11LnguYShiLmMpCmIuYT0yCmIuYz1hCmEualEocil9fSwKSFo6ZnVuY3Rpb24oYSxiKXt2
+YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZT1udWxsLGQ9e30sYz1kLmE9YQpmb3IodD11
+Lm4scz11Lngscj11LmM7ITA7KXtxPXt9CnA9Yy5hPT09OAppZihiPT1udWxsKXtpZihwKXtvPXQuYShj
+LmMpClAuTDIoZSxlLGMuYixvLmEsby5iKX1yZXR1cm59Zm9yKDtuPWIuYSxuIT1udWxsO2I9bil7Yi5h
+PW51bGwKUC5IWihkLmEsYil9Yz1kLmEKbT1jLmMKcS5hPXAKcS5iPW0KbD0hcAppZihsKXtrPWIuYwpr
+PShrJjEpIT09MHx8KGsmMTUpPT09OH1lbHNlIGs9ITAKaWYoayl7az1iLmIKaj1rLmIKaWYocCl7aT1j
+LmI9PT1qCmk9IShpfHxpKX1lbHNlIGk9ITEKaWYoaSl7dC5hKG0pClAuTDIoZSxlLGMuYixtLmEsbS5i
+KQpyZXR1cm59aD0kLlgzCmlmKGghPT1qKSQuWDM9agplbHNlIGg9ZQpjPWIuYwppZigoYyYxNSk9PT04
+KW5ldyBQLlJUKGQscSxiLHApLiQwKCkKZWxzZSBpZihsKXtpZigoYyYxKSE9PTApbmV3IFAucnEocSxi
+LG0pLiQwKCl9ZWxzZSBpZigoYyYyKSE9PTApbmV3IFAuUlcoZCxxLGIpLiQwKCkKaWYoaCE9bnVsbCkk
+LlgzPWgKYz1xLmIKaWYoci5iKGMpKXtpZihjLmE+PTQpe2c9cy5hKGsuYykKay5jPW51bGwKYj1rLk44
+KGcpCmsuYT1jLmEKay5jPWMuYwpkLmE9Ywpjb250aW51ZX1lbHNlIFAuQTkoYyxrKQpyZXR1cm59fWY9
+Yi5iCmc9cy5hKGYuYykKZi5jPW51bGwKYj1mLk44KGcpCmM9cS5hCmw9cS5iCmlmKCFjKXtmLiR0aS5j
+LmEobCkKZi5hPTQKZi5jPWx9ZWxzZXt0LmEobCkKZi5hPTgKZi5jPWx9ZC5hPWYKYz1mfX0sClZIOmZ1
+bmN0aW9uKGEsYil7dmFyIHQKaWYodS5hZy5iKGEpKXJldHVybiBiLkxqKGEsdS56LHUuSyx1LmwpCnQ9
+dS5iSQppZih0LmIoYSkpcmV0dXJuIHQuYShhKQp0aHJvdyBILmIoUC5MMyhhLCJvbkVycm9yIiwiRXJy
+b3IgaGFuZGxlciBtdXN0IGFjY2VwdCBvbmUgT2JqZWN0IG9yIG9uZSBPYmplY3QgYW5kIGEgU3RhY2tU
+cmFjZSBhcyBhcmd1bWVudHMsIGFuZCByZXR1cm4gYSBhIHZhbGlkIHJlc3VsdCIpKX0sCnB1OmZ1bmN0
+aW9uKCl7dmFyIHQscwpmb3IoO3Q9JC5TNix0IT1udWxsOyl7JC5tZz1udWxsCnM9dC5iCiQuUzY9cwpp
+ZihzPT1udWxsKSQuazg9bnVsbAp0LmEuJDAoKX19LAplTjpmdW5jdGlvbigpeyQuVUQ9ITAKdHJ5e1Au
+cHUoKX1maW5hbGx5eyQubWc9bnVsbAokLlVEPSExCmlmKCQuUzYhPW51bGwpJC51dCgpLiQxKFAuVjko
+KSl9fSwKZVc6ZnVuY3Rpb24oYSl7dmFyIHQ9bmV3IFAuT00oYSkKaWYoJC5TNj09bnVsbCl7JC5TNj0k
+Lms4PXQKaWYoISQuVUQpJC51dCgpLiQxKFAuVjkoKSl9ZWxzZSAkLms4PSQuazguYj10fSwKclI6ZnVu
+Y3Rpb24oYSl7dmFyIHQscyxyPSQuUzYKaWYocj09bnVsbCl7UC5lVyhhKQokLm1nPSQuazgKcmV0dXJu
+fXQ9bmV3IFAuT00oYSkKcz0kLm1nCmlmKHM9PW51bGwpe3QuYj1yCiQuUzY9JC5tZz10fWVsc2V7dC5i
+PXMuYgokLm1nPXMuYj10CmlmKHQuYj09bnVsbCkkLms4PXR9fSwKcmI6ZnVuY3Rpb24oYSl7dmFyIHQ9
+bnVsbCxzPSQuWDMKaWYoQy5OVT09PXMpe1AuVGsodCx0LEMuTlUsYSkKcmV0dXJufVAuVGsodCx0LHMs
+dS5NLmEocy5HWShhKSkpfSwKUXc6ZnVuY3Rpb24oYSxiKXtpZihhPT1udWxsKUgudmgoUC5FZSgic3Ry
+ZWFtIikpCnJldHVybiBuZXcgUC54SShiLkMoInhJPDA+IikpfSwKVGw6ZnVuY3Rpb24oYSxiKXt2YXIg
+dD1iPT1udWxsP1AudjAoYSk6YgpQLlVJKGEsImVycm9yIix1LkspCnJldHVybiBuZXcgUC5PSChhLHQp
+fSwKdjA6ZnVuY3Rpb24oYSl7dmFyIHQKaWYodS5XLmIoYSkpe3Q9YS5nSUkoKQppZih0IT1udWxsKXJl
+dHVybiB0fXJldHVybiBDLnBkfSwKTDI6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdD17fQp0LmE9ZAp0
+LmI9ZQppZihkPT1udWxsKXt0LmE9bmV3IFAuQVQoITEsbnVsbCwiZXJyb3IiLCJNdXN0IG5vdCBiZSBu
+dWxsIikKdC5iPVAuWmIoKX1QLnJSKG5ldyBQLnBLKHQpKX0sClQ4OmZ1bmN0aW9uKGEsYixjLGQsZSl7
+dmFyIHQscz0kLlgzCmlmKHM9PT1jKXJldHVybiBkLiQwKCkKJC5YMz1jCnQ9cwp0cnl7cz1kLiQwKCkK
+cmV0dXJuIHN9ZmluYWxseXskLlgzPXR9fSwKeXY6ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyl7dmFyIHQs
+cz0kLlgzCmlmKHM9PT1jKXJldHVybiBkLiQxKGUpCiQuWDM9Ywp0PXMKdHJ5e3M9ZC4kMShlKQpyZXR1
+cm4gc31maW5hbGx5eyQuWDM9dH19LApReDpmdW5jdGlvbihhLGIsYyxkLGUsZixnLGgsaSl7dmFyIHQs
+cz0kLlgzCmlmKHM9PT1jKXJldHVybiBkLiQyKGUsZikKJC5YMz1jCnQ9cwp0cnl7cz1kLiQyKGUsZikK
+cmV0dXJuIHN9ZmluYWxseXskLlgzPXR9fSwKVGs6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQKdS5NLmEo
+ZCkKdD1DLk5VIT09YwppZih0KWQ9ISghdHx8ITEpP2MuR1koZCk6Yy5SVChkLHUuSCkKUC5lVyhkKX0s
+CnRoOmZ1bmN0aW9uIHRoKGEpe3RoaXMuYT1hfSwKaGE6ZnVuY3Rpb24gaGEoYSxiLGMpe3RoaXMuYT1h
+CnRoaXMuYj1iCnRoaXMuYz1jfSwKVnM6ZnVuY3Rpb24gVnMoYSl7dGhpcy5hPWF9LApGdDpmdW5jdGlv
+biBGdChhKXt0aGlzLmE9YX0sClczOmZ1bmN0aW9uIFczKCl7fSwKeUg6ZnVuY3Rpb24geUgoYSxiKXt0
+aGlzLmE9YQp0aGlzLmI9Yn0sCmloOmZ1bmN0aW9uIGloKGEsYil7dGhpcy5hPWEKdGhpcy5iPSExCnRo
+aXMuJHRpPWJ9LApXTTpmdW5jdGlvbiBXTShhKXt0aGlzLmE9YX0sClNYOmZ1bmN0aW9uIFNYKGEpe3Ro
+aXMuYT1hfSwKR3M6ZnVuY3Rpb24gR3MoYSl7dGhpcy5hPWF9LApGeTpmdW5jdGlvbiBGeShhLGIpe3Ro
+aXMuYT1hCnRoaXMuYj1ifSwKR1Y6ZnVuY3Rpb24gR1YoYSxiKXt2YXIgXz10aGlzCl8uYT1hCl8uZD1f
+LmM9Xy5iPW51bGwKXy4kdGk9Yn0sCnE0OmZ1bmN0aW9uIHE0KGEsYil7dGhpcy5hPWEKdGhpcy4kdGk9
+Yn0sCmI4OmZ1bmN0aW9uIGI4KCl7fSwKUGY6ZnVuY3Rpb24gUGYoKXt9LApaZjpmdW5jdGlvbiBaZihh
+LGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApGZTpmdW5jdGlvbiBGZShhLGIsYyxkLGUpe3ZhciBfPXRo
+aXMKXy5hPW51bGwKXy5iPWEKXy5jPWIKXy5kPWMKXy5lPWQKXy4kdGk9ZX0sCnZzOmZ1bmN0aW9uIHZz
+KGEsYil7dmFyIF89dGhpcwpfLmE9MApfLmI9YQpfLmM9bnVsbApfLiR0aT1ifSwKZGE6ZnVuY3Rpb24g
+ZGEoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCm9ROmZ1bmN0aW9uIG9RKGEsYil7dGhpcy5hPWEKdGhp
+cy5iPWJ9LApwVjpmdW5jdGlvbiBwVihhKXt0aGlzLmE9YX0sClU3OmZ1bmN0aW9uIFU3KGEpe3RoaXMu
+YT1hfSwKdnI6ZnVuY3Rpb24gdnIoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKckg6
+ZnVuY3Rpb24gckgoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCktGOmZ1bmN0aW9uIEtGKGEsYil7dGhp
+cy5hPWEKdGhpcy5iPWJ9LApaTDpmdW5jdGlvbiBaTChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhp
+cy5jPWN9LApSVDpmdW5jdGlvbiBSVChhLGIsYyxkKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1j
+Cl8uZD1kfSwKalo6ZnVuY3Rpb24galooYSl7dGhpcy5hPWF9LApycTpmdW5jdGlvbiBycShhLGIsYyl7
+dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApSVzpmdW5jdGlvbiBSVyhhLGIsYyl7dGhpcy5hPWEK
+dGhpcy5iPWIKdGhpcy5jPWN9LApPTTpmdW5jdGlvbiBPTShhKXt0aGlzLmE9YQp0aGlzLmI9bnVsbH0s
+CnFoOmZ1bmN0aW9uIHFoKCl7fSwKQjU6ZnVuY3Rpb24gQjUoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0s
+CnVPOmZ1bmN0aW9uIHVPKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApNTzpmdW5jdGlvbiBNTygpe30s
+CmtUOmZ1bmN0aW9uIGtUKCl7fSwKeEk6ZnVuY3Rpb24geEkoYSl7dGhpcy4kdGk9YX0sCk9IOmZ1bmN0
+aW9uIE9IKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LAptMDpmdW5jdGlvbiBtMCgpe30sCnBLOmZ1bmN0
+aW9uIHBLKGEpe3RoaXMuYT1hfSwKSmk6ZnVuY3Rpb24gSmkoKXt9LApoajpmdW5jdGlvbiBoaihhLGIs
+Yyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApWcDpmdW5jdGlvbiBWcChhLGIpe3RoaXMuYT1h
+CnRoaXMuYj1ifSwKT1I6ZnVuY3Rpb24gT1IoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1j
+fSwKRUY6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBiLkMoIkA8MD4iKS5LcShjKS5DKCJGbzwxLDI+Iiku
+YShILkI3KGEsbmV3IEguTjUoYi5DKCJAPDA+IikuS3EoYykuQygiTjU8MSwyPiIpKSkpfSwKRmw6ZnVu
+Y3Rpb24oYSxiKXtyZXR1cm4gbmV3IEguTjUoYS5DKCJAPDA+IikuS3EoYikuQygiTjU8MSwyPiIpKX0s
+CkxzOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5iNihhLkMoImI2PDA+IikpfSwKVDI6ZnVuY3Rpb24o
+KXt2YXIgdD1PYmplY3QuY3JlYXRlKG51bGwpCnRbIjxub24taWRlbnRpZmllci1rZXk+Il09dApkZWxl
+dGUgdFsiPG5vbi1pZGVudGlmaWVyLWtleT4iXQpyZXR1cm4gdH0sCnJqOmZ1bmN0aW9uKGEsYixjKXt2
+YXIgdD1uZXcgUC5sbShhLGIsYy5DKCJsbTwwPiIpKQp0LmM9YS5lCnJldHVybiB0fSwKRVA6ZnVuY3Rp
+b24oYSxiLGMpe3ZhciB0LHMKaWYoUC5oQihhKSl7aWYoYj09PSIoIiYmYz09PSIpIilyZXR1cm4iKC4u
+LikiCnJldHVybiBiKyIuLi4iK2N9dD1ILlZNKFtdLHUucykKQy5ObS5pKCQueGcsYSkKdHJ5e1AuVnIo
+YSx0KX1maW5hbGx5e2lmKDA+PSQueGcubGVuZ3RoKXJldHVybiBILmsoJC54ZywtMSkKJC54Zy5wb3Ao
+KX1zPVAudmcoYix1LlIuYSh0KSwiLCAiKStjCnJldHVybiBzLmNoYXJDb2RlQXQoMCk9PTA/czpzfSwK
+V0U6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKaWYoUC5oQihhKSlyZXR1cm4gYisiLi4uIitjCnQ9bmV3
+IFAuUm4oYikKQy5ObS5pKCQueGcsYSkKdHJ5e3M9dApzLmE9UC52ZyhzLmEsYSwiLCAiKX1maW5hbGx5
+e2lmKDA+PSQueGcubGVuZ3RoKXJldHVybiBILmsoJC54ZywtMSkKJC54Zy5wb3AoKX10LmErPWMKcz10
+LmEKcmV0dXJuIHMuY2hhckNvZGVBdCgwKT09MD9zOnN9LApoQjpmdW5jdGlvbihhKXt2YXIgdCxzCmZv
+cih0PSQueGcubGVuZ3RoLHM9MDtzPHQ7KytzKWlmKGE9PT0kLnhnW3NdKXJldHVybiEwCnJldHVybiEx
+fSwKVnI6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtPWEuZ2t6KGEpLGw9MCxrPTAKd2hp
+bGUoITApe2lmKCEobDw4MHx8azwzKSlicmVhawppZighbS5GKCkpcmV0dXJuCnQ9SC5kKG0uZ2woKSkK
+Qy5ObS5pKGIsdCkKbCs9dC5sZW5ndGgrMjsrK2t9aWYoIW0uRigpKXtpZihrPD01KXJldHVybgppZigw
+Pj1iLmxlbmd0aClyZXR1cm4gSC5rKGIsLTEpCnM9Yi5wb3AoKQppZigwPj1iLmxlbmd0aClyZXR1cm4g
+SC5rKGIsLTEpCnI9Yi5wb3AoKX1lbHNle3E9bS5nbCgpOysrawppZighbS5GKCkpe2lmKGs8PTQpe0Mu
+Tm0uaShiLEguZChxKSkKcmV0dXJufXM9SC5kKHEpCmlmKDA+PWIubGVuZ3RoKXJldHVybiBILmsoYiwt
+MSkKcj1iLnBvcCgpCmwrPXMubGVuZ3RoKzJ9ZWxzZXtwPW0uZ2woKTsrK2sKZm9yKDttLkYoKTtxPXAs
+cD1vKXtvPW0uZ2woKTsrK2sKaWYoaz4xMDApe3doaWxlKCEwKXtpZighKGw+NzUmJms+MykpYnJlYWsK
+aWYoMD49Yi5sZW5ndGgpcmV0dXJuIEguayhiLC0xKQpsLT1iLnBvcCgpLmxlbmd0aCsyOy0ta31DLk5t
+LmkoYiwiLi4uIikKcmV0dXJufX1yPUguZChxKQpzPUguZChwKQpsKz1zLmxlbmd0aCtyLmxlbmd0aCs0
+fX1pZihrPmIubGVuZ3RoKzIpe2wrPTUKbj0iLi4uIn1lbHNlIG49bnVsbAp3aGlsZSghMCl7aWYoIShs
+PjgwJiZiLmxlbmd0aD4zKSlicmVhawppZigwPj1iLmxlbmd0aClyZXR1cm4gSC5rKGIsLTEpCmwtPWIu
+cG9wKCkubGVuZ3RoKzIKaWYobj09bnVsbCl7bCs9NQpuPSIuLi4ifX1pZihuIT1udWxsKUMuTm0uaShi
+LG4pCkMuTm0uaShiLHIpCkMuTm0uaShiLHMpfSwKdE06ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9UC5M
+cyhiKQpmb3IodD1hLmxlbmd0aCxzPTA7czxhLmxlbmd0aDthLmxlbmd0aD09PXR8fCgwLEgubGspKGEp
+LCsrcylyLmkoMCxiLmEoYVtzXSkpCnJldHVybiByfSwKbk86ZnVuY3Rpb24oYSl7dmFyIHQscz17fQpp
+ZihQLmhCKGEpKXJldHVybiJ7Li4ufSIKdD1uZXcgUC5SbigiIikKdHJ5e0MuTm0uaSgkLnhnLGEpCnQu
+YSs9InsiCnMuYT0hMAphLksoMCxuZXcgUC5yYShzLHQpKQp0LmErPSJ9In1maW5hbGx5e2lmKDA+PSQu
+eGcubGVuZ3RoKXJldHVybiBILmsoJC54ZywtMSkKJC54Zy5wb3AoKX1zPXQuYQpyZXR1cm4gcy5jaGFy
+Q29kZUF0KDApPT0wP3M6c30sCmI2OmZ1bmN0aW9uIGI2KGEpe3ZhciBfPXRoaXMKXy5hPTAKXy5mPV8u
+ZT1fLmQ9Xy5jPV8uYj1udWxsCl8ucj0wCl8uJHRpPWF9LApibjpmdW5jdGlvbiBibihhKXt0aGlzLmE9
+YQp0aGlzLmM9dGhpcy5iPW51bGx9LApsbTpmdW5jdGlvbiBsbShhLGIsYyl7dmFyIF89dGhpcwpfLmE9
+YQpfLmI9YgpfLmQ9Xy5jPW51bGwKXy4kdGk9Y30sCm1XOmZ1bmN0aW9uIG1XKCl7fSwKdXk6ZnVuY3Rp
+b24gdXkoKXt9LApsRDpmdW5jdGlvbiBsRCgpe30sCmlsOmZ1bmN0aW9uIGlsKCl7fSwKcmE6ZnVuY3Rp
+b24gcmEoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCllrOmZ1bmN0aW9uIFlrKCl7fSwKeVE6ZnVuY3Rp
+b24geVEoYSl7dGhpcy5hPWF9LApLUDpmdW5jdGlvbiBLUCgpe30sClBuOmZ1bmN0aW9uIFBuKCl7fSwK
+R2o6ZnVuY3Rpb24gR2ooYSxiKXt0aGlzLmE9YQp0aGlzLiR0aT1ifSwKTWE6ZnVuY3Rpb24gTWEoKXt9
+LApWajpmdW5jdGlvbiBWaigpe30sClh2OmZ1bmN0aW9uIFh2KCl7fSwKblk6ZnVuY3Rpb24gblkoKXt9
+LApUQzpmdW5jdGlvbiBUQygpe30sClJVOmZ1bmN0aW9uIFJVKCl7fSwKQlM6ZnVuY3Rpb24oYSxiKXt2
+YXIgdCxzLHIscQppZih0eXBlb2YgYSE9InN0cmluZyIpdGhyb3cgSC5iKEguSShhKSkKdD1udWxsCnRy
+eXt0PUpTT04ucGFyc2UoYSl9Y2F0Y2gocil7cz1ILlJ1KHIpCnE9UC5ycihTdHJpbmcocyksbnVsbCxu
+dWxsKQp0aHJvdyBILmIocSl9cT1QLlFlKHQpCnJldHVybiBxfSwKUWU6ZnVuY3Rpb24oYSl7dmFyIHQK
+aWYoYT09bnVsbClyZXR1cm4gbnVsbAppZih0eXBlb2YgYSE9Im9iamVjdCIpcmV0dXJuIGEKaWYoT2Jq
+ZWN0LmdldFByb3RvdHlwZU9mKGEpIT09QXJyYXkucHJvdG90eXBlKXJldHVybiBuZXcgUC51dyhhLE9i
+amVjdC5jcmVhdGUobnVsbCkpCmZvcih0PTA7dDxhLmxlbmd0aDsrK3QpYVt0XT1QLlFlKGFbdF0pCnJl
+dHVybiBhfSwKa3k6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYiBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkpcmV0
+dXJuIFAuUlAoITEsYixjLGQpCnJldHVybiBudWxsfSwKUlA6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQs
+cyxyPSQudEwoKQppZihyPT1udWxsKXJldHVybiBudWxsCnQ9MD09PWMKaWYodCYmITApcmV0dXJuIFAu
+T1EocixiKQpzPWIubGVuZ3RoCmQ9UC5qQihjLGQscykKaWYodCYmZD09PXMpcmV0dXJuIFAuT1Eocixi
+KQpyZXR1cm4gUC5PUShyLGIuc3ViYXJyYXkoYyxkKSl9LApPUTpmdW5jdGlvbihhLGIpe2lmKFAuQWoo
+YikpcmV0dXJuIG51bGwKcmV0dXJuIFAuSmgoYSxiKX0sCkpoOmZ1bmN0aW9uKGEsYil7dmFyIHQscwp0
+cnl7dD1hLmRlY29kZShiKQpyZXR1cm4gdH1jYXRjaChzKXtILlJ1KHMpfXJldHVybiBudWxsfSwKQWo6
+ZnVuY3Rpb24oYSl7dmFyIHQscz1hLmxlbmd0aC0yCmZvcih0PTA7dDxzOysrdClpZihhW3RdPT09MjM3
+KWlmKChhW3QrMV0mMjI0KT09PTE2MClyZXR1cm4hMApyZXR1cm4hMX0sCldJOmZ1bmN0aW9uKCl7dmFy
+IHQscwp0cnl7dD1uZXcgVGV4dERlY29kZXIoInV0Zi04Iix7ZmF0YWw6dHJ1ZX0pCnJldHVybiB0fWNh
+dGNoKHMpe0guUnUocyl9cmV0dXJuIG51bGx9LApjUDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyCmZv
+cih0PUouVTYoYSkscz1iO3M8YzsrK3Mpe3I9dC5xKGEscykKaWYodHlwZW9mIHIhPT0ibnVtYmVyIily
+ZXR1cm4gci56TSgpCmlmKChyJjEyNykhPT1yKXJldHVybiBzLWJ9cmV0dXJuIGMtYn0sCnhNOmZ1bmN0
+aW9uKGEsYixjLGQsZSxmKXtpZihDLmpuLnpZKGYsNCkhPT0wKXRocm93IEguYihQLnJyKCJJbnZhbGlk
+IGJhc2U2NCBwYWRkaW5nLCBwYWRkZWQgbGVuZ3RoIG11c3QgYmUgbXVsdGlwbGUgb2YgZm91ciwgaXMg
+IitmLGEsYykpCmlmKGQrZSE9PWYpdGhyb3cgSC5iKFAucnIoIkludmFsaWQgYmFzZTY0IHBhZGRpbmcs
+ICc9JyBub3QgYXQgdGhlIGVuZCIsYSxiKSkKaWYoZT4yKXRocm93IEguYihQLnJyKCJJbnZhbGlkIGJh
+c2U2NCBwYWRkaW5nLCBtb3JlIHRoYW4gdHdvICc9JyBjaGFyYWN0ZXJzIixhLGIpKX0sCkd5OmZ1bmN0
+aW9uKGEsYixjKXtyZXR1cm4gbmV3IFAuVWQoYSxiKX0sCk5DOmZ1bmN0aW9uKGEpe3JldHVybiBhLkx0
+KCl9LAp1WDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz1uZXcgUC5SbigiIikscj1uZXcgUC50dShzLFtd
+LFAuQ3koKSkKci5pVShhKQp0PXMuYQpyZXR1cm4gdC5jaGFyQ29kZUF0KDApPT0wP3Q6dH0sCnV3OmZ1
+bmN0aW9uIHV3KGEsYil7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPW51bGx9LAppODpmdW5jdGlvbiBp
+OChhKXt0aGlzLmE9YX0sCkNWOmZ1bmN0aW9uIENWKCl7fSwKVTg6ZnVuY3Rpb24gVTgoKXt9LApVazpm
+dW5jdGlvbiBVaygpe30sCndJOmZ1bmN0aW9uIHdJKCl7fSwKWmk6ZnVuY3Rpb24gWmkoKXt9LApVZDpm
+dW5jdGlvbiBVZChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKSzg6ZnVuY3Rpb24gSzgoYSxiKXt0aGlz
+LmE9YQp0aGlzLmI9Yn0sCmJ5OmZ1bmN0aW9uIGJ5KCl7fSwKb2o6ZnVuY3Rpb24gb2ooYSl7dGhpcy5i
+PWF9LApNeDpmdW5jdGlvbiBNeChhKXt0aGlzLmE9YX0sClNoOmZ1bmN0aW9uIFNoKCl7fSwKdGk6ZnVu
+Y3Rpb24gdGkoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCnR1OmZ1bmN0aW9uIHR1KGEsYixjKXt0aGlz
+LmM9YQp0aGlzLmE9Ygp0aGlzLmI9Y30sCnU1OmZ1bmN0aW9uIHU1KCl7fSwKRTM6ZnVuY3Rpb24gRTMo
+KXt9LApSdzpmdW5jdGlvbiBSdyhhKXt0aGlzLmI9MAp0aGlzLmM9YX0sCkdZOmZ1bmN0aW9uIEdZKGEp
+e3RoaXMuYT1hfSwKYno6ZnVuY3Rpb24gYnooYSxiKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz0h
+MApfLmY9Xy5lPV8uZD0wfSwKUUE6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PUguSHAoYSxjKQppZih0IT1u
+dWxsKXJldHVybiB0CmlmKGIhPW51bGwpcmV0dXJuIGIuJDEoYSkKdGhyb3cgSC5iKFAucnIoYSxudWxs
+LG51bGwpKX0sCm9zOmZ1bmN0aW9uKGEpe2lmKGEgaW5zdGFuY2VvZiBILlRwKXJldHVybiBhLlooMCkK
+cmV0dXJuIkluc3RhbmNlIG9mICciK0guZChILmxoKGEpKSsiJyJ9LApPODpmdW5jdGlvbihhLGIsYyxk
+KXt2YXIgdCxzCmlmKGMpdD1ILlZNKG5ldyBBcnJheShhKSxkLkMoImpkPDA+IikpCmVsc2UgdD1KLlFp
+KGEsZCkKaWYoYSE9PTAmJiEwKWZvcihzPTA7czx0Lmxlbmd0aDsrK3MpQy5ObS5ZKHQscyxiKQpyZXR1
+cm4gdH0sCkNIOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzPUguVk0oW10sYy5DKCJqZDwwPiIpKQpmb3Io
+dD1KLklUKGEpO3QuRigpOylDLk5tLmkocyxjLmEodC5nbCgpKSkKaWYoYilyZXR1cm4gcwpyZXR1cm4g
+Yy5DKCJ6TTwwPiIpLmEoSi5FcChzKSl9LApBRjpmdW5jdGlvbihhLGIpe3JldHVybiBiLkMoInpNPDA+
+IikuYShKLnVuKFAuQ0goYSwhMSxiKSkpfSwKSE06ZnVuY3Rpb24oYSxiLGMpe3ZhciB0CmlmKEFycmF5
+LmlzQXJyYXkoYSkpe3UudC5hKGEpCnQ9YS5sZW5ndGgKYz1QLmpCKGIsYyx0KQpyZXR1cm4gSC5lVChi
+PjB8fGM8dD9DLk5tLkQ2KGEsYixjKTphKX1pZih1LmJtLmIoYSkpcmV0dXJuIEguZncoYSxiLFAuakIo
+YixjLGEubGVuZ3RoKSkKcmV0dXJuIFAuYncoYSxiLGMpfSwKT286ZnVuY3Rpb24oYSl7cmV0dXJuIEgu
+THcoYSl9LApidzpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscD1udWxsCmlmKGI8MCl0aHJvdyBI
+LmIoUC5URShiLDAsSi5IKGEpLHAscCkpCnQ9Yz09bnVsbAppZighdCYmYzxiKXRocm93IEguYihQLlRF
+KGMsYixKLkgoYSkscCxwKSkKcz1KLklUKGEpCmZvcihyPTA7cjxiOysrcilpZighcy5GKCkpdGhyb3cg
+SC5iKFAuVEUoYiwwLHIscCxwKSkKcT1bXQppZih0KWZvcig7cy5GKCk7KXEucHVzaChzLmdsKCkpCmVs
+c2UgZm9yKHI9YjtyPGM7KytyKXtpZighcy5GKCkpdGhyb3cgSC5iKFAuVEUoYyxiLHIscCxwKSkKcS5w
+dXNoKHMuZ2woKSl9cmV0dXJuIEguZVQocSl9LApudTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEguVlIo
+YSxILnY0KGEsITEsITAsITEsITEsITEpKX0sCnZnOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1KLklUKGIp
+CmlmKCF0LkYoKSlyZXR1cm4gYQppZihjLmxlbmd0aD09PTApe2RvIGErPUguZCh0LmdsKCkpCndoaWxl
+KHQuRigpKX1lbHNle2ErPUguZCh0LmdsKCkpCmZvcig7dC5GKCk7KWE9YStjK0guZCh0LmdsKCkpfXJl
+dHVybiBhfSwKbHI6ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIG5ldyBQLm1wKGEsYixjLGQpfSwKdW86
+ZnVuY3Rpb24oKXt2YXIgdD1ILk0wKCkKaWYodCE9bnVsbClyZXR1cm4gUC5oSyh0KQp0aHJvdyBILmIo
+UC5MNCgiJ1VyaS5iYXNlJyBpcyBub3Qgc3VwcG9ydGVkIikpfSwKZVA6ZnVuY3Rpb24oYSxiLGMsZCl7
+dmFyIHQscyxyLHEscCxvLG49IjAxMjM0NTY3ODlBQkNERUYiCmlmKGM9PT1DLnhNKXt0PSQuejQoKS5i
+CmlmKHR5cGVvZiBiIT0ic3RyaW5nIilILnZoKEguSShiKSkKdD10LnRlc3QoYil9ZWxzZSB0PSExCmlm
+KHQpcmV0dXJuIGIKSC5MaChjKS5DKCJVay5TIikuYShiKQpzPWMuZ1pFKCkuV0ooYikKZm9yKHQ9cy5s
+ZW5ndGgscj0wLHE9IiI7cjx0Oysrcil7cD1zW3JdCmlmKHA8MTI4KXtvPXA+Pj40CmlmKG8+PTgpcmV0
+dXJuIEguayhhLG8pCm89KGFbb10mMTw8KHAmMTUpKSE9PTB9ZWxzZSBvPSExCmlmKG8pcSs9SC5Mdyhw
+KQplbHNlIHE9ZCYmcD09PTMyP3ErIisiOnErIiUiK25bcD4+PjQmMTVdK25bcCYxNV19cmV0dXJuIHEu
+Y2hhckNvZGVBdCgwKT09MD9xOnF9LApaYjpmdW5jdGlvbigpe3ZhciB0LHMKaWYoSC5vVCgkLnA2KCkp
+KXJldHVybiBILnRzKG5ldyBFcnJvcigpKQp0cnl7dGhyb3cgSC5iKCIiKX1jYXRjaChzKXtILlJ1KHMp
+CnQ9SC50cyhzKQpyZXR1cm4gdH19LApHcTpmdW5jdGlvbihhKXt2YXIgdD1NYXRoLmFicyhhKSxzPWE8
+MD8iLSI6IiIKaWYodD49MTAwMClyZXR1cm4iIithCmlmKHQ+PTEwMClyZXR1cm4gcysiMCIrdAppZih0
+Pj0xMClyZXR1cm4gcysiMDAiK3QKcmV0dXJuIHMrIjAwMCIrdH0sClZ4OmZ1bmN0aW9uKGEpe2lmKGE+
+PTEwMClyZXR1cm4iIithCmlmKGE+PTEwKXJldHVybiIwIithCnJldHVybiIwMCIrYX0sCmgwOmZ1bmN0
+aW9uKGEpe2lmKGE+PTEwKXJldHVybiIiK2EKcmV0dXJuIjAiK2F9LApoOmZ1bmN0aW9uKGEpe2lmKHR5
+cGVvZiBhPT0ibnVtYmVyInx8SC5yUShhKXx8bnVsbD09YSlyZXR1cm4gSi5BYyhhKQppZih0eXBlb2Yg
+YT09InN0cmluZyIpcmV0dXJuIEpTT04uc3RyaW5naWZ5KGEpCnJldHVybiBQLm9zKGEpfSwKaFY6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIG5ldyBQLkM2KGEpfSwKeFk6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLkFU
+KCExLG51bGwsbnVsbCxhKX0sCkwzOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbmV3IFAuQVQoITAsYSxi
+LGMpfSwKRWU6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLkFUKCExLG51bGwsYSwiTXVzdCBub3QgYmUg
+bnVsbCIpfSwKVUk6ZnVuY3Rpb24oYSxiLGMpe2lmKGE9PW51bGwpdGhyb3cgSC5iKFAuRWUoYikpCnJl
+dHVybiBhfSwKTzc6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IFAuYkoobnVsbCxudWxsLCEwLGEsYiwi
+VmFsdWUgbm90IGluIHJhbmdlIil9LApURTpmdW5jdGlvbihhLGIsYyxkLGUpe3JldHVybiBuZXcgUC5i
+SihiLGMsITAsYSxkLCJJbnZhbGlkIHZhbHVlIil9LAp3QTpmdW5jdGlvbihhLGIsYyxkKXtpZihhPGJ8
+fGE+Yyl0aHJvdyBILmIoUC5URShhLGIsYyxkLG51bGwpKQpyZXR1cm4gYX0sCmpCOmZ1bmN0aW9uKGEs
+YixjKXtpZigwPmF8fGE+Yyl0aHJvdyBILmIoUC5URShhLDAsYywic3RhcnQiLG51bGwpKQppZihiIT1u
+dWxsKXtpZihhPmJ8fGI+Yyl0aHJvdyBILmIoUC5URShiLGEsYywiZW5kIixudWxsKSkKcmV0dXJuIGJ9
+cmV0dXJuIGN9LAprMTpmdW5jdGlvbihhLGIpe2lmKHR5cGVvZiBhIT09Im51bWJlciIpcmV0dXJuIGEu
+SigpCmlmKGE8MCl0aHJvdyBILmIoUC5URShhLDAsbnVsbCxiLG51bGwpKQpyZXR1cm4gYX0sCnQ6ZnVu
+Y3Rpb24oYSxiLGMsZCxlKXt2YXIgdD1ILldZKGU9PW51bGw/Si5IKGIpOmUpCnJldHVybiBuZXcgUC5l
+WSh0LCEwLGEsYywiSW5kZXggb3V0IG9mIHJhbmdlIil9LApMNDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3
+IFAudWIoYSl9LApuOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5kcyhhKX0sClBWOmZ1bmN0aW9uKGEp
+e3JldHVybiBuZXcgUC5saihhKX0sCmE0OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5VVihhKX0sCnJy
+OmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbmV3IFAuYUUoYSxiLGMpfSwKZEg6ZnVuY3Rpb24oYSxiLGMp
+e3ZhciB0LHM9SC5WTShbXSxjLkMoImpkPDA+IikpCkMuTm0uc0EocyxhKQpmb3IodD0wO3Q8YTsrK3Qp
+Qy5ObS5ZKHMsdCxiLiQxKHQpKQpyZXR1cm4gc30sCmhLOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAs
+byxuLG0sbCxrLGosaSxoLGcsZixlPW51bGwsZD1hLmxlbmd0aAppZihkPj01KXt0PSgoSi5ReihhLDQp
+XjU4KSozfEMueEIuVyhhLDApXjEwMHxDLnhCLlcoYSwxKV45N3xDLnhCLlcoYSwyKV4xMTZ8Qy54Qi5X
+KGEsMyleOTcpPj4+MAppZih0PT09MClyZXR1cm4gUC5LRChkPGQ/Qy54Qi5OaihhLDAsZCk6YSw1LGUp
+LmdsUigpCmVsc2UgaWYodD09PTMyKXJldHVybiBQLktEKEMueEIuTmooYSw1LGQpLDAsZSkuZ2xSKCl9
+cz1uZXcgQXJyYXkoOCkKcy5maXhlZCRsZW5ndGg9QXJyYXkKcj1ILlZNKHMsdS50KQpDLk5tLlkociww
+LDApCkMuTm0uWShyLDEsLTEpCkMuTm0uWShyLDIsLTEpCkMuTm0uWShyLDcsLTEpCkMuTm0uWShyLDMs
+MCkKQy5ObS5ZKHIsNCwwKQpDLk5tLlkociw1LGQpCkMuTm0uWShyLDYsZCkKaWYoUC5VQihhLDAsZCww
+LHIpPj0xNClDLk5tLlkociw3LGQpCnE9clsxXQppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBx
+LnRCKCkKaWYocT49MClpZihQLlVCKGEsMCxxLDIwLHIpPT09MjApcls3XT1xCnM9clsyXQppZih0eXBl
+b2YgcyE9PSJudW1iZXIiKXJldHVybiBzLmgoKQpwPXMrMQpvPXJbM10Kbj1yWzRdCm09cls1XQpsPXJb
+Nl0KaWYodHlwZW9mIGwhPT0ibnVtYmVyIilyZXR1cm4gbC5KKCkKaWYodHlwZW9mIG0hPT0ibnVtYmVy
+IilyZXR1cm4gSC5wWShtKQppZihsPG0pbT1sCmlmKHR5cGVvZiBuIT09Im51bWJlciIpcmV0dXJuIG4u
+SigpCmlmKG48cCluPW0KZWxzZSBpZihuPD1xKW49cSsxCmlmKHR5cGVvZiBvIT09Im51bWJlciIpcmV0
+dXJuIG8uSigpCmlmKG88cClvPW4Kcz1yWzddCmlmKHR5cGVvZiBzIT09Im51bWJlciIpcmV0dXJuIHMu
+SigpCms9czwwCmlmKGspaWYocD5xKzMpe2o9ZQprPSExfWVsc2V7cz1vPjAKaWYocyYmbysxPT09bil7
+aj1lCms9ITF9ZWxzZXtpZighKG08ZCYmbT09PW4rMiYmSi5xMChhLCIuLiIsbikpKWk9bT5uKzImJkou
+cTAoYSwiLy4uIixtLTMpCmVsc2UgaT0hMAppZihpKXtqPWUKaz0hMX1lbHNle2lmKHE9PT00KWlmKEou
+cTAoYSwiZmlsZSIsMCkpe2lmKHA8PTApe2lmKCFDLnhCLlFpKGEsIi8iLG4pKXtoPSJmaWxlOi8vLyIK
+dD0zfWVsc2V7aD0iZmlsZTovLyIKdD0yfWE9aCtDLnhCLk5qKGEsbixkKQpxLT0wCnM9dC0wCm0rPXMK
+bCs9cwpkPWEubGVuZ3RoCnA9NwpvPTcKbj03fWVsc2UgaWYobj09PW0pe2c9bSsxOysrbAphPUMueEIu
+aTcoYSxuLG0sIi8iKTsrK2QKbT1nfWo9ImZpbGUifWVsc2UgaWYoQy54Qi5RaShhLCJodHRwIiwwKSl7
+aWYocyYmbyszPT09biYmQy54Qi5RaShhLCI4MCIsbysxKSl7Zj1uLTMKbS09MwpsLT0zCmE9Qy54Qi5p
+NyhhLG8sbiwiIikKZC09MwpuPWZ9aj0iaHR0cCJ9ZWxzZSBqPWUKZWxzZSBpZihxPT09NSYmSi5xMChh
+LCJodHRwcyIsMCkpe2lmKHMmJm8rND09PW4mJkoucTAoYSwiNDQzIixvKzEpKXtmPW4tNAptLT00Cmwt
+PTQKYT1KLmRnKGEsbyxuLCIiKQpkLT0zCm49Zn1qPSJodHRwcyJ9ZWxzZSBqPWUKaz0hMH19fWVsc2Ug
+aj1lCmlmKGspe3M9YS5sZW5ndGgKaWYoZDxzKXthPUoubGQoYSwwLGQpCnEtPTAKcC09MApvLT0wCm4t
+PTAKbS09MApsLT0wfXJldHVybiBuZXcgUC5VZihhLHEscCxvLG4sbSxsLGopfXJldHVybiBQLmp2KGEs
+MCxkLHEscCxvLG4sbSxsLGopfSwKTXQ6ZnVuY3Rpb24oYSl7SC5jKGEpCnJldHVybiBQLmt1KGEsMCxh
+Lmxlbmd0aCxDLnhNLCExKX0sCldYOmZ1bmN0aW9uKGEpe3ZhciB0PXUuTgpyZXR1cm4gQy5ObS5OMChI
+LlZNKGEuc3BsaXQoIiYiKSx1LnMpLFAuRmwodCx0KSxuZXcgUC5uMShDLnhNKSx1LmYpfSwKSGg6ZnVu
+Y3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG09bnVsbCxsPSJJUHY0IGFkZHJlc3Mgc2hvdWxk
+IGNvbnRhaW4gZXhhY3RseSA0IHBhcnRzIixrPSJlYWNoIHBhcnQgbXVzdCBiZSBpbiB0aGUgcmFuZ2Ug
+MC4uMjU1IixqPW5ldyBQLmNTKGEpLGk9bmV3IFVpbnQ4QXJyYXkoNCkKZm9yKHQ9aS5sZW5ndGgscz1i
+LHI9cyxxPTA7czxjOysrcyl7cD1DLnhCLm0oYSxzKQppZihwIT09NDYpe2lmKChwXjQ4KT45KWouJDIo
+ImludmFsaWQgY2hhcmFjdGVyIixzKX1lbHNle2lmKHE9PT0zKWouJDIobCxzKQpvPVAuUUEoQy54Qi5O
+aihhLHIscyksbSxtKQppZih0eXBlb2YgbyE9PSJudW1iZXIiKXJldHVybiBvLm9zKCkKaWYobz4yNTUp
+ai4kMihrLHIpCm49cSsxCmlmKHE+PXQpcmV0dXJuIEguayhpLHEpCmlbcV09bwpyPXMrMQpxPW59fWlm
+KHEhPT0zKWouJDIobCxjKQpvPVAuUUEoQy54Qi5OaihhLHIsYyksbSxtKQppZih0eXBlb2YgbyE9PSJu
+dW1iZXIiKXJldHVybiBvLm9zKCkKaWYobz4yNTUpai4kMihrLHIpCmlmKHE+PXQpcmV0dXJuIEguayhp
+LHEpCmlbcV09bwpyZXR1cm4gaX0sCmVnOmZ1bmN0aW9uKGEsYixhMCl7dmFyIHQscyxyLHEscCxvLG4s
+bSxsLGssaixpLGgsZyxmLGUsZD1uZXcgUC5WQyhhKSxjPW5ldyBQLkpUKGQsYSkKaWYoYS5sZW5ndGg8
+MilkLiQxKCJhZGRyZXNzIGlzIHRvbyBzaG9ydCIpCnQ9SC5WTShbXSx1LnQpCmZvcihzPWIscj1zLHE9
+ITEscD0hMTtzPGEwOysrcyl7bz1DLnhCLm0oYSxzKQppZihvPT09NTgpe2lmKHM9PT1iKXsrK3MKaWYo
+Qy54Qi5tKGEscykhPT01OClkLiQyKCJpbnZhbGlkIHN0YXJ0IGNvbG9uLiIscykKcj1zfWlmKHM9PT1y
+KXtpZihxKWQuJDIoIm9ubHkgb25lIHdpbGRjYXJkIGA6OmAgaXMgYWxsb3dlZCIscykKQy5ObS5pKHQs
+LTEpCnE9ITB9ZWxzZSBDLk5tLmkodCxjLiQyKHIscykpCnI9cysxfWVsc2UgaWYobz09PTQ2KXA9ITB9
+aWYodC5sZW5ndGg9PT0wKWQuJDEoInRvbyBmZXcgcGFydHMiKQpuPXI9PT1hMAptPUMuTm0uZ3JaKHQp
+CmlmKG4mJm0hPT0tMSlkLiQyKCJleHBlY3RlZCBhIHBhcnQgYWZ0ZXIgbGFzdCBgOmAiLGEwKQppZigh
+bilpZighcClDLk5tLmkodCxjLiQyKHIsYTApKQplbHNle2w9UC5IaChhLHIsYTApCkMuTm0uaSh0LChs
+WzBdPDw4fGxbMV0pPj4+MCkKQy5ObS5pKHQsKGxbMl08PDh8bFszXSk+Pj4wKX1pZihxKXtpZih0Lmxl
+bmd0aD43KWQuJDEoImFuIGFkZHJlc3Mgd2l0aCBhIHdpbGRjYXJkIG11c3QgaGF2ZSBsZXNzIHRoYW4g
+NyBwYXJ0cyIpfWVsc2UgaWYodC5sZW5ndGghPT04KWQuJDEoImFuIGFkZHJlc3Mgd2l0aG91dCBhIHdp
+bGRjYXJkIG11c3QgY29udGFpbiBleGFjdGx5IDggcGFydHMiKQprPW5ldyBVaW50OEFycmF5KDE2KQpm
+b3IobT10Lmxlbmd0aCxqPWsubGVuZ3RoLGk9OS1tLHM9MCxoPTA7czxtOysrcyl7Zz10W3NdCmlmKGc9
+PT0tMSlmb3IoZj0wO2Y8aTsrK2Ype2lmKGg8MHx8aD49ailyZXR1cm4gSC5rKGssaCkKa1toXT0wCmU9
+aCsxCmlmKGU+PWopcmV0dXJuIEguayhrLGUpCmtbZV09MApoKz0yfWVsc2V7ZT1DLmpuLndHKGcsOCkK
+aWYoaDwwfHxoPj1qKXJldHVybiBILmsoayxoKQprW2hdPWUKZT1oKzEKaWYoZT49ailyZXR1cm4gSC5r
+KGssZSkKa1tlXT1nJjI1NQpoKz0yfX1yZXR1cm4ga30sCmp2OmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcs
+aCxpLGope3ZhciB0LHMscixxLHAsbyxuLG09bnVsbAppZihqPT1udWxsKWlmKGQ+YilqPVAuUGkoYSxi
+LGQpCmVsc2V7aWYoZD09PWIpUC5SMyhhLGIsIkludmFsaWQgZW1wdHkgc2NoZW1lIikKaj0iIn1pZihl
+PmIpe3Q9ZCszCnM9dDxlP1AuelIoYSx0LGUtMSk6IiIKcj1QLk9lKGEsZSxmLCExKQppZih0eXBlb2Yg
+ZiE9PSJudW1iZXIiKXJldHVybiBmLmgoKQpxPWYrMQppZih0eXBlb2YgZyE9PSJudW1iZXIiKXJldHVy
+biBILnBZKGcpCnA9cTxnP1Aud0IoUC5RQShKLmxkKGEscSxnKSxuZXcgUC5lMShhLGYpLG0pLGopOm19
+ZWxzZXtwPW0Kcj1wCnM9IiJ9bz1QLmthKGEsZyxoLG0saixyIT1udWxsKQppZih0eXBlb2YgaCE9PSJu
+dW1iZXIiKXJldHVybiBoLkooKQpuPWg8aT9QLmxlKGEsaCsxLGksbSk6bQpyZXR1cm4gbmV3IFAuRG4o
+aixzLHIscCxvLG4saTxjP1AudEcoYSxpKzEsYyk6bSl9LApLTDpmdW5jdGlvbihhLGIsYyxkLGUsZixn
+KXt2YXIgdCxzLHIscSxwLG8KZj1QLlBpKGYsMCxmPT1udWxsPzA6Zi5sZW5ndGgpCmc9UC56UihnLDAs
+Zz09bnVsbD8wOmcubGVuZ3RoKQphPVAuT2UoYSwwLGE9PW51bGw/MDphLmxlbmd0aCwhMSkKdD1QLmxl
+KG51bGwsMCwwLGUpCnM9UC50RyhudWxsLDAsMCkKZD1QLndCKGQsZikKcj1mPT09ImZpbGUiCmlmKGE9
+PW51bGwpcT1nLmxlbmd0aCE9PTB8fGQhPW51bGx8fHIKZWxzZSBxPSExCmlmKHEpYT0iIgpxPWE9PW51
+bGwKcD0hcQpiPVAua2EoYiwwLGI9PW51bGw/MDpiLmxlbmd0aCxjLGYscCkKbz1mLmxlbmd0aD09PTAK
+aWYobyYmcSYmIUMueEIubihiLCIvIikpYj1QLndGKGIsIW98fHApCmVsc2UgYj1QLnhlKGIpCnJldHVy
+biBuZXcgUC5EbihmLGcscSYmQy54Qi5uKGIsIi8vIik/IiI6YSxkLGIsdCxzKX0sCndLOmZ1bmN0aW9u
+KGEpe2lmKGE9PT0iaHR0cCIpcmV0dXJuIDgwCmlmKGE9PT0iaHR0cHMiKXJldHVybiA0NDMKcmV0dXJu
+IDB9LApSMzpmdW5jdGlvbihhLGIsYyl7dGhyb3cgSC5iKFAucnIoYyxhLGIpKX0sClhkOmZ1bmN0aW9u
+KGEsYixjLGQpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaT1udWxsLGg9Yi5sZW5ndGgKaWYoaCE9
+PTApe3I9MAp3aGlsZSghMCl7aWYoIShyPGgpKXt0PSIiCnM9MApicmVha31pZihDLnhCLlcoYixyKT09
+PTY0KXt0PUMueEIuTmooYiwwLHIpCnM9cisxCmJyZWFrfSsrcn1pZihzPGgmJkMueEIuVyhiLHMpPT09
+OTEpe2ZvcihxPXMscD0tMTtxPGg7KytxKXtvPUMueEIuVyhiLHEpCmlmKG89PT0zNyYmcDwwKXtuPUMu
+eEIuUWkoYiwiMjUiLHErMSk/cSsyOnEKcD1xCnE9bn1lbHNlIGlmKG89PT05MylicmVha31pZihxPT09
+aCl0aHJvdyBILmIoUC5ycigiSW52YWxpZCBJUHY2IGhvc3QgZW50cnkuIixiLHMpKQptPXA8MD9xOnAK
+UC5lZyhiLHMrMSxtKTsrK3EKaWYocSE9PWgmJkMueEIuVyhiLHEpIT09NTgpdGhyb3cgSC5iKFAucnIo
+IkludmFsaWQgZW5kIG9mIGF1dGhvcml0eSIsYixxKSl9ZWxzZSBxPXMKd2hpbGUoITApe2lmKCEocTxo
+KSl7bD1pCmJyZWFrfWlmKEMueEIuVyhiLHEpPT09NTgpe2s9Qy54Qi5HKGIscSsxKQpsPWsubGVuZ3Ro
+IT09MD9QLlFBKGssaSxpKTppCmJyZWFrfSsrcX1qPUMueEIuTmooYixzLHEpfWVsc2V7bD1pCmo9bAp0
+PSIifXJldHVybiBQLktMKGosaSxILlZNKGMuc3BsaXQoIi8iKSx1LnMpLGwsZCxhLHQpfSwKa0U6ZnVu
+Y3Rpb24oYSxiKXtDLk5tLksoYSxuZXcgUC5OWSghMSkpfSwKSE46ZnVuY3Rpb24oYSxiLGMpe3ZhciB0
+LHMscgpmb3IodD1ILnFDKGEsYyxudWxsLEgudDYoYSkuYyksdD1uZXcgSC5hNyh0LHQuZ0EodCksdC4k
+dGkuQygiYTc8YUwuRT4iKSk7dC5GKCk7KXtzPXQuZApyPVAubnUoJ1siKi86PD4/XFxcXHxdJykKcy50
+b1N0cmluZwppZihILm0yKHMsciwwKSl7dD1QLkw0KCJJbGxlZ2FsIGNoYXJhY3RlciBpbiBwYXRoOiAi
+K3MpCnRocm93IEguYih0KX19fSwKcmc6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZighKDY1PD1hJiZhPD05
+MCkpdD05Nzw9YSYmYTw9MTIyCmVsc2UgdD0hMAppZih0KXJldHVybgp0PVAuTDQoIklsbGVnYWwgZHJp
+dmUgbGV0dGVyICIrUC5PbyhhKSkKdGhyb3cgSC5iKHQpfSwKd0I6ZnVuY3Rpb24oYSxiKXtpZihhIT1u
+dWxsJiZhPT09UC53SyhiKSlyZXR1cm4gbnVsbApyZXR1cm4gYX0sCk9lOmZ1bmN0aW9uKGEsYixjLGQp
+e3ZhciB0LHMscixxLHAsbwppZihhPT1udWxsKXJldHVybiBudWxsCmlmKGI9PT1jKXJldHVybiIiCmlm
+KEMueEIubShhLGIpPT09OTEpe2lmKHR5cGVvZiBjIT09Im51bWJlciIpcmV0dXJuIGMuSE4oKQp0PWMt
+MQppZihDLnhCLm0oYSx0KSE9PTkzKVAuUjMoYSxiLCJNaXNzaW5nIGVuZCBgXWAgdG8gbWF0Y2ggYFtg
+IGluIGhvc3QiKQpzPWIrMQpyPVAudG8oYSxzLHQpCmlmKHR5cGVvZiByIT09Im51bWJlciIpcmV0dXJu
+IHIuSigpCmlmKHI8dCl7cT1yKzEKcD1QLk9BKGEsQy54Qi5RaShhLCIyNSIscSk/ciszOnEsdCwiJTI1
+Iil9ZWxzZSBwPSIiClAuZWcoYSxzLHIpCnJldHVybiBDLnhCLk5qKGEsYixyKS50b0xvd2VyQ2FzZSgp
+K3ArIl0ifWlmKHR5cGVvZiBjIT09Im51bWJlciIpcmV0dXJuIEgucFkoYykKbz1iCmZvcig7bzxjOysr
+bylpZihDLnhCLm0oYSxvKT09PTU4KXtyPUMueEIuWFUoYSwiJSIsYikKaWYoIShyPj1iJiZyPGMpKXI9
+YwppZihyPGMpe3E9cisxCnA9UC5PQShhLEMueEIuUWkoYSwiMjUiLHEpP3IrMzpxLGMsIiUyNSIpfWVs
+c2UgcD0iIgpQLmVnKGEsYixyKQpyZXR1cm4iWyIrQy54Qi5OaihhLGIscikrcCsiXSJ9cmV0dXJuIFAu
+T0woYSxiLGMpfSwKdG86ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHM9Qy54Qi5YVShhLCIlIixiKQppZihz
+Pj1iKXtpZih0eXBlb2YgYyE9PSJudW1iZXIiKXJldHVybiBILnBZKGMpCnQ9czxjfWVsc2UgdD0hMQpy
+ZXR1cm4gdD9zOmN9LApPQTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsaz1k
+IT09IiI/bmV3IFAuUm4oZCk6bnVsbAppZih0eXBlb2YgYyE9PSJudW1iZXIiKXJldHVybiBILnBZKGMp
+CnQ9YgpzPXQKcj0hMApmb3IoO3Q8Yzspe3E9Qy54Qi5tKGEsdCkKaWYocT09PTM3KXtwPVAucnYoYSx0
+LCEwKQpvPXA9PW51bGwKaWYobyYmcil7dCs9Mwpjb250aW51ZX1pZihrPT1udWxsKWs9bmV3IFAuUm4o
+IiIpCm49ay5hKz1DLnhCLk5qKGEscyx0KQppZihvKXA9Qy54Qi5OaihhLHQsdCszKQplbHNlIGlmKHA9
+PT0iJSIpUC5SMyhhLHQsIlpvbmVJRCBzaG91bGQgbm90IGNvbnRhaW4gJSBhbnltb3JlIikKay5hPW4r
+cAp0Kz0zCnM9dApyPSEwfWVsc2V7aWYocTwxMjcpe289cT4+PjQKaWYobz49OClyZXR1cm4gSC5rKEMu
+RjMsbykKbz0oQy5GM1tvXSYxPDwocSYxNSkpIT09MH1lbHNlIG89ITEKaWYobyl7aWYociYmNjU8PXEm
+JjkwPj1xKXtpZihrPT1udWxsKWs9bmV3IFAuUm4oIiIpCmlmKHM8dCl7ay5hKz1DLnhCLk5qKGEscyx0
+KQpzPXR9cj0hMX0rK3R9ZWxzZXtpZigocSY2NDUxMik9PT01NTI5NiYmdCsxPGMpe209Qy54Qi5tKGEs
+dCsxKQppZigobSY2NDUxMik9PT01NjMyMCl7cT02NTUzNnwocSYxMDIzKTw8MTB8bSYxMDIzCmw9Mn1l
+bHNlIGw9MX1lbHNlIGw9MQppZihrPT1udWxsKWs9bmV3IFAuUm4oIiIpCmsuYSs9Qy54Qi5OaihhLHMs
+dCkKay5hKz1QLnpYKHEpCnQrPWwKcz10fX19aWYoaz09bnVsbClyZXR1cm4gQy54Qi5OaihhLGIsYykK
+aWYoczxjKWsuYSs9Qy54Qi5OaihhLHMsYykKbz1rLmEKcmV0dXJuIG8uY2hhckNvZGVBdCgwKT09MD9v
+Om99LApPTDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGssagppZih0eXBlb2Yg
+YyE9PSJudW1iZXIiKXJldHVybiBILnBZKGMpCnQ9YgpzPXQKcj1udWxsCnE9ITAKZm9yKDt0PGM7KXtw
+PUMueEIubShhLHQpCmlmKHA9PT0zNyl7bz1QLnJ2KGEsdCwhMCkKbj1vPT1udWxsCmlmKG4mJnEpe3Qr
+PTMKY29udGludWV9aWYocj09bnVsbClyPW5ldyBQLlJuKCIiKQptPUMueEIuTmooYSxzLHQpCmw9ci5h
+Kz0hcT9tLnRvTG93ZXJDYXNlKCk6bQppZihuKXtvPUMueEIuTmooYSx0LHQrMykKaz0zfWVsc2UgaWYo
+bz09PSIlIil7bz0iJTI1IgprPTF9ZWxzZSBrPTMKci5hPWwrbwp0Kz1rCnM9dApxPSEwfWVsc2V7aWYo
+cDwxMjcpe249cD4+PjQKaWYobj49OClyZXR1cm4gSC5rKEMuZWEsbikKbj0oQy5lYVtuXSYxPDwocCYx
+NSkpIT09MH1lbHNlIG49ITEKaWYobil7aWYocSYmNjU8PXAmJjkwPj1wKXtpZihyPT1udWxsKXI9bmV3
+IFAuUm4oIiIpCmlmKHM8dCl7ci5hKz1DLnhCLk5qKGEscyx0KQpzPXR9cT0hMX0rK3R9ZWxzZXtpZihw
+PD05Myl7bj1wPj4+NAppZihuPj04KXJldHVybiBILmsoQy5hayxuKQpuPShDLmFrW25dJjE8PChwJjE1
+KSkhPT0wfWVsc2Ugbj0hMQppZihuKVAuUjMoYSx0LCJJbnZhbGlkIGNoYXJhY3RlciIpCmVsc2V7aWYo
+KHAmNjQ1MTIpPT09NTUyOTYmJnQrMTxjKXtqPUMueEIubShhLHQrMSkKaWYoKGomNjQ1MTIpPT09NTYz
+MjApe3A9NjU1MzZ8KHAmMTAyMyk8PDEwfGomMTAyMwprPTJ9ZWxzZSBrPTF9ZWxzZSBrPTEKaWYocj09
+bnVsbClyPW5ldyBQLlJuKCIiKQptPUMueEIuTmooYSxzLHQpCnIuYSs9IXE/bS50b0xvd2VyQ2FzZSgp
+Om0Kci5hKz1QLnpYKHApCnQrPWsKcz10fX19fWlmKHI9PW51bGwpcmV0dXJuIEMueEIuTmooYSxiLGMp
+CmlmKHM8Yyl7bT1DLnhCLk5qKGEscyxjKQpyLmErPSFxP20udG9Mb3dlckNhc2UoKTptfW49ci5hCnJl
+dHVybiBuLmNoYXJDb2RlQXQoMCk9PTA/bjpufSwKUGk6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixx
+CmlmKGI9PT1jKXJldHVybiIiCmlmKCFQLkV0KEouclkoYSkuVyhhLGIpKSlQLlIzKGEsYiwiU2NoZW1l
+IG5vdCBzdGFydGluZyB3aXRoIGFscGhhYmV0aWMgY2hhcmFjdGVyIikKZm9yKHQ9YixzPSExO3Q8Yzsr
+K3Qpe3I9Qy54Qi5XKGEsdCkKaWYocjwxMjgpe3E9cj4+PjQKaWYocT49OClyZXR1cm4gSC5rKEMubUss
+cSkKcT0oQy5tS1txXSYxPDwociYxNSkpIT09MH1lbHNlIHE9ITEKaWYoIXEpUC5SMyhhLHQsIklsbGVn
+YWwgc2NoZW1lIGNoYXJhY3RlciIpCmlmKDY1PD1yJiZyPD05MClzPSEwfWE9Qy54Qi5OaihhLGIsYykK
+cmV0dXJuIFAuWWEocz9hLnRvTG93ZXJDYXNlKCk6YSl9LApZYTpmdW5jdGlvbihhKXtpZihhPT09Imh0
+dHAiKXJldHVybiJodHRwIgppZihhPT09ImZpbGUiKXJldHVybiJmaWxlIgppZihhPT09Imh0dHBzIily
+ZXR1cm4iaHR0cHMiCmlmKGE9PT0icGFja2FnZSIpcmV0dXJuInBhY2thZ2UiCnJldHVybiBhfSwKelI6
+ZnVuY3Rpb24oYSxiLGMpe2lmKGE9PW51bGwpcmV0dXJuIiIKcmV0dXJuIFAuUEkoYSxiLGMsQy50bywh
+MSl9LAprYTpmdW5jdGlvbihhLGIsYyxkLGUsZil7dmFyIHQscz1lPT09ImZpbGUiLHI9c3x8ZixxPWE9
+PW51bGwKaWYocSYmZD09bnVsbClyZXR1cm4gcz8iLyI6IiIKcT0hcQppZihxJiZkIT1udWxsKXRocm93
+IEguYihQLnhZKCJCb3RoIHBhdGggYW5kIHBhdGhTZWdtZW50cyBzcGVjaWZpZWQiKSkKaWYocSl0PVAu
+UEkoYSxiLGMsQy5XZCwhMCkKZWxzZXtkLnRvU3RyaW5nCnE9SC50NihkKQp0PW5ldyBILmxKKGQscS5D
+KCJxVSgxKSIpLmEobmV3IFAuUlooKSkscS5DKCJsSjwxLHFVPiIpKS5IKDAsIi8iKX1pZih0Lmxlbmd0
+aD09PTApe2lmKHMpcmV0dXJuIi8ifWVsc2UgaWYociYmIUMueEIubih0LCIvIikpdD0iLyIrdApyZXR1
+cm4gUC5Kcih0LGUsZil9LApKcjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9Yi5sZW5ndGg9PT0wCmlmKHQm
+JiFjJiYhQy54Qi5uKGEsIi8iKSlyZXR1cm4gUC53RihhLCF0fHxjKQpyZXR1cm4gUC54ZShhKX0sCmxl
+OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHM9e30KaWYoYSE9bnVsbCl7aWYoZCE9bnVsbCl0aHJvdyBI
+LmIoUC54WSgiQm90aCBxdWVyeSBhbmQgcXVlcnlQYXJhbWV0ZXJzIHNwZWNpZmllZCIpKQpyZXR1cm4g
+UC5QSShhLGIsYyxDLlZDLCEwKX1pZihkPT1udWxsKXJldHVybiBudWxsCnQ9bmV3IFAuUm4oIiIpCnMu
+YT0iIgpkLksoMCxuZXcgUC55NShuZXcgUC5NRShzLHQpKSkKcz10LmEKcmV0dXJuIHMuY2hhckNvZGVB
+dCgwKT09MD9zOnN9LAp0RzpmdW5jdGlvbihhLGIsYyl7aWYoYT09bnVsbClyZXR1cm4gbnVsbApyZXR1
+cm4gUC5QSShhLGIsYyxDLlZDLCEwKX0sCnJ2OmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG89
+YisyCmlmKG8+PWEubGVuZ3RoKXJldHVybiIlIgp0PUMueEIubShhLGIrMSkKcz1DLnhCLm0oYSxvKQpy
+PUgub28odCkKcT1ILm9vKHMpCmlmKHI8MHx8cTwwKXJldHVybiIlIgpwPXIqMTYrcQppZihwPDEyNyl7
+bz1DLmpuLndHKHAsNCkKaWYobz49OClyZXR1cm4gSC5rKEMuRjMsbykKbz0oQy5GM1tvXSYxPDwocCYx
+NSkpIT09MH1lbHNlIG89ITEKaWYobylyZXR1cm4gSC5MdyhjJiY2NTw9cCYmOTA+PXA/KHB8MzIpPj4+
+MDpwKQppZih0Pj05N3x8cz49OTcpcmV0dXJuIEMueEIuTmooYSxiLGIrMykudG9VcHBlckNhc2UoKQpy
+ZXR1cm4gbnVsbH0sCnpYOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuPSIwMTIzNDU2Nzg5QUJD
+REVGIgppZihhPDEyOCl7dD1uZXcgQXJyYXkoMykKdC5maXhlZCRsZW5ndGg9QXJyYXkKcz1ILlZNKHQs
+dS50KQpDLk5tLlkocywwLDM3KQpDLk5tLlkocywxLEMueEIuVyhuLGE+Pj40KSkKQy5ObS5ZKHMsMixD
+LnhCLlcobixhJjE1KSl9ZWxzZXtpZihhPjIwNDcpaWYoYT42NTUzNSl7cj0yNDAKcT00fWVsc2V7cj0y
+MjQKcT0zfWVsc2V7cj0xOTIKcT0yfXQ9bmV3IEFycmF5KDMqcSkKdC5maXhlZCRsZW5ndGg9QXJyYXkK
+cz1ILlZNKHQsdS50KQpmb3IocD0wOy0tcSxxPj0wO3I9MTI4KXtvPUMuam4uYmYoYSw2KnEpJjYzfHIK
+Qy5ObS5ZKHMscCwzNykKQy5ObS5ZKHMscCsxLEMueEIuVyhuLG8+Pj40KSkKQy5ObS5ZKHMscCsyLEMu
+eEIuVyhuLG8mMTUpKQpwKz0zfX1yZXR1cm4gUC5ITShzLDAsbnVsbCl9LApQSTpmdW5jdGlvbihhLGIs
+YyxkLGUpe3ZhciB0PVAuVWwoYSxiLGMsZCxlKQpyZXR1cm4gdD09bnVsbD9DLnhCLk5qKGEsYixjKTp0
+fSwKVWw6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzLHIscSxwLG89bnVsbCxuPSFlLG09YixsPW0s
+az1vCndoaWxlKCEwKXtpZih0eXBlb2YgbSE9PSJudW1iZXIiKXJldHVybiBtLkooKQppZih0eXBlb2Yg
+YyE9PSJudW1iZXIiKXJldHVybiBILnBZKGMpCmlmKCEobTxjKSlicmVhawpjJDA6e3Q9Qy54Qi5tKGEs
+bSkKaWYodDwxMjcpe3M9dD4+PjQKaWYocz49OClyZXR1cm4gSC5rKGQscykKcz0oZFtzXSYxPDwodCYx
+NSkpIT09MH1lbHNlIHM9ITEKaWYocykrK20KZWxzZXtpZih0PT09Mzcpe3I9UC5ydihhLG0sITEpCmlm
+KHI9PW51bGwpe20rPTMKYnJlYWsgYyQwfWlmKCIlIj09PXIpe3I9IiUyNSIKcT0xfWVsc2UgcT0zfWVs
+c2V7aWYobilpZih0PD05Myl7cz10Pj4+NAppZihzPj04KXJldHVybiBILmsoQy5hayxzKQpzPShDLmFr
+W3NdJjE8PCh0JjE1KSkhPT0wfWVsc2Ugcz0hMQplbHNlIHM9ITEKaWYocyl7UC5SMyhhLG0sIkludmFs
+aWQgY2hhcmFjdGVyIikKcT1vCnI9cX1lbHNle2lmKCh0JjY0NTEyKT09PTU1Mjk2KXtzPW0rMQppZihz
+PGMpe3A9Qy54Qi5tKGEscykKaWYoKHAmNjQ1MTIpPT09NTYzMjApe3Q9NjU1MzZ8KHQmMTAyMyk8PDEw
+fHAmMTAyMwpxPTJ9ZWxzZSBxPTF9ZWxzZSBxPTF9ZWxzZSBxPTEKcj1QLnpYKHQpfX1pZihrPT1udWxs
+KWs9bmV3IFAuUm4oIiIpCmsuYSs9Qy54Qi5OaihhLGwsbSkKay5hKz1ILmQocikKaWYodHlwZW9mIHEh
+PT0ibnVtYmVyIilyZXR1cm4gSC5wWShxKQptKz1xCmw9bX19fWlmKGs9PW51bGwpcmV0dXJuIG8KaWYo
+dHlwZW9mIGwhPT0ibnVtYmVyIilyZXR1cm4gbC5KKCkKaWYobDxjKWsuYSs9Qy54Qi5OaihhLGwsYykK
+bj1rLmEKcmV0dXJuIG4uY2hhckNvZGVBdCgwKT09MD9uOm59LAp5QjpmdW5jdGlvbihhKXtpZihDLnhC
+Lm4oYSwiLiIpKXJldHVybiEwCnJldHVybiBDLnhCLk9ZKGEsIi8uIikhPT0tMX0sCnhlOmZ1bmN0aW9u
+KGEpe3ZhciB0LHMscixxLHAsbyxuCmlmKCFQLnlCKGEpKXJldHVybiBhCnQ9SC5WTShbXSx1LnMpCmZv
+cihzPWEuc3BsaXQoIi8iKSxyPXMubGVuZ3RoLHE9ITEscD0wO3A8cjsrK3Ape289c1twXQppZihKLlJN
+KG8sIi4uIikpe249dC5sZW5ndGgKaWYobiE9PTApe2lmKDA+PW4pcmV0dXJuIEguayh0LC0xKQp0LnBv
+cCgpCmlmKHQubGVuZ3RoPT09MClDLk5tLmkodCwiIil9cT0hMH1lbHNlIGlmKCIuIj09PW8pcT0hMApl
+bHNle0MuTm0uaSh0LG8pCnE9ITF9fWlmKHEpQy5ObS5pKHQsIiIpCnJldHVybiBDLk5tLkgodCwiLyIp
+fSwKd0Y6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8KaWYoIVAueUIoYSkpcmV0dXJuIWI/UC5D
+MShhKTphCnQ9SC5WTShbXSx1LnMpCmZvcihzPWEuc3BsaXQoIi8iKSxyPXMubGVuZ3RoLHE9ITEscD0w
+O3A8cjsrK3Ape289c1twXQppZigiLi4iPT09bylpZih0Lmxlbmd0aCE9PTAmJkMuTm0uZ3JaKHQpIT09
+Ii4uIil7aWYoMD49dC5sZW5ndGgpcmV0dXJuIEguayh0LC0xKQp0LnBvcCgpCnE9ITB9ZWxzZXtDLk5t
+LmkodCwiLi4iKQpxPSExfWVsc2UgaWYoIi4iPT09bylxPSEwCmVsc2V7Qy5ObS5pKHQsbykKcT0hMX19
+cz10Lmxlbmd0aAppZihzIT09MClpZihzPT09MSl7aWYoMD49cylyZXR1cm4gSC5rKHQsMCkKcz10WzBd
+Lmxlbmd0aD09PTB9ZWxzZSBzPSExCmVsc2Ugcz0hMAppZihzKXJldHVybiIuLyIKaWYocXx8Qy5ObS5n
+cloodCk9PT0iLi4iKUMuTm0uaSh0LCIiKQppZighYil7aWYoMD49dC5sZW5ndGgpcmV0dXJuIEguayh0
+LDApCkMuTm0uWSh0LDAsUC5DMSh0WzBdKSl9cmV0dXJuIEMuTm0uSCh0LCIvIil9LApDMTpmdW5jdGlv
+bihhKXt2YXIgdCxzLHIscT1hLmxlbmd0aAppZihxPj0yJiZQLkV0KEouUXooYSwwKSkpZm9yKHQ9MTt0
+PHE7Kyt0KXtzPUMueEIuVyhhLHQpCmlmKHM9PT01OClyZXR1cm4gQy54Qi5OaihhLDAsdCkrIiUzQSIr
+Qy54Qi5HKGEsdCsxKQppZihzPD0xMjcpe3I9cz4+PjQKaWYocj49OClyZXR1cm4gSC5rKEMubUsscikK
+cj0oQy5tS1tyXSYxPDwocyYxNSkpPT09MH1lbHNlIHI9ITAKaWYocilicmVha31yZXR1cm4gYX0sCm1u
+OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPWEuZ0ZqKCkscD1xLmxlbmd0aAppZihwPjAmJkouSChxWzBd
+KT09PTImJkouYTYocVswXSwxKT09PTU4KXtpZigwPj1wKXJldHVybiBILmsocSwwKQpQLnJnKEouYTYo
+cVswXSwwKSwhMSkKUC5ITihxLCExLDEpCnQ9ITB9ZWxzZXtQLkhOKHEsITEsMCkKdD0hMX1zPWEuZ3RU
+KCkmJiF0PyJcXCI6IiIKaWYoYS5nY2ooKSl7cj1hLmdKZihhKQppZihyLmxlbmd0aCE9PTApcz1zKyJc
+XCIrcisiXFwifXM9UC52ZyhzLHEsIlxcIikKcD10JiZwPT09MT9zKyJcXCI6cwpyZXR1cm4gcC5jaGFy
+Q29kZUF0KDApPT0wP3A6cH0sCkloOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyCmZvcih0PTAscz0wO3M8
+MjsrK3Mpe3I9Qy54Qi5XKGEsYitzKQppZig0ODw9ciYmcjw9NTcpdD10KjE2K3ItNDgKZWxzZXtyfD0z
+MgppZig5Nzw9ciYmcjw9MTAyKXQ9dCoxNityLTg3CmVsc2UgdGhyb3cgSC5iKFAueFkoIkludmFsaWQg
+VVJMIGVuY29kaW5nIikpfX1yZXR1cm4gdH0sCmt1OmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxy
+LHEscD1KLnJZKGEpLG89Ygp3aGlsZSghMCl7aWYoIShvPGMpKXt0PSEwCmJyZWFrfXM9cC5XKGEsbykK
+aWYoczw9MTI3KWlmKHMhPT0zNylyPWUmJnM9PT00MwplbHNlIHI9ITAKZWxzZSByPSEwCmlmKHIpe3Q9
+ITEKYnJlYWt9KytvfWlmKHQpe2lmKEMueE0hPT1kKXI9ITEKZWxzZSByPSEwCmlmKHIpcmV0dXJuIHAu
+TmooYSxiLGMpCmVsc2UgcT1uZXcgSC5xaihwLk5qKGEsYixjKSl9ZWxzZXtxPUguVk0oW10sdS50KQpm
+b3Iobz1iO288YzsrK28pe3M9cC5XKGEsbykKaWYocz4xMjcpdGhyb3cgSC5iKFAueFkoIklsbGVnYWwg
+cGVyY2VudCBlbmNvZGluZyBpbiBVUkkiKSkKaWYocz09PTM3KXtpZihvKzM+YS5sZW5ndGgpdGhyb3cg
+SC5iKFAueFkoIlRydW5jYXRlZCBVUkkiKSkKQy5ObS5pKHEsUC5JaChhLG8rMSkpCm8rPTJ9ZWxzZSBp
+ZihlJiZzPT09NDMpQy5ObS5pKHEsMzIpCmVsc2UgQy5ObS5pKHEscyl9fXUuTC5hKHEpCnJldHVybiBu
+ZXcgUC5HWSghMSkuV0oocSl9LApFdDpmdW5jdGlvbihhKXt2YXIgdD1hfDMyCnJldHVybiA5Nzw9dCYm
+dDw9MTIyfSwKS0Q6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG0sbD0iSW52YWxpZCBN
+SU1FIHR5cGUiLGs9SC5WTShbYi0xXSx1LnQpCmZvcih0PWEubGVuZ3RoLHM9YixyPS0xLHE9bnVsbDtz
+PHQ7KytzKXtxPUMueEIuVyhhLHMpCmlmKHE9PT00NHx8cT09PTU5KWJyZWFrCmlmKHE9PT00Nyl7aWYo
+cjwwKXtyPXMKY29udGludWV9dGhyb3cgSC5iKFAucnIobCxhLHMpKX19aWYocjwwJiZzPmIpdGhyb3cg
+SC5iKFAucnIobCxhLHMpKQpmb3IoO3EhPT00NDspe0MuTm0uaShrLHMpOysrcwpmb3IocD0tMTtzPHQ7
+KytzKXtxPUMueEIuVyhhLHMpCmlmKHE9PT02MSl7aWYocDwwKXA9c31lbHNlIGlmKHE9PT01OXx8cT09
+PTQ0KWJyZWFrfWlmKHA+PTApQy5ObS5pKGsscCkKZWxzZXtvPUMuTm0uZ3JaKGspCmlmKHEhPT00NHx8
+cyE9PW8rN3x8IUMueEIuUWkoYSwiYmFzZTY0IixvKzEpKXRocm93IEguYihQLnJyKCJFeHBlY3Rpbmcg
+Jz0nIixhLHMpKQpicmVha319Qy5ObS5pKGsscykKbj1zKzEKaWYoKGsubGVuZ3RoJjEpPT09MSlhPUMu
+aDkueXIoYSxuLHQpCmVsc2V7bT1QLlVsKGEsbix0LEMuVkMsITApCmlmKG0hPW51bGwpYT1DLnhCLmk3
+KGEsbix0LG0pfXJldHVybiBuZXcgUC5QRShhLGssYyl9LApLTjpmdW5jdGlvbigpe3ZhciB0PSIwMTIz
+NDU2Nzg5QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ei0u
+X34hJCYnKCkqKyw7PSIscz0iLiIscj0iOiIscT0iLyIscD0iPyIsbz0iIyIsbj11LmdjLG09UC5kSCgy
+MixuZXcgUC5xMygpLG4pLGw9bmV3IFAueUkobSksaz1uZXcgUC5jNigpLGo9bmV3IFAucWQoKSxpPW4u
+YShsLiQyKDAsMjI1KSkKay4kMyhpLHQsMSkKay4kMyhpLHMsMTQpCmsuJDMoaSxyLDM0KQprLiQzKGks
+cSwzKQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigxNCwyMjUpKQprLiQzKGks
+dCwxKQprLiQzKGkscywxNSkKay4kMyhpLHIsMzQpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQpr
+LiQzKGksbywyMDUpCmk9bi5hKGwuJDIoMTUsMjI1KSkKay4kMyhpLHQsMSkKay4kMyhpLCIlIiwyMjUp
+CmsuJDMoaSxyLDM0KQprLiQzKGkscSw5KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEo
+bC4kMigxLDIyNSkpCmsuJDMoaSx0LDEpCmsuJDMoaSxyLDM0KQprLiQzKGkscSwxMCkKay4kMyhpLHAs
+MTcyKQprLiQzKGksbywyMDUpCmk9bi5hKGwuJDIoMiwyMzUpKQprLiQzKGksdCwxMzkpCmsuJDMoaSxx
+LDEzMSkKay4kMyhpLHMsMTQ2KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigz
+LDIzNSkpCmsuJDMoaSx0LDExKQprLiQzKGkscSw2OCkKay4kMyhpLHMsMTgpCmsuJDMoaSxwLDE3MikK
+ay4kMyhpLG8sMjA1KQppPW4uYShsLiQyKDQsMjI5KSkKay4kMyhpLHQsNSkKai4kMyhpLCJBWiIsMjI5
+KQprLiQzKGksciwxMDIpCmsuJDMoaSwiQCIsNjgpCmsuJDMoaSwiWyIsMjMyKQprLiQzKGkscSwxMzgp
+CmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQppPW4uYShsLiQyKDUsMjI5KSkKay4kMyhpLHQsNSkK
+ai4kMyhpLCJBWiIsMjI5KQprLiQzKGksciwxMDIpCmsuJDMoaSwiQCIsNjgpCmsuJDMoaSxxLDEzOCkK
+ay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5hKGwuJDIoNiwyMzEpKQpqLiQzKGksIjE5Iiw3
+KQprLiQzKGksIkAiLDY4KQprLiQzKGkscSwxMzgpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8sMjA1KQpp
+PW4uYShsLiQyKDcsMjMxKSkKai4kMyhpLCIwOSIsNykKay4kMyhpLCJAIiw2OCkKay4kMyhpLHEsMTM4
+KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKay4kMyhuLmEobC4kMig4LDgpKSwiXSIsNSkKaT1u
+LmEobC4kMig5LDIzNSkpCmsuJDMoaSx0LDExKQprLiQzKGkscywxNikKay4kMyhpLHEsMjM0KQprLiQz
+KGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigxNiwyMzUpKQprLiQzKGksdCwxMSkKay4k
+MyhpLHMsMTcpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUpCmk9bi5hKGwu
+JDIoMTcsMjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxxLDkpCmsuJDMoaSxwLDE3MikKay4kMyhpLG8s
+MjA1KQppPW4uYShsLiQyKDEwLDIzNSkpCmsuJDMoaSx0LDExKQprLiQzKGkscywxOCkKay4kMyhpLHEs
+MjM0KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigxOCwyMzUpKQprLiQzKGks
+dCwxMSkKay4kMyhpLHMsMTkpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcyKQprLiQzKGksbywyMDUp
+Cmk9bi5hKGwuJDIoMTksMjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxxLDIzNCkKay4kMyhpLHAsMTcy
+KQprLiQzKGksbywyMDUpCmk9bi5hKGwuJDIoMTEsMjM1KSkKay4kMyhpLHQsMTEpCmsuJDMoaSxxLDEw
+KQprLiQzKGkscCwxNzIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigxMiwyMzYpKQprLiQzKGksdCwx
+MikKay4kMyhpLHAsMTIpCmsuJDMoaSxvLDIwNSkKaT1uLmEobC4kMigxMywyMzcpKQprLiQzKGksdCwx
+MykKay4kMyhpLHAsMTMpCmouJDMobi5hKGwuJDIoMjAsMjQ1KSksImF6IiwyMSkKbD1uLmEobC4kMigy
+MSwyNDUpKQpqLiQzKGwsImF6IiwyMSkKai4kMyhsLCIwOSIsMjEpCmsuJDMobCwiKy0uIiwyMSkKcmV0
+dXJuIG19LApVQjpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0LHMscixxLHAsbz0kLnZaKCkKZm9yKHQ9
+Si5yWShhKSxzPWI7czxjOysrcyl7aWYoZDwwfHxkPj1vLmxlbmd0aClyZXR1cm4gSC5rKG8sZCkKcj1v
+W2RdCnE9dC5XKGEscyleOTYKaWYocT45NSlxPTMxCmlmKHE+PXIubGVuZ3RoKXJldHVybiBILmsocixx
+KQpwPXJbcV0KZD1wJjMxCkMuTm0uWShlLHA+Pj41LHMpfXJldHVybiBkfSwKV0Y6ZnVuY3Rpb24gV0Yo
+YSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCmEyOmZ1bmN0aW9uIGEyKCl7fSwKaVA6ZnVuY3Rpb24gaVAo
+YSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkNQOmZ1bmN0aW9uIENQKCl7fSwKWFM6ZnVuY3Rpb24gWFMo
+KXt9LApDNjpmdW5jdGlvbiBDNihhKXt0aGlzLmE9YX0sCkxLOmZ1bmN0aW9uIExLKCl7fSwKQVQ6ZnVu
+Y3Rpb24gQVQoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCmJKOmZ1
+bmN0aW9uIGJKKGEsYixjLGQsZSxmKXt2YXIgXz10aGlzCl8uZT1hCl8uZj1iCl8uYT1jCl8uYj1kCl8u
+Yz1lCl8uZD1mfSwKZVk6ZnVuY3Rpb24gZVkoYSxiLGMsZCxlKXt2YXIgXz10aGlzCl8uZj1hCl8uYT1i
+Cl8uYj1jCl8uYz1kCl8uZD1lfSwKbXA6ZnVuY3Rpb24gbXAoYSxiLGMsZCl7dmFyIF89dGhpcwpfLmE9
+YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCnViOmZ1bmN0aW9uIHViKGEpe3RoaXMuYT1hfSwKZHM6ZnVuY3Rp
+b24gZHMoYSl7dGhpcy5hPWF9LApsajpmdW5jdGlvbiBsaihhKXt0aGlzLmE9YX0sClVWOmZ1bmN0aW9u
+IFVWKGEpe3RoaXMuYT1hfSwKazU6ZnVuY3Rpb24gazUoKXt9LApLWTpmdW5jdGlvbiBLWSgpe30sCnQ3
+OmZ1bmN0aW9uIHQ3KGEpe3RoaXMuYT1hfSwKQ0Q6ZnVuY3Rpb24gQ0QoYSl7dGhpcy5hPWF9LAphRTpm
+dW5jdGlvbiBhRShhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApFSDpmdW5jdGlvbiBF
+SCgpe30sCklmOmZ1bmN0aW9uIElmKCl7fSwKY1g6ZnVuY3Rpb24gY1goKXt9LApBbjpmdW5jdGlvbiBB
+bigpe30sCnpNOmZ1bmN0aW9uIHpNKCl7fSwKWjA6ZnVuY3Rpb24gWjAoKXt9LApOMzpmdW5jdGlvbiBO
+MyhhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy4kdGk9Y30sCmM4OmZ1bmN0aW9uIGM4KCl7fSwK
+bGY6ZnVuY3Rpb24gbGYoKXt9LApNaDpmdW5jdGlvbiBNaCgpe30sCk9kOmZ1bmN0aW9uIE9kKCl7fSwK
+aWI6ZnVuY3Rpb24gaWIoKXt9LAp4dTpmdW5jdGlvbiB4dSgpe30sCkd6OmZ1bmN0aW9uIEd6KCl7fSwK
+WmQ6ZnVuY3Rpb24gWmQoKXt9LApxVTpmdW5jdGlvbiBxVSgpe30sClJuOmZ1bmN0aW9uIFJuKGEpe3Ro
+aXMuYT1hfSwKR0Q6ZnVuY3Rpb24gR0QoKXt9LApuMTpmdW5jdGlvbiBuMShhKXt0aGlzLmE9YX0sCmNT
+OmZ1bmN0aW9uIGNTKGEpe3RoaXMuYT1hfSwKVkM6ZnVuY3Rpb24gVkMoYSl7dGhpcy5hPWF9LApKVDpm
+dW5jdGlvbiBKVChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKRG46ZnVuY3Rpb24gRG4oYSxiLGMsZCxl
+LGYsZyl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9ZgpfLnI9Zwpf
+LlE9Xy56PV8ueT1fLng9bnVsbH0sCmUxOmZ1bmN0aW9uIGUxKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9
+LApOWTpmdW5jdGlvbiBOWShhKXt0aGlzLmE9YX0sClJaOmZ1bmN0aW9uIFJaKCl7fSwKTUU6ZnVuY3Rp
+b24gTUUoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCnk1OmZ1bmN0aW9uIHk1KGEpe3RoaXMuYT1hfSwK
+UEU6ZnVuY3Rpb24gUEUoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKcTM6ZnVuY3Rp
+b24gcTMoKXt9LAp5STpmdW5jdGlvbiB5SShhKXt0aGlzLmE9YX0sCmM2OmZ1bmN0aW9uIGM2KCl7fSwK
+cWQ6ZnVuY3Rpb24gcWQoKXt9LApVZjpmdW5jdGlvbiBVZihhLGIsYyxkLGUsZixnLGgpe3ZhciBfPXRo
+aXMKXy5hPWEKXy5iPWIKXy5jPWMKXy5kPWQKXy5lPWUKXy5mPWYKXy5yPWcKXy54PWgKXy55PW51bGx9
+LApxZTpmdW5jdGlvbiBxZShhLGIsYyxkLGUsZixnKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1j
+Cl8uZD1kCl8uZT1lCl8uZj1mCl8ucj1nCl8uUT1fLno9Xy55PV8ueD1udWxsfSwKaUo6ZnVuY3Rpb24g
+aUooKXt9LApqZzpmdW5jdGlvbiBqZyhhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKVGE6ZnVuY3Rpb24g
+VGEoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkJmOmZ1bmN0aW9uIEJmKGEsYil7dGhpcy5hPWEKdGhp
+cy5iPWJ9LApBczpmdW5jdGlvbiBBcygpe30sCkdFOmZ1bmN0aW9uIEdFKGEpe3RoaXMuYT1hfSwKTjc6
+ZnVuY3Rpb24gTjcoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCnVROmZ1bmN0aW9uIHVRKCl7fSwKaEY6
+ZnVuY3Rpb24gaEYoKXt9LApSNDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIKSC5FOShiKQp1Lmou
+YShkKQppZihILm9UKGIpKXt0PVtjXQpDLk5tLkZWKHQsZCkKZD10fXM9dS56CnI9UC5DSChKLk0xKGQs
+UC53MCgpLHMpLCEwLHMpCnUuWi5hKGEpCnJldHVybiBQLndZKEguRWsoYSxyLG51bGwpKX0sCkRtOmZ1
+bmN0aW9uKGEsYixjKXt2YXIgdAp0cnl7aWYoT2JqZWN0LmlzRXh0ZW5zaWJsZShhKSYmIU9iamVjdC5w
+cm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChhLGIpKXtPYmplY3QuZGVmaW5lUHJvcGVydHkoYSxi
+LHt2YWx1ZTpjfSkKcmV0dXJuITB9fWNhdGNoKHQpe0guUnUodCl9cmV0dXJuITF9LApPbTpmdW5jdGlv
+bihhLGIpe2lmKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChhLGIpKXJldHVybiBh
+W2JdCnJldHVybiBudWxsfSwKd1k6ZnVuY3Rpb24oYSl7aWYoYT09bnVsbHx8dHlwZW9mIGE9PSJzdHJp
+bmcifHx0eXBlb2YgYT09Im51bWJlciJ8fEguclEoYSkpcmV0dXJuIGEKaWYoYSBpbnN0YW5jZW9mIFAu
+RTQpcmV0dXJuIGEuYQppZihILlI5KGEpKXJldHVybiBhCmlmKHUudS5iKGEpKXJldHVybiBhCmlmKGEg
+aW5zdGFuY2VvZiBQLmlQKXJldHVybiBILm8yKGEpCmlmKHUuWi5iKGEpKXJldHVybiBQLmhFKGEsIiRk
+YXJ0X2pzRnVuY3Rpb24iLG5ldyBQLlBDKCkpCnJldHVybiBQLmhFKGEsIl8kZGFydF9qc09iamVjdCIs
+bmV3IFAubXQoJC5rSSgpKSl9LApoRTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9UC5PbShhLGIpCmlmKHQ9
+PW51bGwpe3Q9Yy4kMShhKQpQLkRtKGEsYix0KX1yZXR1cm4gdH0sCkw3OmZ1bmN0aW9uKGEpe3ZhciB0
+LHMKaWYoYT09bnVsbHx8dHlwZW9mIGE9PSJzdHJpbmcifHx0eXBlb2YgYT09Im51bWJlciJ8fHR5cGVv
+ZiBhPT0iYm9vbGVhbiIpcmV0dXJuIGEKZWxzZSBpZihhIGluc3RhbmNlb2YgT2JqZWN0JiZILlI5KGEp
+KXJldHVybiBhCmVsc2UgaWYoYSBpbnN0YW5jZW9mIE9iamVjdCYmdS51LmIoYSkpcmV0dXJuIGEKZWxz
+ZSBpZihhIGluc3RhbmNlb2YgRGF0ZSl7dD1ILldZKGEuZ2V0VGltZSgpKQppZihNYXRoLmFicyh0KTw9
+ODY0ZTEzKXM9ITEKZWxzZSBzPSEwCmlmKHMpSC52aChQLnhZKCJEYXRlVGltZSBpcyBvdXRzaWRlIHZh
+bGlkIHJhbmdlOiAiK3QpKQpQLlVJKCExLCJpc1V0YyIsdS55KQpyZXR1cm4gbmV3IFAuaVAodCwhMSl9
+ZWxzZSBpZihhLmNvbnN0cnVjdG9yPT09JC5rSSgpKXJldHVybiBhLm8KZWxzZSByZXR1cm4gUC5ORChh
+KX0sCk5EOmZ1bmN0aW9uKGEpe2lmKHR5cGVvZiBhPT0iZnVuY3Rpb24iKXJldHVybiBQLmlRKGEsJC53
+USgpLG5ldyBQLk56KCkpCmlmKGEgaW5zdGFuY2VvZiBBcnJheSlyZXR1cm4gUC5pUShhLCQuQ3IoKSxu
+ZXcgUC5RUygpKQpyZXR1cm4gUC5pUShhLCQuQ3IoKSxuZXcgUC5ucCgpKX0sCmlROmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdD1QLk9tKGEsYikKaWYodD09bnVsbHx8IShhIGluc3RhbmNlb2YgT2JqZWN0KSl7dD1j
+LiQxKGEpClAuRG0oYSxiLHQpfXJldHVybiB0fSwKUEM6ZnVuY3Rpb24gUEMoKXt9LAptdDpmdW5jdGlv
+biBtdChhKXt0aGlzLmE9YX0sCk56OmZ1bmN0aW9uIE56KCl7fSwKUVM6ZnVuY3Rpb24gUVMoKXt9LApu
+cDpmdW5jdGlvbiBucCgpe30sCkU0OmZ1bmN0aW9uIEU0KGEpe3RoaXMuYT1hfSwKcjc6ZnVuY3Rpb24g
+cjcoYSl7dGhpcy5hPWF9LApUejpmdW5jdGlvbiBUeihhLGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApj
+bzpmdW5jdGlvbiBjbygpe30sCm5kOmZ1bmN0aW9uIG5kKCl7fSwKS2U6ZnVuY3Rpb24gS2UoYSl7dGhp
+cy5hPWF9LApkNTpmdW5jdGlvbiBkNSgpe30sCm42OmZ1bmN0aW9uIG42KCl7fX0sVz17CngzOmZ1bmN0
+aW9uKCl7cmV0dXJuIHdpbmRvd30sClpyOmZ1bmN0aW9uKCl7cmV0dXJuIGRvY3VtZW50fSwKSjY6ZnVu
+Y3Rpb24oYSl7dmFyIHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpCmlmKGEhPW51bGwpdC5ocmVm
+PWEKcmV0dXJuIHR9LApVOTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9ZG9jdW1lbnQuYm9keSxzPSh0JiZD
+LlJZKS5yNih0LGEsYixjKQpzLnRvU3RyaW5nCnQ9dS5hYwp0PW5ldyBILlU1KG5ldyBXLmU3KHMpLHQu
+QygiYTIobEQuRSkiKS5hKG5ldyBXLkN2KCkpLHQuQygiVTU8bEQuRT4iKSkKcmV0dXJuIHUuaC5hKHQu
+Z3I4KHQpKX0sCnJTOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj0iZWxlbWVudCB0YWcgdW5hdmFpbGFibGUi
+CnRyeXt0PUouUkUoYSkKaWYodHlwZW9mIHQuZ25zKGEpPT0ic3RyaW5nIilyPXQuZ25zKGEpfWNhdGNo
+KHMpe0guUnUocyl9cmV0dXJuIHJ9LApDMDpmdW5jdGlvbihhLGIpe2E9NTM2ODcwOTExJmErYgphPTUz
+Njg3MDkxMSZhKygoNTI0Mjg3JmEpPDwxMCkKcmV0dXJuIGFeYT4+PjZ9LApyRTpmdW5jdGlvbihhLGIs
+YyxkKXt2YXIgdD1XLkMwKFcuQzAoVy5DMChXLkMwKDAsYSksYiksYyksZCkscz01MzY4NzA5MTEmdCso
+KDY3MTA4ODYzJnQpPDwzKQpzXj1zPj4+MTEKcmV0dXJuIDUzNjg3MDkxMSZzKygoMTYzODMmcyk8PDE1
+KX0sClROOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyPWEuY2xhc3NMaXN0CmZvcih0PWIubGVuZ3RoLHM9
+MDtzPGIubGVuZ3RoO2IubGVuZ3RoPT09dHx8KDAsSC5saykoYiksKytzKXIuYWRkKGJbc10pfSwKSkU6
+ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdD1XLmFGKG5ldyBXLnZOKGMpLHUuQikKaWYodCE9bnVsbCYm
+ITApSi5kWihhLGIsdCwhMSkKcmV0dXJuIG5ldyBXLnhDKGEsYix0LCExLGUuQygieEM8MD4iKSl9LApU
+dzpmdW5jdGlvbihhKXt2YXIgdD1XLko2KG51bGwpLHM9d2luZG93LmxvY2F0aW9uCnQ9bmV3IFcuSlEo
+bmV3IFcubWsodCxzKSkKdC5DWShhKQpyZXR1cm4gdH0sCnFEOmZ1bmN0aW9uKGEsYixjLGQpe3UuaC5h
+KGEpCkguYyhiKQpILmMoYykKdS5PLmEoZCkKcmV0dXJuITB9LApRVzpmdW5jdGlvbihhLGIsYyxkKXt2
+YXIgdCxzLHIKdS5oLmEoYSkKSC5jKGIpCkguYyhjKQp0PXUuTy5hKGQpLmEKcz10LmEKcy5ocmVmPWMK
+cj1zLmhvc3RuYW1lCnQ9dC5iCmlmKCEocj09dC5ob3N0bmFtZSYmcy5wb3J0PT10LnBvcnQmJnMucHJv
+dG9jb2w9PXQucHJvdG9jb2wpKWlmKHI9PT0iIilpZihzLnBvcnQ9PT0iIil7dD1zLnByb3RvY29sCnQ9
+dD09PSI6Inx8dD09PSIifWVsc2UgdD0hMQplbHNlIHQ9ITEKZWxzZSB0PSEwCnJldHVybiB0fSwKQmw6
+ZnVuY3Rpb24oKXt2YXIgdD11Lk4scz1QLnRNKEMuUXgsdCkscj11LmRHLmEobmV3IFcuSUEoKSkscT1I
+LlZNKFsiVEVNUExBVEUiXSx1LnMpCnQ9bmV3IFcuY3QocyxQLkxzKHQpLFAuTHModCksUC5Mcyh0KSxu
+dWxsKQp0LkNZKG51bGwsbmV3IEgubEooQy5ReCxyLHUuZHYpLHEsbnVsbCkKcmV0dXJuIHR9LApQdjpm
+dW5jdGlvbihhKXtpZihhPT1udWxsKXJldHVybiBudWxsCnJldHVybiBXLlAxKGEpfSwKcWM6ZnVuY3Rp
+b24oYSl7dmFyIHQKaWYoYT09bnVsbClyZXR1cm4gbnVsbAppZigicG9zdE1lc3NhZ2UiIGluIGEpe3Q9
+Vy5QMShhKQppZih1LnIuYih0KSlyZXR1cm4gdApyZXR1cm4gbnVsbH1lbHNlIHJldHVybiB1LnIuYShh
+KX0sClAxOmZ1bmN0aW9uKGEpe2lmKGE9PT13aW5kb3cpcmV0dXJuIHUuY2kuYShhKQplbHNlIHJldHVy
+biBuZXcgVy5kVyhhKX0sCkhIOmZ1bmN0aW9uKGEpe2lmKGE9PT13aW5kb3cubG9jYXRpb24pcmV0dXJu
+IGEKZWxzZSByZXR1cm4gbmV3IFcuRmIoKX0sCmFGOmZ1bmN0aW9uKGEsYil7dmFyIHQ9JC5YMwppZih0
+PT09Qy5OVSlyZXR1cm4gYQpyZXR1cm4gdC5QeShhLGIpfSwKcUU6ZnVuY3Rpb24gcUUoKXt9LApHaDpm
+dW5jdGlvbiBHaCgpe30sCmZZOmZ1bmN0aW9uIGZZKCl7fSwKbkI6ZnVuY3Rpb24gbkIoKXt9LApBejpm
+dW5jdGlvbiBBeigpe30sClFQOmZ1bmN0aW9uIFFQKCl7fSwKbng6ZnVuY3Rpb24gbngoKXt9LApvSjpm
+dW5jdGlvbiBvSigpe30sCmlkOmZ1bmN0aW9uIGlkKCl7fSwKUUY6ZnVuY3Rpb24gUUYoKXt9LApOaDpm
+dW5jdGlvbiBOaCgpe30sCklCOmZ1bmN0aW9uIElCKCl7fSwKbjc6ZnVuY3Rpb24gbjcoKXt9LAp3ejpm
+dW5jdGlvbiB3eihhLGIpe3RoaXMuYT1hCnRoaXMuJHRpPWJ9LApjdjpmdW5jdGlvbiBjdigpe30sCkN2
+OmZ1bmN0aW9uIEN2KCl7fSwKZWE6ZnVuY3Rpb24gZWEoKXt9LApEMDpmdW5jdGlvbiBEMCgpe30sCmhI
+OmZ1bmN0aW9uIGhIKCl7fSwKaDQ6ZnVuY3Rpb24gaDQoKXt9LApicjpmdW5jdGlvbiBicigpe30sClZi
+OmZ1bmN0aW9uIFZiKCl7fSwKZko6ZnVuY3Rpb24gZkooKXt9LAp3YTpmdW5jdGlvbiB3YSgpe30sClNn
+OmZ1bmN0aW9uIFNnKCl7fSwKdTg6ZnVuY3Rpb24gdTgoKXt9LApPSzpmdW5jdGlvbiBPSygpe30sCmU3
+OmZ1bmN0aW9uIGU3KGEpe3RoaXMuYT1hfSwKdUg6ZnVuY3Rpb24gdUgoKXt9LApCSDpmdW5jdGlvbiBC
+SCgpe30sClNOOmZ1bmN0aW9uIFNOKCl7fSwKZXc6ZnVuY3Rpb24gZXcoKXt9LApscDpmdW5jdGlvbiBs
+cCgpe30sClRiOmZ1bmN0aW9uIFRiKCl7fSwKSXY6ZnVuY3Rpb24gSXYoKXt9LApXUDpmdW5jdGlvbiBX
+UCgpe30sCnlZOmZ1bmN0aW9uIHlZKCl7fSwKdzY6ZnVuY3Rpb24gdzYoKXt9LApLNTpmdW5jdGlvbiBL
+NSgpe30sCkNtOmZ1bmN0aW9uIENtKCl7fSwKQ1E6ZnVuY3Rpb24gQ1EoKXt9LAp3NDpmdW5jdGlvbiB3
+NCgpe30sCnJoOmZ1bmN0aW9uIHJoKCl7fSwKY2Y6ZnVuY3Rpb24gY2YoKXt9LAppNzpmdW5jdGlvbiBp
+NyhhKXt0aGlzLmE9YX0sClN5OmZ1bmN0aW9uIFN5KGEpe3RoaXMuYT1hfSwKS1M6ZnVuY3Rpb24gS1Mo
+YSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkEzOmZ1bmN0aW9uIEEzKGEsYil7dGhpcy5hPWEKdGhpcy5i
+PWJ9LApJNDpmdW5jdGlvbiBJNChhKXt0aGlzLmE9YX0sCkZrOmZ1bmN0aW9uIEZrKGEsYil7dGhpcy5h
+PWEKdGhpcy4kdGk9Yn0sClJPOmZ1bmN0aW9uIFJPKGEsYixjLGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5i
+PWIKXy5jPWMKXy4kdGk9ZH0sCmV1OmZ1bmN0aW9uIGV1KGEsYixjLGQpe3ZhciBfPXRoaXMKXy5hPWEK
+Xy5iPWIKXy5jPWMKXy4kdGk9ZH0sCnhDOmZ1bmN0aW9uIHhDKGEsYixjLGQsZSl7dmFyIF89dGhpcwpf
+LmI9YQpfLmM9YgpfLmQ9YwpfLmU9ZApfLiR0aT1lfSwKdk46ZnVuY3Rpb24gdk4oYSl7dGhpcy5hPWF9
+LApKUTpmdW5jdGlvbiBKUShhKXt0aGlzLmE9YX0sCkdtOmZ1bmN0aW9uIEdtKCl7fSwKdkQ6ZnVuY3Rp
+b24gdkQoYSl7dGhpcy5hPWF9LApVdjpmdW5jdGlvbiBVdihhKXt0aGlzLmE9YX0sCkVnOmZ1bmN0aW9u
+IEVnKGEsYixjKXt0aGlzLmE9YQp0aGlzLmI9Ygp0aGlzLmM9Y30sCm02OmZ1bmN0aW9uIG02KCl7fSwK
+RW86ZnVuY3Rpb24gRW8oKXt9LApXazpmdW5jdGlvbiBXaygpe30sCmN0OmZ1bmN0aW9uIGN0KGEsYixj
+LGQsZSl7dmFyIF89dGhpcwpfLmU9YQpfLmE9YgpfLmI9YwpfLmM9ZApfLmQ9ZX0sCklBOmZ1bmN0aW9u
+IElBKCl7fSwKT3c6ZnVuY3Rpb24gT3coKXt9LApXOTpmdW5jdGlvbiBXOShhLGIsYyl7dmFyIF89dGhp
+cwpfLmE9YQpfLmI9YgpfLmM9LTEKXy5kPW51bGwKXy4kdGk9Y30sCmRXOmZ1bmN0aW9uIGRXKGEpe3Ro
+aXMuYT1hfSwKRmI6ZnVuY3Rpb24gRmIoKXt9LAprRjpmdW5jdGlvbiBrRigpe30sCm1rOmZ1bmN0aW9u
+IG1rKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApLbzpmdW5jdGlvbiBLbyhhKXt0aGlzLmE9YQp0aGlz
+LmI9ITF9LApmbTpmdW5jdGlvbiBmbShhKXt0aGlzLmE9YX0sCkxlOmZ1bmN0aW9uIExlKCl7fSwKSzc6
+ZnVuY3Rpb24gSzcoKXt9LApyQjpmdW5jdGlvbiByQigpe30sClhXOmZ1bmN0aW9uIFhXKCl7fSwKb2E6
+ZnVuY3Rpb24gb2EoKXt9fSxNPXsKT1g6ZnVuY3Rpb24oYSl7c3dpdGNoKGEpe2Nhc2UgQy5BZDpyZXR1
+cm4iQWRkIC8qPyovIGhpbnQiCmNhc2UgQy5uZTpyZXR1cm4iQWRkIC8qISovIGhpbnQiCmNhc2UgQy53
+VjpyZXR1cm4iUmVtb3ZlIC8qPyovIGhpbnQiCmNhc2UgQy5mUjpyZXR1cm4iUmVtb3ZlIC8qISovIGhp
+bnQiCmNhc2UgQy5teTpyZXR1cm4iQ2hhbmdlIHRvIC8qPyovIGhpbnQiCmNhc2UgQy5yeDpyZXR1cm4i
+Q2hhbmdlIHRvIC8qISovIGhpbnQifXJldHVybiBudWxsfSwKSDc6ZnVuY3Rpb24gSDcoYSxiKXt0aGlz
+LmE9YQp0aGlzLmI9Yn0sCllGOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscCxvLG4KZm9yKHQ9Yi5s
+ZW5ndGgscz0xO3M8dDsrK3Mpe2lmKGJbc109PW51bGx8fGJbcy0xXSE9bnVsbCljb250aW51ZQpmb3Io
+O3Q+PTE7dD1yKXtyPXQtMQppZihiW3JdIT1udWxsKWJyZWFrfXE9bmV3IFAuUm4oIiIpCnA9YSsiKCIK
+cS5hPXAKbz1ILnFDKGIsMCx0LEgudDYoYikuYykKbj1vLiR0aQpuPXArbmV3IEgubEoobyxuLkMoInFV
+KGFMLkUpIikuYShuZXcgTS5ObygpKSxuLkMoImxKPGFMLkUscVU+IikpLkgoMCwiLCAiKQpxLmE9bgpx
+LmE9bisoIik6IHBhcnQgIisocy0xKSsiIHdhcyBudWxsLCBidXQgcGFydCAiK3MrIiB3YXMgbm90LiIp
+CnRocm93IEguYihQLnhZKHEuWigwKSkpfX0sCmxJOmZ1bmN0aW9uIGxJKGEpe3RoaXMuYT1hfSwKTWk6
+ZnVuY3Rpb24gTWkoKXt9LApxNzpmdW5jdGlvbiBxNygpe30sCk5vOmZ1bmN0aW9uIE5vKCl7fX0sVT17
+Cm56OmZ1bmN0aW9uKGEpe3ZhciB0PUguV1koYS5xKDAsIm5vZGVJZCIpKQpyZXR1cm4gbmV3IFUuTEwo
+Qy5ObS5IdChDLnJrLG5ldyBVLk1EKGEpKSx0KX0sCkxMOmZ1bmN0aW9uIExMKGEsYil7dGhpcy5hPWEK
+dGhpcy5iPWJ9LApNRDpmdW5jdGlvbiBNRChhKXt0aGlzLmE9YX0sCmpmOmZ1bmN0aW9uKGEpe3ZhciB0
+LHMscixxCmlmKGE9PW51bGwpdD1udWxsCmVsc2V7dD1ILlZNKFtdLHUuZkEpCmZvcihzPUouSVQodS5S
+LmEoYSkpO3MuRigpOyl7cj1zLmdsKCkKcT1KLlU2KHIpCkMuTm0uaSh0LG5ldyBVLlNlKEguYyhxLnEo
+ciwiZGVzY3JpcHRpb24iKSksSC5jKHEucShyLCJocmVmIikpKSl9fXJldHVybiB0fSwKTmQ6ZnVuY3Rp
+b24oYSl7dmFyIHQscwppZihhPT1udWxsKXQ9bnVsbAplbHNle3Q9SC5WTShbXSx1LmhoKQpmb3Iocz1K
+LklUKHUuUi5hKGEpKTtzLkYoKTspQy5ObS5pKHQsVS5KaihzLmdsKCkpKX1yZXR1cm4gdH0sCkpqOmZ1
+bmN0aW9uKGEpe3ZhciB0PUouVTYoYSkscz1ILmModC5xKGEsImRlc2NyaXB0aW9uIikpLHI9SC5WTShb
+XSx1LmFKKQpmb3IodD1KLklUKHUuUi5hKHQucShhLCJlbnRyaWVzIikpKTt0LkYoKTspQy5ObS5pKHIs
+VS5Saih0LmdsKCkpKQpyZXR1cm4gbmV3IFUueUQocyxyKX0sClJqOmZ1bmN0aW9uKGEpe3ZhciB0LHM9
+Si5VNihhKSxyPUguYyhzLnEoYSwiZGVzY3JpcHRpb24iKSkscT1ILmMocy5xKGEsImZ1bmN0aW9uIikp
+LHA9cy5xKGEsImxpbmsiKQppZihwPT1udWxsKXA9bnVsbAplbHNle3Q9Si5VNihwKQpwPW5ldyBVLk1s
+KEguYyh0LnEocCwiaHJlZiIpKSxILldZKHQucShwLCJsaW5lIikpLEguYyh0LnEocCwicGF0aCIpKSl9
+cz11LmouYShzLnEoYSwiaGludEFjdGlvbnMiKSkKcz1zPT1udWxsP251bGw6Si5NMShzLG5ldyBVLmFO
+KCksdS5FKQpzPXM9PW51bGw/bnVsbDpzLmJyKDApCnJldHVybiBuZXcgVS53YihyLHEscCxzPT1udWxs
+P0MuZG46cyl9LApkMjpmdW5jdGlvbiBkMihhLGIsYyxkLGUsZil7dmFyIF89dGhpcwpfLmE9YQpfLmI9
+YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9Zn0sClNlOmZ1bmN0aW9uIFNlKGEsYil7dGhpcy5hPWEKdGhp
+cy5iPWJ9LApNbDpmdW5jdGlvbiBNbChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LAp5
+RDpmdW5jdGlvbiB5RChhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKd2I6ZnVuY3Rpb24gd2IoYSxiLGMs
+ZCl7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZH0sCmFOOmZ1bmN0aW9uIGFOKCl7fSwK
+YjA6ZnVuY3Rpb24gYjAoKXt9fSxCPXsKWWY6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG4sbSxs
+PUguYyhhLnEoMCwicmVnaW9ucyIpKSxrPUguYyhhLnEoMCwibmF2aWdhdGlvbkNvbnRlbnQiKSksaj1I
+LmMoYS5xKDAsInNvdXJjZUNvZGUiKSksaT1QLkZsKHUuTix1LmY0KQpmb3IodD11LlMuYShhLnEoMCwi
+ZWRpdHMiKSksdD10LmdQdSh0KSx0PXQuZ2t6KHQpLHM9dS5SLHI9dS5naTt0LkYoKTspe3E9dC5nbCgp
+CnA9cS5hCm89SC5WTShbXSxyKQpmb3IocT1KLklUKHMuYShxLmIpKTtxLkYoKTspe249cS5nbCgpCm09
+Si5VNihuKQpDLk5tLmkobyxuZXcgQi5qOChILldZKG0ucShuLCJsaW5lIikpLEguYyhtLnEobiwiZXhw
+bGFuYXRpb24iKSksSC5XWShtLnEobiwib2Zmc2V0IikpKSl9aS5ZKDAscCxvKX1yZXR1cm4gbmV3IEIu
+cXAobCxrLGosaSl9LApqODpmdW5jdGlvbiBqOChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5j
+PWN9LApxcDpmdW5jdGlvbiBxcChhLGIsYyxkKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8u
+ZD1kfSwKZnY6ZnVuY3Rpb24gZnYoKXt9LApPUzpmdW5jdGlvbihhKXt2YXIgdAppZighKGE+PTY1JiZh
+PD05MCkpdD1hPj05NyYmYTw9MTIyCmVsc2UgdD0hMApyZXR1cm4gdH0sCll1OmZ1bmN0aW9uKGEsYil7
+dmFyIHQ9YS5sZW5ndGgscz1iKzIKaWYodDxzKXJldHVybiExCmlmKCFCLk9TKEMueEIubShhLGIpKSly
+ZXR1cm4hMQppZihDLnhCLm0oYSxiKzEpIT09NTgpcmV0dXJuITEKaWYodD09PXMpcmV0dXJuITAKcmV0
+dXJuIEMueEIubShhLHMpPT09NDd9fSxUPXttUTpmdW5jdGlvbiBtUSgpe319LEw9ewpJcTpmdW5jdGlv
+bigpe0MuQlouQihkb2N1bWVudCwiRE9NQ29udGVudExvYWRlZCIsbmV3IEwuZSgpKQpDLm9sLkIod2lu
+ZG93LCJwb3BzdGF0ZSIsbmV3IEwuTCgpKX0sCmt6OmZ1bmN0aW9uKGEpe3ZhciB0LHM9dS5oLmEoYS5w
+YXJlbnROb2RlKS5xdWVyeVNlbGVjdG9yKCI6c2NvcGUgPiB1bCIpLHI9cy5zdHlsZSxxPSIiK0MuQ0Qu
+elEocy5vZmZzZXRIZWlnaHQpKjIrInB4IgpyLm1heEhlaWdodD1xCnI9Si5xRihhKQpxPXIuJHRpCnQ9
+cS5DKCJ+KDEpIikuYShuZXcgTC5XeChzLGEpKQp1Lk0uYShudWxsKQpXLkpFKHIuYSxyLmIsdCwhMSxx
+LmMpfSwKeVg6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG89InF1ZXJ5U2VsZWN0b3JBbGwiLG49
+ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihhKSxtPXUuaApuLnRvU3RyaW5nCkguRGgobSxtLCJUIixvKQp0
+PXUuVApzPW5ldyBXLnd6KG4ucXVlcnlTZWxlY3RvckFsbCgiLm5hdi1saW5rIiksdCkKcy5LKHMsbmV3
+IEwuQU8oYikpCkguRGgobSxtLCJUIixvKQpyPW5ldyBXLnd6KG4ucXVlcnlTZWxlY3RvckFsbCgiLnJl
+Z2lvbiIpLHQpCmlmKHIuZ0EocikhPT0wKXtxPW4ucXVlcnlTZWxlY3RvcigidGFibGVbZGF0YS1wYXRo
+XSIpCnEudG9TdHJpbmcKci5LKHIsbmV3IEwuSG8ocS5nZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5T
+eShuZXcgVy5pNyhxKSkuTygicGF0aCIpKSkpfUguRGgobSxtLCJUIixvKQpwPW5ldyBXLnd6KG4ucXVl
+cnlTZWxlY3RvckFsbCgiLmFkZC1oaW50LWxpbmsiKSx0KQpwLksocCxuZXcgTC5JQygpKX0sClE2OmZ1
+bmN0aW9uKGEsYixjKXt2YXIgdD1uZXcgWE1MSHR0cFJlcXVlc3QoKQpDLkR0LmVvKHQsIkdFVCIsTC5R
+NChhLGIpLCEwKQp0LnNldFJlcXVlc3RIZWFkZXIoIkNvbnRlbnQtVHlwZSIsImFwcGxpY2F0aW9uL2pz
+b247IGNoYXJzZXQ9VVRGLTgiKQpyZXR1cm4gTC5MVSh0LG51bGwsYyl9LAp0eTpmdW5jdGlvbihhLGIp
+e3ZhciB0PW5ldyBYTUxIdHRwUmVxdWVzdCgpLHM9dS5OCkMuRHQuZW8odCwiUE9TVCIsTC5RNChhLFAu
+RmwocyxzKSksITApCnQuc2V0UmVxdWVzdEhlYWRlcigiQ29udGVudC1UeXBlIiwiYXBwbGljYXRpb24v
+anNvbjsgY2hhcnNldD1VVEYtOCIpCnJldHVybiBMLkxVKHQsYix1LlMpfSwKTFU6ZnVuY3Rpb24oYSxi
+LGMpe3JldHVybiBMLlRnKGEsYixjLGMpfSwKVGc6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQ9MCxzPVAu
+RlgoZCkscixxPTIscCxvPVtdLG4sbSxsLGssaixpLGgsZwp2YXIgJGFzeW5jJExVPVAubHooZnVuY3Rp
+b24oZSxmKXtpZihlPT09MSl7cD1mCnQ9cX13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6aj1uZXcg
+UC5aZihuZXcgUC52cygkLlgzLHUuYW8pLHUuYmopCmk9dS5hbgpoPWkuYShuZXcgTC5mQyhqLGEpKQp1
+Lk0uYShudWxsKQptPXUuRgpXLkpFKGEsImxvYWQiLGgsITEsbSkKVy5KRShhLCJlcnJvciIsaS5hKGou
+Z1lKKCkpLCExLG0pCmEuc2VuZChiPT1udWxsP251bGw6Qy5DdC5PQihiLG51bGwpKQpxPTQKdD03CnJl
+dHVybiBQLmpRKGouYSwkYXN5bmMkTFUpCmNhc2UgNzpxPTIKdD02CmJyZWFrCmNhc2UgNDpxPTMKZz1w
+CkguUnUoZykKbj1ILnRzKGcpCmk9UC5UbCgiRXJyb3IgcmVhY2hpbmcgbWlncmF0aW9uIHByZXZpZXcg
+c2VydmVyLiIsbikKdGhyb3cgSC5iKGkpCnQ9NgpicmVhawpjYXNlIDM6dD0yCmJyZWFrCmNhc2UgNjpr
+PUMuQ3QucFcoMCxhLnJlc3BvbnNlVGV4dCxudWxsKQppZihhLnN0YXR1cz09PTIwMCl7cj1jLmEoaykK
+dD0xCmJyZWFrfWVsc2UgdGhyb3cgSC5iKGspCmNhc2UgMTpyZXR1cm4gUC55QyhyLHMpCmNhc2UgMjpy
+ZXR1cm4gUC5mMyhwLHMpfX0pCnJldHVybiBQLkRJKCRhc3luYyRMVSxzKX0sCmFLOmZ1bmN0aW9uKGEp
+e3ZhciB0PVAuaEsoYSkuZ2hZKCkucSgwLCJsaW5lIikKcmV0dXJuIHQ9PW51bGw/bnVsbDpILkhwKHQs
+bnVsbCl9LApHNjpmdW5jdGlvbihhKXt2YXIgdD1QLmhLKGEpLmdoWSgpLnEoMCwib2Zmc2V0IikKcmV0
+dXJuIHQ9PW51bGw/bnVsbDpILkhwKHQsbnVsbCl9LAppNjpmdW5jdGlvbihhKXtyZXR1cm4gTC5uVyh1
+LlYuYShhKSl9LApuVzpmdW5jdGlvbihhKXt2YXIgdD0wLHM9UC5GWCh1LnopLHI9MSxxLHA9W10sbyxu
+LG0sbCxrCnZhciAkYXN5bmMkaTY9UC5seihmdW5jdGlvbihiLGMpe2lmKGI9PT0xKXtxPWMKdD1yfXdo
+aWxlKHRydWUpc3dpdGNoKHQpe2Nhc2UgMDpsPXUuaC5hKFcucWMoYS5jdXJyZW50VGFyZ2V0KSkuZ2V0
+QXR0cmlidXRlKCJocmVmIikKYS5wcmV2ZW50RGVmYXVsdCgpCnI9Mwp0PTYKcmV0dXJuIFAualEoTC50
+eShsLG51bGwpLCRhc3luYyRpNikKY2FzZSA2OnUuYV8uYShKLkdyKFcuUHYoZG9jdW1lbnQuZGVmYXVs
+dFZpZXcpKSkucmVsb2FkKCkKcj0xCnQ9NQpicmVhawpjYXNlIDM6cj0yCms9cQpvPUguUnUoaykKbj1I
+LnRzKGspCkwuQzIoIkNvdWxkIG5vdCBhZGQvcmVtb3ZlIGhpbnQiLG8sbikKdD01CmJyZWFrCmNhc2Ug
+Mjp0PTEKYnJlYWsKY2FzZSA1OnJldHVybiBQLnlDKG51bGwscykKY2FzZSAxOnJldHVybiBQLmYzKHEs
+cyl9fSkKcmV0dXJuIFAuREkoJGFzeW5jJGk2LHMpfSwKQzI6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMs
+cj0iZXhjZXB0aW9uIixxPSJzdGFja1RyYWNlIixwPXUuUy5iKGIpJiZKLlJNKGIucSgwLCJzdWNjZXNz
+IiksITEpJiZILm9UKGIueDQocikpJiZILm9UKGIueDQocSkpLG89Si5pYShiKQppZihwKXt0PUguYyhv
+LnEoYixyKSkKYz1vLnEoYixxKX1lbHNlIHQ9by5aKGIpCnA9ZG9jdW1lbnQKcz1wLnF1ZXJ5U2VsZWN0
+b3IoIi5wb3B1cC1wYW5lIikKcy5xdWVyeVNlbGVjdG9yKCJoMiIpLmlubmVyVGV4dD1hCnMucXVlcnlT
+ZWxlY3RvcigicCIpLmlubmVyVGV4dD10CnMucXVlcnlTZWxlY3RvcigicHJlIikuaW5uZXJUZXh0PUou
+QWMoYykKbz11Lk4KdS5icS5hKHMucXVlcnlTZWxlY3RvcigiYS5ib3R0b20iKSkuaHJlZj1QLlhkKCJo
+dHRwcyIsImdpdGh1Yi5jb20iLCJkYXJ0LWxhbmcvc2RrL2lzc3Vlcy9uZXciLFAuRUYoWyJ0aXRsZSIs
+IkN1c3RvbWVyLXJlcG9ydGVkIGlzc3VlIHdpdGggTk5CRCBtaWdyYXRpb24gdG9vbDogIithLCJsYWJl
+bHMiLCJhcmVhLWFuYWx5emVyLGFuYWx5emVyLW5uYmQtbWlncmF0aW9uLHR5cGUtYnVnIiwiYm9keSIs
+YSsiXG5cbkVycm9yOiAiK0guZCh0KSsiXG5cblBsZWFzZSBmaWxsIGluIHRoZSBmb2xsb3dpbmc6XG5c
+bioqTmFtZSBvZiBwYWNrYWdlIGJlaW5nIG1pZ3JhdGVkIChpZiBwdWJsaWMpKio6XG4qKldoYXQgSSB3
+YXMgZG9pbmcgd2hlbiB0aGlzIGlzc3VlIG9jY3VycmVkKio6XG4qKklzIGl0IHBvc3NpYmxlIHRvIHdv
+cmsgYXJvdW5kIHRoaXMgaXNzdWUqKjpcbioqSGFzIHRoaXMgaXNzdWUgaGFwcGVuZWQgYmVmb3JlLCBh
+bmQgaWYgc28sIGhvdyBvZnRlbioqOlxuKipEYXJ0IFNESyB2ZXJzaW9uKio6ICIrSC5kKHAuZ2V0RWxl
+bWVudEJ5SWQoInNkay12ZXJzaW9uIikudGV4dENvbnRlbnQpKyJcbioqQWRkaXRpb25hbCBkZXRhaWxz
+Kio6XG5cblRoYW5rcyBmb3IgZmlsaW5nIVxuXG5TdGFja3RyYWNlOiBfYXV0byBwb3B1bGF0ZWQgYnkg
+bWlncmF0aW9uIHByZXZpZXcgdG9vbC5fXG5cbmBgYFxuIitILmQoYykrIlxuYGBgXG4iXSxvLG8pKS5a
+KDApCm89cy5zdHlsZQpvLmRpc3BsYXk9ImluaXRpYWwiCnA9YSsiOiAiK0guZChiKQp3aW5kb3cKaWYo
+dHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLmVycm9yKHApCndpbmRvdwpw
+PUguZChjKQppZih0eXBlb2YgY29uc29sZSE9InVuZGVmaW5lZCIpd2luZG93LmNvbnNvbGUuZXJyb3Io
+cCl9LAp0MjpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscD17fSxvPXUuaC5hKFcucWMoYS5jdXJy
+ZW50VGFyZ2V0KSkKYS5wcmV2ZW50RGVmYXVsdCgpCnQ9cC5hPW8uZ2V0QXR0cmlidXRlKCJocmVmIikK
+cz1KLnpsKHQsIj8iKT9wLmE9Qy54Qi5Oaih0LDAsQy54Qi5PWSh0LCI/IikpOnQKcj1MLkc2KHQpCnE9
+TC5hSyh0KQppZihyIT1udWxsKUwuYWYocyxyLHEsYixuZXcgTC5uVChwLHIscSkpCmVsc2UgTC5hZihz
+LG51bGwsbnVsbCxiLG5ldyBMLkJaKHApKX0sCnZVOmZ1bmN0aW9uKCl7dmFyIHQ9ZG9jdW1lbnQscz11
+LmgKSC5EaChzLHMsIlQiLCJxdWVyeVNlbGVjdG9yQWxsIikKdD1uZXcgVy53eih0LnF1ZXJ5U2VsZWN0
+b3JBbGwoIi5jb2RlIiksdS5UKQp0LksodCxuZXcgTC5HSCgpKX0sCmhYOmZ1bmN0aW9uKGEsYixjKXty
+ZXR1cm4gTC5ZdyhhLGIsYyl9LApZdzpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9MCxzPVAuRlgodS56KSxy
+PTEscSxwPVtdLG8sbixtLGwsayxqLGksaAp2YXIgJGFzeW5jJGhYPVAubHooZnVuY3Rpb24oZCxlKXtp
+ZihkPT09MSl7cT1lCnQ9cn13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6cj0zCms9dS5OCnQ9Ngpy
+ZXR1cm4gUC5qUShMLlE2KGEsUC5FRihbInJlZ2lvbiIsInJlZ2lvbiIsIm9mZnNldCIsSC5kKGIpXSxr
+LGspLHUuUyksJGFzeW5jJGhYKQpjYXNlIDY6bz1lCms9bwpqPUouVTYoaykKbj1uZXcgVS5kMihVLmpm
+KGoucShrLCJlZGl0cyIpKSxILmMoai5xKGssImV4cGxhbmF0aW9uIikpLEguV1koai5xKGssImxpbmUi
+KSksSC5jKGoucShrLCJkaXNwbGF5UGF0aCIpKSxILmMoai5xKGssInVyaVBhdGgiKSksVS5OZChqLnEo
aywidHJhY2VzIikpKQpMLlQxKG4pCkwuRnIoYSxiLGMpCkwueVgoIi5lZGl0LXBhbmVsIC5wYW5lbC1j
b250ZW50IiwhMSkKcj0xCnQ9NQpicmVhawpjYXNlIDM6cj0yCmg9cQptPUguUnUoaCkKbD1ILnRzKGgp
CkwuQzIoIkNvdWxkIG5vdCBsb2FkIGVkaXQgZGV0YWlscyIsbSxsKQp0PTUKYnJlYWsKY2FzZSAyOnQ9
@@ -2116,2323 +2323,2338 @@
CnQ9NQpicmVhawpjYXNlIDM6cj0yCmk9cQptPUguUnUoaSkKbD1ILnRzKGkpCkwuQzIoIkNvdWxkIG5v
dCBsb2FkIG5hdmlnYXRpb24gdHJlZSIsbSxsKQp0PTUKYnJlYWsKY2FzZSAyOnQ9MQpicmVhawpjYXNl
IDU6cmV0dXJuIFAueUMobnVsbCxzKQpjYXNlIDE6cmV0dXJuIFAuZjMocSxzKX19KQpyZXR1cm4gUC5E
-SSgkYXN5bmMkR2Uscyl9LApxTzpmdW5jdGlvbihhKXt2YXIgdD1hLmdldEJvdW5kaW5nQ2xpZW50UmVj
-dCgpLHM9Qy5DRC56USgkLmZpKCkub2Zmc2V0SGVpZ2h0KSxyPXdpbmRvdy5pbm5lckhlaWdodCxxPUMu
-Q0QuelEoJC5EVygpLm9mZnNldEhlaWdodCkKaWYodHlwZW9mIHIhPT0ibnVtYmVyIilyZXR1cm4gci5I
-TigpCmlmKHQuYm90dG9tPnItKHErMTQpKUouZGgoYSkKZWxzZSBpZih0LnRvcDxzKzE0KUouZGgoYSl9
-LApmRzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAKaWYoYSE9bnVsbCl7dD1kb2N1bWVudApzPXQu
-Z2V0RWxlbWVudEJ5SWQoIm8iK0guZChhKSkKcj10LnF1ZXJ5U2VsZWN0b3IoIi5saW5lLSIrSC5kKGIp
-KQppZihzIT1udWxsKXtMLnFPKHMpCkouZFIocykuaSgwLCJ0YXJnZXQiKX1lbHNlIGlmKHIhPW51bGwp
-TC5xTyhyLnBhcmVudEVsZW1lbnQpCmlmKHIhPW51bGwpSi5kUih1LmguYShyLnBhcmVudE5vZGUpKS5p
-KDAsImhpZ2hsaWdodCIpfWVsc2V7dD1kb2N1bWVudApxPXUuaApILkRoKHEscSwiVCIsInF1ZXJ5U2Vs
-ZWN0b3JBbGwiKQp0PXQucXVlcnlTZWxlY3RvckFsbCgiLmxpbmUtbm8iKQpwPW5ldyBXLnd6KHQsdS5U
-KQppZihwLmdBKHApPT09MClyZXR1cm4KTC5xTyhxLmIoQy50NS5ndEgodCkpKX19LAphZjpmdW5jdGlv
-bihhLGIsYyxkLGUpe3ZhciB0LHMscj1MLkc2KHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxxPUwuYUsod2lu
-ZG93LmxvY2F0aW9uLmhyZWYpCmlmKHIhPW51bGwpe3Q9ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoIm8i
-K0guZChyKSkKaWYodCE9bnVsbClKLmRSKHQpLlIoMCwidGFyZ2V0Iil9aWYocSE9bnVsbCl7cz1kb2N1
-bWVudC5xdWVyeVNlbGVjdG9yKCIubGluZS0iK0guZChxKSkKaWYocyE9bnVsbClKLmRSKHMucGFyZW50
-RWxlbWVudCkuUigwLCJoaWdobGlnaHQiKX1pZihhPT13aW5kb3cubG9jYXRpb24ucGF0aG5hbWUpe0wu
-ZkcoYixjKQplLiQwKCl9ZWxzZSBMLkc3KGEsYixjLGQsZSl9LApRNDpmdW5jdGlvbihhLGIpe3ZhciB0
-LHMscj1QLmhLKGEpLHE9dS5OCnE9UC5GbChxLHEpCmZvcih0PXIuZ2hZKCksdD10LmdQdSh0KSx0PXQu
-Z2t6KHQpO3QuRigpOyl7cz10LmdsKCkKcS5ZKDAscy5hLHMuYil9Zm9yKHQ9Yi5nUHUoYiksdD10Lmdr
-eih0KTt0LkYoKTspe3M9dC5nbCgpCnEuWSgwLHMuYSxzLmIpfXEuWSgwLCJhdXRoVG9rZW4iLCQuVUUo
-KSkKcmV0dXJuIHIubm0oMCxxKS53KDApfSwKVDE6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG4s
-bSxsLGs9JC5oTCgpCkoubDUoaywiIikKaWYoYT09bnVsbCl7dD1kb2N1bWVudC5jcmVhdGVFbGVtZW50
-KCJwIikKdC50ZXh0Q29udGVudD0iU2VlIGRldGFpbHMgYWJvdXQgYSBwcm9wb3NlZCBlZGl0LiIKQy5M
-dC5zUCh0LEguVk0oWyJwbGFjZWhvbGRlciJdLHUucykpCmsuYXBwZW5kQ2hpbGQodCkKQy5MdC5GRih0
-KQpyZXR1cm59cz1hLmQKcj0kLm5VKCkKcT1yLnpmKHMpCnA9YS5iCm89ZG9jdW1lbnQKbj1yLkhQKHMs
-Si5UMChvLnF1ZXJ5U2VsZWN0b3IoIi5yb290IikudGV4dENvbnRlbnQpKQptPWEuYwpsPW8uY3JlYXRl
-RWxlbWVudCgicCIpCmsuYXBwZW5kQ2hpbGQobCkKbC5hcHBlbmRDaGlsZChvLmNyZWF0ZVRleHROb2Rl
-KEguZChwKSsiIGF0ICIpKQpyPXUuTgpyPVcuSjYoTC5RNChhLmUsUC5FRihbImxpbmUiLEouaihtKV0s
-cixyKSkpCnIuYXBwZW5kQ2hpbGQoby5jcmVhdGVUZXh0Tm9kZShILmQobikrIjoiK0guZChtKSsiLiIp
-KQpsLmFwcGVuZENoaWxkKHIpCkouZGgobCkKTC5DQyhhLGsscSkKTC5GeihhLGspfSwKTEg6ZnVuY3Rp
-b24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoLGc9JC55UCgpCkoubDUoZywiIikK
-aWYoYi5nQShiKT09PTApe3Q9ZG9jdW1lbnQKcz10LmNyZWF0ZUVsZW1lbnQoInAiKQpnLmFwcGVuZENo
-aWxkKHMpCnMuYXBwZW5kQ2hpbGQodC5jcmVhdGVUZXh0Tm9kZSgiTm8gcHJvcG9zZWQgZWRpdHMiKSl9
-ZWxzZSBmb3IoZz1iLmdQdShiKSxnPWcuZ2t6KGcpLHQ9dS5RLHI9dC5DKCJ+KDEpIikscT11Lk0sdD10
-LmQ7Zy5GKCk7KXtwPWcuZ2woKQpvPWRvY3VtZW50CnM9by5jcmVhdGVFbGVtZW50KCJwIikKbj0kLnlQ
-KCkKbi5hcHBlbmRDaGlsZChzKQpzLmFwcGVuZENoaWxkKG8uY3JlYXRlVGV4dE5vZGUoSC5kKHAuYSkr
-IjoiKSkKbT1vLmNyZWF0ZUVsZW1lbnQoInVsIikKbi5hcHBlbmRDaGlsZChtKQpmb3IocD1KLklUKHAu
-Yik7cC5GKCk7KXtuPXAuZ2woKQpsPW8uY3JlYXRlRWxlbWVudCgibGkiKQptLmFwcGVuZENoaWxkKGwp
-CkouZFIobCkuaSgwLCJlZGl0IikKaz1vLmNyZWF0ZUVsZW1lbnQoImEiKQpsLmFwcGVuZENoaWxkKGsp
-CmsuY2xhc3NMaXN0LmFkZCgiZWRpdC1saW5rIikKaj1uLmMKaT1ILmQoaikKay5zZXRBdHRyaWJ1dGUo
-ImRhdGEtIituZXcgVy5TeShuZXcgVy5pNyhrKSkuTygib2Zmc2V0IiksaSkKaD1uLmEKaT1ILmQoaCkK
-ay5zZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5TeShuZXcgVy5pNyhrKSkuTygibGluZSIpLGkpCmsu
-YXBwZW5kQ2hpbGQoby5jcmVhdGVUZXh0Tm9kZSgibGluZSAiK0guZChoKSkpCmk9ci5iKG5ldyBMLkVF
-KGosaCxhKSkKcS5iKG51bGwpClcuSkUoaywiY2xpY2siLGksITEsdCkKbC5hcHBlbmRDaGlsZChvLmNy
-ZWF0ZVRleHROb2RlKCI6ICIrSC5kKG4uYikpKX19aWYoYylMLlQxKG51bGwpfSwKRnI6ZnVuY3Rpb24o
-YSxiLGMpe3ZhciB0LHMscj13aW5kb3cubG9jYXRpb24scT1QLmhLKChyJiZDLkV4KS5nRHIocikrSC5k
-KGEpKQpyPXUuTgpyPVAuRmwocixyKQppZihiIT1udWxsKXIuWSgwLCJvZmZzZXQiLEguZChiKSkKaWYo
-YyE9bnVsbClyLlkoMCwibGluZSIsSC5kKGMpKQpyLlkoMCwiYXV0aFRva2VuIiwkLlVFKCkpCnE9cS5u
-bSgwLHIpCnI9d2luZG93Lmhpc3RvcnkKdD11LnoKcz1xLncoMCkKci50b1N0cmluZwpyLnB1c2hTdGF0
-ZShuZXcgUC5CZihbXSxbXSkuUHYoUC5GbCh0LHQpKSwiIixzKX0sCkVuOmZ1bmN0aW9uKGEpe3ZhciB0
-PUouYmIoZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLnJvb3QiKS50ZXh0Q29udGVudCwiLyIpCmlmKEMu
-eEIubihhLHQpKXJldHVybiBDLnhCLkcoYSx0Lmxlbmd0aCkKZWxzZSByZXR1cm4gYX0sCkJYOmZ1bmN0
-aW9uKGEsYil7dmFyIHQscyxyPXt9CnIuYT1hCmE9TC5FbihhKQpyLmE9YQokLkQ5KCkudGV4dENvbnRl
-bnQ9YQp0PWRvY3VtZW50CnM9dS5oCkguRGgocyxzLCJUIiwicXVlcnlTZWxlY3RvckFsbCIpCnQ9bmV3
-IFcud3oodC5xdWVyeVNlbGVjdG9yQWxsKCIubmF2LXBhbmVsIC5uYXYtbGluayIpLHUuVCkKdC5LKHQs
-bmV3IEwuVlMocikpfSwKQkU6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0PSIucmVnaW9ucyIscz1kb2N1bWVu
-dCxyPXMucXVlcnlTZWxlY3Rvcih0KSxxPXMucXVlcnlTZWxlY3RvcigiLmNvZGUiKQpKLnRIKHIsYi5h
-LCQuS0coKSkKSi50SChxLGIuYiwkLktHKCkpCkwuTEgoYSxiLmQsYykKTC52VSgpCkwueVgoIi5jb2Rl
-IiwhMCkKTC55WCh0LCEwKX0sCnRYOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscCxvLG4sbSxsLGss
-aixpLGgsZz1kb2N1bWVudCxmPWcuY3JlYXRlRWxlbWVudCgidWwiKQphLmFwcGVuZENoaWxkKGYpCmZv
-cih0PWIubGVuZ3RoLHM9dS5NLHI9MDtyPGIubGVuZ3RoO2IubGVuZ3RoPT09dHx8KDAsSC5saykoYiks
-KytyKXtxPWJbcl0KcD1nLmNyZWF0ZUVsZW1lbnQoImxpIikKZi5hcHBlbmRDaGlsZChwKQpvPUouUkUo
-cCkKaWYocS5hPT09Qy5ZMil7by5nUChwKS5pKDAsImRpciIpCm49Zy5jcmVhdGVFbGVtZW50KCJzcGFu
-IikKcC5hcHBlbmRDaGlsZChuKQpvPUouUkUobikKby5nUChuKS5pKDAsImFycm93IikKby5zaGYobiwi
-JiN4MjVCQzsiKQptPWcuY3JlYXRlRWxlbWVudCgic3BhbiIpCnAuYXBwZW5kQ2hpbGQobSkKSi5sNSht
-LCImI3gxRjRDMTsiKQpwLmFwcGVuZENoaWxkKGcuY3JlYXRlVGV4dE5vZGUocS5iKSkKTC50WChwLHEu
-YykKTC5reihuKX1lbHNle28uc2hmKHAsIiYjeDFGNEM0OyIpCmw9Zy5jcmVhdGVFbGVtZW50KCJhIikK
-cC5hcHBlbmRDaGlsZChsKQpvPUouUkUobCkKby5nUChsKS5pKDAsIm5hdi1saW5rIikKbC5zZXRBdHRy
-aWJ1dGUoImRhdGEtIituZXcgVy5TeShuZXcgVy5pNyhsKSkuTygibmFtZSIpLHEuZCkKbC5zZXRBdHRy
-aWJ1dGUoImhyZWYiLHEuZSkKbC5hcHBlbmRDaGlsZChnLmNyZWF0ZVRleHROb2RlKHEuYikpCm89by5n
-VmwobCkKaz1vLiR0aQpqPWsuQygifigxKSIpLmIobmV3IEwuVEQoKSkKcy5iKG51bGwpClcuSkUoby5h
-LG8uYixqLCExLGsuZCkKaT1xLmYKaWYodHlwZW9mIGkhPT0ibnVtYmVyIilyZXR1cm4gaS5vcygpCmlm
-KGk+MCl7aD1nLmNyZWF0ZUVsZW1lbnQoInNwYW4iKQpwLmFwcGVuZENoaWxkKGgpCkouZFIoaCkuaSgw
-LCJlZGl0LWNvdW50IikKbz0iIitpKyIgIgppZihpPT09MSlrPSJlZGl0IgplbHNlIGs9ImVkaXRzIgpo
-LnNldEF0dHJpYnV0ZSgidGl0bGUiLG8raykKaC5hcHBlbmRDaGlsZChnLmNyZWF0ZVRleHROb2RlKEMu
-am4udyhpKSkpfX19fSwKRno6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGk9
-YS5hCmlmKGk9PW51bGwpcmV0dXJuCnQ9ZG9jdW1lbnQKcz10LmNyZWF0ZUVsZW1lbnQoInAiKQpyPWIu
-YXBwZW5kQ2hpbGQocykKcz10LmNyZWF0ZUVsZW1lbnQoInNwYW4iKQpxPXUucwpKLk11KHMsSC5WTShb
-InR5cGUtZGVzY3JpcHRpb24iXSxxKSkKcy5hcHBlbmRDaGlsZCh0LmNyZWF0ZVRleHROb2RlKCJBY3Rp
-b25zIikpCnIuYXBwZW5kQ2hpbGQocykKci5hcHBlbmRDaGlsZCh0LmNyZWF0ZVRleHROb2RlKCI6Iikp
-CnA9dC5jcmVhdGVFbGVtZW50KCJwIikKYi5hcHBlbmRDaGlsZChwKQpmb3Iocz1pLmxlbmd0aCxvPXUu
-WCxuPTA7bjxpLmxlbmd0aDtpLmxlbmd0aD09PXN8fCgwLEgubGspKGkpLCsrbil7bT1pW25dCmw9dC5j
-cmVhdGVFbGVtZW50KCJhIikKcC5hcHBlbmRDaGlsZChsKQpsLmFwcGVuZENoaWxkKHQuY3JlYXRlVGV4
-dE5vZGUobS5hKSkKbC5zZXRBdHRyaWJ1dGUoImhyZWYiLG0uYikKaz1vLmIoSC5WTShbImFkZC1oaW50
-LWxpbmsiLCJiZWZvcmUtYXBwbHkiLCJidXR0b24iXSxxKSkKaj1KLmRSKGwpCmouVjEoMCkKai5GVigw
-LGspfX0sCkNDOmZ1bmN0aW9uKGE4LGE5LGIwKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxn
-LGYsZSxkLGMsYixhLGEwLGExLGEyLGEzLGE0LGE1LGE2LGE3CmZvcih0PWE4LmYscz10Lmxlbmd0aCxy
-PXUucyxxPXUuWCxwPXUuUSxvPXAuQygifigxKSIpLG49dS5NLHA9cC5kLG09MDttPHQubGVuZ3RoO3Qu
-bGVuZ3RoPT09c3x8KDAsSC5saykodCksKyttKXtsPXRbbV0Kaz1kb2N1bWVudApqPWsuY3JlYXRlRWxl
-bWVudCgicCIpCmk9cS5iKEguVk0oWyJ0cmFjZSJdLHIpKQpoPUouZFIoaikKaC5WMSgwKQpoLkZWKDAs
-aSkKZz1hOS5hcHBlbmRDaGlsZChqKQpqPWsuY3JlYXRlRWxlbWVudCgic3BhbiIpCmk9cS5iKEguVk0o
-WyJ0eXBlLWRlc2NyaXB0aW9uIl0scikpCmg9Si5kUihqKQpoLlYxKDApCmguRlYoMCxpKQpqLmFwcGVu
-ZENoaWxkKGsuY3JlYXRlVGV4dE5vZGUobC5hKSkKZy5hcHBlbmRDaGlsZChqKQpnLmFwcGVuZENoaWxk
-KGsuY3JlYXRlVGV4dE5vZGUoIjoiKSkKaj1rLmNyZWF0ZUVsZW1lbnQoInVsIikKaT1xLmIoSC5WTShb
-InRyYWNlIl0scikpCmg9Si5kUihqKQpoLlYxKDApCmguRlYoMCxpKQpmPWcuYXBwZW5kQ2hpbGQoaikK
-Zm9yKGo9bC5iLGk9ai5sZW5ndGgsZT0wO2U8ai5sZW5ndGg7ai5sZW5ndGg9PT1pfHwoMCxILmxrKShq
-KSwrK2Upe2Q9altlXQpjPWsuY3JlYXRlRWxlbWVudCgibGkiKQpmLmFwcGVuZENoaWxkKGMpCmI9ay5j
-cmVhdGVFbGVtZW50KCJzcGFuIikKYT1xLmIoSC5WTShbImZ1bmN0aW9uIl0scikpCmg9Si5kUihiKQpo
-LlYxKDApCmguRlYoMCxhKQphPWQuYgpMLmtEKGIsYT09bnVsbD8idW5rbm93biI6YSkKYy5hcHBlbmRD
-aGlsZChiKQphMD1kLmMKaWYoYTAhPW51bGwpe2MuYXBwZW5kQ2hpbGQoay5jcmVhdGVUZXh0Tm9kZSgi
-ICgiKSkKYTE9YTAuYgphMj1rLmNyZWF0ZUVsZW1lbnQoImEiKQphMi5hcHBlbmRDaGlsZChrLmNyZWF0
-ZVRleHROb2RlKEguZChhMC5jKSsiOiIrSC5kKGExKSkpCmEyLnNldEF0dHJpYnV0ZSgiaHJlZiIsYTAu
-YSkKYTIuY2xhc3NMaXN0LmFkZCgibmF2LWxpbmsiKQpjLmFwcGVuZENoaWxkKGEyKQpjLmFwcGVuZENo
-aWxkKGsuY3JlYXRlVGV4dE5vZGUoIikiKSl9Yy5hcHBlbmRDaGlsZChrLmNyZWF0ZVRleHROb2RlKCI6
-ICIpKQpiPWQuYQpMLmtEKGMsYj09bnVsbD8idW5rbm93biI6YikKYj1kLmQKaWYoYi5sZW5ndGghPT0w
-KXthPWsuY3JlYXRlRWxlbWVudCgicCIpCmEzPXEuYihILlZNKFsiZHJhd2VyIiwiYmVmb3JlLWFwcGx5
-Il0scikpCmg9Si5kUihhKQpoLlYxKDApCmguRlYoMCxhMykKYTQ9Yy5hcHBlbmRDaGlsZChhKQpmb3Io
-YT1iLmxlbmd0aCxhNT0wO2E1PGIubGVuZ3RoO2IubGVuZ3RoPT09YXx8KDAsSC5saykoYiksKythNSl7
-YTY9YlthNV0KYTM9ay5jcmVhdGVFbGVtZW50KCJidXR0b24iKQphNz1vLmIobmV3IEwuQVMoYTYsYTAp
-KQpuLmIobnVsbCkKVy5KRShhMywiY2xpY2siLGE3LCExLHApCmEzLmFwcGVuZENoaWxkKGsuY3JlYXRl
-VGV4dE5vZGUoTS5PWChhNi5hKSkpCmE0LmFwcGVuZENoaWxkKGEzKX19fX19LAprRDpmdW5jdGlvbihh
-LGIpe3ZhciB0LHMscj1ILlZNKGIuc3BsaXQoIi4iKSx1LnMpLHE9Qy5ObS5ndEgocikscD1kb2N1bWVu
-dAphLmFwcGVuZENoaWxkKHAuY3JlYXRlVGV4dE5vZGUocSkpCmZvcihxPUgucUMociwxLG51bGwsdS5O
-KSxxPW5ldyBILmE3KHEscS5nQShxKSxxLiR0aS5DKCJhNzxhTC5FPiIpKSx0PUouUkUoYSk7cS5GKCk7
-KXtzPXEuZAp0Lm56KGEsImJlZm9yZWVuZCIsIiYjODIwMzsuIixudWxsLG51bGwpCmEuYXBwZW5kQ2hp
-bGQocC5jcmVhdGVUZXh0Tm9kZShzKSl9fSwKZTpmdW5jdGlvbiBlKCl7fSwKVlc6ZnVuY3Rpb24gVlco
-YSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKb1o6ZnVuY3Rpb24gb1ooKXt9LApqcjpm
-dW5jdGlvbiBqcigpe30sCnFsOmZ1bmN0aW9uIHFsKCl7fSwKeTg6ZnVuY3Rpb24geTgoKXt9LApIaTpm
-dW5jdGlvbiBIaSgpe30sCkJUOmZ1bmN0aW9uIEJUKCl7fSwKTDpmdW5jdGlvbiBMKCl7fSwKV3g6ZnVu
-Y3Rpb24gV3goYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkFPOmZ1bmN0aW9uIEFPKGEpe3RoaXMuYT1h
-fSwKZE46ZnVuY3Rpb24gZE4oYSl7dGhpcy5hPWF9LApIbzpmdW5jdGlvbiBIbyhhKXt0aGlzLmE9YX0s
-Cnh6OmZ1bmN0aW9uIHh6KGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApJQzpmdW5jdGlvbiBJQygpe30s
-CmZDOmZ1bmN0aW9uIGZDKGEsYil7dGhpcy5hPWEKdGhpcy5iPWJ9LApuVDpmdW5jdGlvbiBuVChhLGIs
-Yyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApCWjpmdW5jdGlvbiBCWihhKXt0aGlzLmE9YX0s
-CkdIOmZ1bmN0aW9uIEdIKCl7fSwKRUU6ZnVuY3Rpb24gRUUoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1i
-CnRoaXMuYz1jfSwKUUw6ZnVuY3Rpb24gUUwoYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sClZTOmZ1bmN0
-aW9uIFZTKGEpe3RoaXMuYT1hfSwKVEQ6ZnVuY3Rpb24gVEQoKXt9LApBUzpmdW5jdGlvbiBBUyhhLGIp
-e3RoaXMuYT1hCnRoaXMuYj1ifSwKWEE6ZnVuY3Rpb24gWEEoKXt9LAptSzpmdW5jdGlvbihhKXt2YXIg
-dCxzLHIscSxwLG8sbj1ILlZNKFtdLHUuZmgpCmZvcih0PUouSVQodS5SLmIoYSkpO3QuRigpOyl7cz10
-LmdsKCkKcj1KLlU2KHMpCnE9TC5wMihILmMwKHIucShzLCJ0eXBlIikpKQpwPUguYzAoci5xKHMsIm5h
-bWUiKSkKbz1yLnEocywic3VidHJlZSIpCm89bz09bnVsbD9udWxsOkwubUsobykKQy5ObS5pKG4sbmV3
-IEwuWloocSxwLG8sSC5jMChyLnEocywicGF0aCIpKSxILmMwKHIucShzLCJocmVmIikpLEguV1koci5x
-KHMsImVkaXRDb3VudCIpKSkpfXJldHVybiBufSwKVkQ6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPUguVk0o
-W10sdS5KKQpmb3IodD1hLmxlbmd0aCxzPTA7czxhLmxlbmd0aDthLmxlbmd0aD09PXR8fCgwLEgubGsp
-KGEpLCsrcylDLk5tLmkocixhW3NdLkx0KCkpCnJldHVybiByfSwKcDI6ZnVuY3Rpb24oYSl7c3dpdGNo
-KGEpe2Nhc2UiZGlyZWN0b3J5IjpyZXR1cm4gQy5ZMgpjYXNlImZpbGUiOnJldHVybiBDLnJmCmRlZmF1
-bHQ6dGhyb3cgSC5iKFAuUFYoIlVucmVjb2duaXplZCBuYXZpZ2F0aW9uIHRyZWUgbm9kZSB0eXBlOiAi
-K0guZChhKSkpfX0sCnZ5OmZ1bmN0aW9uKGEpe3N3aXRjaChhKXtjYXNlIEMuWTI6cmV0dXJuImRpcmVj
-dG9yeSIKY2FzZSBDLnJmOnJldHVybiJmaWxlIn10aHJvdyBILmIoUC5QVigiVW5yZWNvZ25pemVkIG5h
-dmlnYXRpb24gdHJlZSBub2RlIHR5cGU6ICIrYS53KDApKSl9LApaWjpmdW5jdGlvbiBaWihhLGIsYyxk
-LGUsZil7dmFyIF89dGhpcwpfLmE9YQpfLmI9YgpfLmM9YwpfLmQ9ZApfLmU9ZQpfLmY9Zn0sCk85OmZ1
-bmN0aW9uIE85KGEpe3RoaXMuYj1hfSwKSVY6ZnVuY3Rpb24gSVYoYSxiLGMsZCl7dmFyIF89dGhpcwpf
-LmQ9YQpfLmU9YgpfLmY9YwpfLnI9ZH19LFg9ewpDTDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAs
-bz1iLnhaKGEpCmIuaEsoYSkKaWYobyE9bnVsbClhPUouS1YoYSxvLmxlbmd0aCkKdD11LnMKcz1ILlZN
-KFtdLHQpCnI9SC5WTShbXSx0KQp0PWEubGVuZ3RoCmlmKHQhPT0wJiZiLnI0KEMueEIuVyhhLDApKSl7
-aWYoMD49dClyZXR1cm4gSC5PSChhLDApCkMuTm0uaShyLGFbMF0pCnE9MX1lbHNle0MuTm0uaShyLCIi
-KQpxPTB9Zm9yKHA9cTtwPHQ7KytwKWlmKGIucjQoQy54Qi5XKGEscCkpKXtDLk5tLmkocyxDLnhCLk5q
-KGEscSxwKSkKQy5ObS5pKHIsYVtwXSkKcT1wKzF9aWYocTx0KXtDLk5tLmkocyxDLnhCLkcoYSxxKSkK
-Qy5ObS5pKHIsIiIpfXJldHVybiBuZXcgWC5XRChiLG8scyxyKX0sCldEOmZ1bmN0aW9uIFdEKGEsYixj
-LGQpe3ZhciBfPXRoaXMKXy5hPWEKXy5iPWIKXy5kPWMKXy5lPWR9LApJNzpmdW5jdGlvbihhKXtyZXR1
-cm4gbmV3IFguZHYoYSl9LApkdjpmdW5jdGlvbiBkdihhKXt0aGlzLmE9YX19LE89ewpSaDpmdW5jdGlv
-bigpe3ZhciB0LHM9bnVsbAppZihQLnVvKCkuZ0ZpKCkhPT0iZmlsZSIpcmV0dXJuICQuRWIoKQp0PVAu
-dW8oKQppZighQy54Qi5UYyh0LmdJaSh0KSwiLyIpKXJldHVybiAkLkViKCkKaWYoUC5LTChzLCJhL2Ii
-LHMscyxzLHMscykudDQoKT09PSJhXFxiIilyZXR1cm4gJC5LaygpCnJldHVybiAkLmJEKCl9LAp6TDpm
-dW5jdGlvbiB6TCgpe319LEU9e09GOmZ1bmN0aW9uIE9GKGEsYixjKXt0aGlzLmQ9YQp0aGlzLmU9Ygp0
-aGlzLmY9Y319LEY9e3J1OmZ1bmN0aW9uIHJ1KGEsYixjLGQpe3ZhciBfPXRoaXMKXy5kPWEKXy5lPWIK
-Xy5mPWMKXy5yPWR9fSxEPXsKUlg6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwPW51bGwKdHJ5e3A9UC51
-bygpfWNhdGNoKHQpe2lmKHUuZzguYyhILlJ1KHQpKSl7cz0kLkZmCmlmKHMhPW51bGwpcmV0dXJuIHMK
-dGhyb3cgdH1lbHNlIHRocm93IHR9aWYoSi5STShwLCQuSTYpKXJldHVybiAkLkZmCiQuSTY9cAppZigk
-LkhrKCk9PSQuRWIoKSlzPSQuRmY9cC5aSSgiLiIpLncoMCkKZWxzZXtyPXAudDQoKQpxPXIubGVuZ3Ro
-LTEKcz0kLkZmPXE9PT0wP3I6Qy54Qi5OaihyLDAscSl9cmV0dXJuIHN9fQp2YXIgdz1bQyxILEosUCxX
-LE0sVSxCLFQsTCxYLE8sRSxGLERdCmh1bmtIZWxwZXJzLnNldEZ1bmN0aW9uTmFtZXNJZk5lY2Vzc2Fy
-eSh3KQp2YXIgJD17fQpILmVvLnByb3RvdHlwZT17fQpKLnZCLnByb3RvdHlwZT17CkROOmZ1bmN0aW9u
-KGEsYil7cmV0dXJuIGE9PT1ifSwKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiBILmVRKGEpfSwKdzpmdW5j
-dGlvbihhKXtyZXR1cm4iSW5zdGFuY2Ugb2YgJyIrSC5kKEguTShhKSkrIicifSwKZTc6ZnVuY3Rpb24o
-YSxiKXt1Lm8uYihiKQp0aHJvdyBILmIoUC5scihhLGIuZ1dhKCksYi5nbmQoKSxiLmdWbSgpKSl9fQpK
-LnlFLnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIFN0cmluZyhhKX0sCmdpTzpmdW5jdGlv
-bihhKXtyZXR1cm4gYT81MTkwMTg6MjE4MTU5fSwKJGlhMjoxfQpKLllFLnByb3RvdHlwZT17CkROOmZ1
-bmN0aW9uKGEsYil7cmV0dXJuIG51bGw9PWJ9LAp3OmZ1bmN0aW9uKGEpe3JldHVybiJudWxsIn0sCmdp
-TzpmdW5jdGlvbihhKXtyZXR1cm4gMH0sCmU3OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuU2ooYSx1
-Lm8uYihiKSl9LAokaWM4OjF9CkouTUYucHJvdG90eXBlPXsKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiAw
-fSwKdzpmdW5jdGlvbihhKXtyZXR1cm4gU3RyaW5nKGEpfSwKJGl2bToxfQpKLmlDLnByb3RvdHlwZT17
-fQpKLmtkLnByb3RvdHlwZT17fQpKLmM1LnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7dmFyIHQ9YVsk
-LncoKV0KaWYodD09bnVsbClyZXR1cm4gdGhpcy50KGEpCnJldHVybiJKYXZhU2NyaXB0IGZ1bmN0aW9u
-IGZvciAiK0guZChKLmoodCkpfSwKJFM6ZnVuY3Rpb24oKXtyZXR1cm57ZnVuYzoxLG9wdDpbLCwsLCws
-LCwsLCwsLCwsLF19fSwKJGlFSDoxfQpKLmpkLnByb3RvdHlwZT17Cmk6ZnVuY3Rpb24oYSxiKXtILnQ2
-KGEpLmQuYihiKQppZighIWEuZml4ZWQkbGVuZ3RoKUgudmgoUC5MNCgiYWRkIikpCmEucHVzaChiKX0s
-Clc0OmZ1bmN0aW9uKGEsYil7dmFyIHQKaWYoISFhLmZpeGVkJGxlbmd0aClILnZoKFAuTDQoInJlbW92
-ZUF0IikpCnQ9YS5sZW5ndGgKaWYoYj49dCl0aHJvdyBILmIoUC54KGIsbnVsbCkpCnJldHVybiBhLnNw
-bGljZShiLDEpWzBdfSwKVUc6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscgpILnQ2KGEpLkMoImNYPDE+
-IikuYihjKQppZighIWEuZml4ZWQkbGVuZ3RoKUgudmgoUC5MNCgiaW5zZXJ0QWxsIikpCnQ9YS5sZW5n
-dGgKUC53QShiLDAsdCwiaW5kZXgiKQpzPWMubGVuZ3RoCnRoaXMuc0EoYSx0K3MpCnI9YitzCnRoaXMu
-WVcoYSxyLGEubGVuZ3RoLGEsYikKdGhpcy52ZyhhLGIscixjKX0sCm12OmZ1bmN0aW9uKGEpe2lmKCEh
-YS5maXhlZCRsZW5ndGgpSC52aChQLkw0KCJyZW1vdmVMYXN0IikpCmlmKGEubGVuZ3RoPT09MCl0aHJv
-dyBILmIoSC5IWShhLC0xKSkKcmV0dXJuIGEucG9wKCl9LApGVjpmdW5jdGlvbihhLGIpe3ZhciB0Ckgu
-dDYoYSkuQygiY1g8MT4iKS5iKGIpCmlmKCEhYS5maXhlZCRsZW5ndGgpSC52aChQLkw0KCJhZGRBbGwi
-KSkKZm9yKHQ9Si5JVChiKTt0LkYoKTspYS5wdXNoKHQuZ2woKSl9LApLOmZ1bmN0aW9uKGEsYil7dmFy
-IHQscwpILnQ2KGEpLkMoIn4oMSkiKS5iKGIpCnQ9YS5sZW5ndGgKZm9yKHM9MDtzPHQ7KytzKXtiLiQx
-KGFbc10pCmlmKGEubGVuZ3RoIT09dCl0aHJvdyBILmIoUC5hNChhKSl9fSwKRTI6ZnVuY3Rpb24oYSxi
-LGMpe3ZhciB0PUgudDYoYSkKcmV0dXJuIG5ldyBILkE4KGEsdC5LcShjKS5DKCIxKDIpIikuYihiKSx0
-LkMoIkA8MT4iKS5LcShjKS5DKCJBODwxLDI+IikpfSwKSDpmdW5jdGlvbihhLGIpe3ZhciB0LHM9bmV3
-IEFycmF5KGEubGVuZ3RoKQpzLmZpeGVkJGxlbmd0aD1BcnJheQpmb3IodD0wO3Q8YS5sZW5ndGg7Kyt0
-KXRoaXMuWShzLHQsSC5kKGFbdF0pKQpyZXR1cm4gcy5qb2luKGIpfSwKTjA6ZnVuY3Rpb24oYSxiLGMs
-ZCl7dmFyIHQscyxyCmQuYihiKQpILnQ2KGEpLktxKGQpLkMoIjEoMSwyKSIpLmIoYykKdD1hLmxlbmd0
-aApmb3Iocz1iLHI9MDtyPHQ7KytyKXtzPWMuJDIocyxhW3JdKQppZihhLmxlbmd0aCE9PXQpdGhyb3cg
-SC5iKFAuYTQoYSkpfXJldHVybiBzfSwKSHQ6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG89SC50
-NihhKQpvLkMoImEyKDEpIikuYihiKQpvLkMoIjEoKSIpLmIobnVsbCkKdD1hLmxlbmd0aApmb3Iocz1u
-dWxsLHI9ITEscT0wO3E8dDsrK3Epe3A9YVtxXQppZihILm9UKGIuJDEocCkpKXtpZihyKXRocm93IEgu
-YihILmRVKCkpCnM9cApyPSEwfWlmKHQhPT1hLmxlbmd0aCl0aHJvdyBILmIoUC5hNChhKSl9aWYocily
-ZXR1cm4gcwp0aHJvdyBILmIoSC5XcCgpKX0sCkU6ZnVuY3Rpb24oYSxiKXtpZihiPDB8fGI+PWEubGVu
-Z3RoKXJldHVybiBILk9IKGEsYikKcmV0dXJuIGFbYl19LApENjpmdW5jdGlvbihhLGIsYyl7aWYoYjww
-fHxiPmEubGVuZ3RoKXRocm93IEguYihQLlRFKGIsMCxhLmxlbmd0aCwic3RhcnQiLG51bGwpKQppZihj
-PGJ8fGM+YS5sZW5ndGgpdGhyb3cgSC5iKFAuVEUoYyxiLGEubGVuZ3RoLCJlbmQiLG51bGwpKQppZihi
-PT09YylyZXR1cm4gSC5WTShbXSxILnQ2KGEpKQpyZXR1cm4gSC5WTShhLnNsaWNlKGIsYyksSC50Nihh
-KSl9LApndEg6ZnVuY3Rpb24oYSl7aWYoYS5sZW5ndGg+MClyZXR1cm4gYVswXQp0aHJvdyBILmIoSC5X
-cCgpKX0sCmdyWjpmdW5jdGlvbihhKXt2YXIgdD1hLmxlbmd0aAppZih0PjApcmV0dXJuIGFbdC0xXQp0
-aHJvdyBILmIoSC5XcCgpKX0sCllXOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscyxyPUgudDYoYSkK
-ci5DKCJjWDwxPiIpLmIoZCkKaWYoISFhLmltbXV0YWJsZSRsaXN0KUgudmgoUC5MNCgic2V0UmFuZ2Ui
-KSkKUC5qQihiLGMsYS5sZW5ndGgpCnQ9Yy1iCmlmKHQ9PT0wKXJldHVybgpQLmsxKGUsInNraXBDb3Vu
-dCIpCnIuQygiek08MT4iKS5iKGQpCnI9Si5VNihkKQppZihlK3Q+ci5nQShkKSl0aHJvdyBILmIoSC5h
-cigpKQppZihlPGIpZm9yKHM9dC0xO3M+PTA7LS1zKWFbYitzXT1yLnEoZCxlK3MpCmVsc2UgZm9yKHM9
-MDtzPHQ7KytzKWFbYitzXT1yLnEoZCxlK3MpfSwKdmc6ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIHRo
-aXMuWVcoYSxiLGMsZCwwKX0sClZyOmZ1bmN0aW9uKGEsYil7dmFyIHQscwpILnQ2KGEpLkMoImEyKDEp
-IikuYihiKQp0PWEubGVuZ3RoCmZvcihzPTA7czx0Oysrcyl7aWYoSC5vVChiLiQxKGFbc10pKSlyZXR1
-cm4hMAppZihhLmxlbmd0aCE9PXQpdGhyb3cgSC5iKFAuYTQoYSkpfXJldHVybiExfSwKdGc6ZnVuY3Rp
-b24oYSxiKXt2YXIgdApmb3IodD0wO3Q8YS5sZW5ndGg7Kyt0KWlmKEouUk0oYVt0XSxiKSlyZXR1cm4h
-MApyZXR1cm4hMX0sCmdsMDpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGg9PT0wfSwKZ29yOmZ1bmN0
-aW9uKGEpe3JldHVybiBhLmxlbmd0aCE9PTB9LAp3OmZ1bmN0aW9uKGEpe3JldHVybiBQLldFKGEsIlsi
-LCJdIil9LApna3o6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBKLm0xKGEsYS5sZW5ndGgsSC50NihhKS5D
-KCJtMTwxPiIpKX0sCmdpTzpmdW5jdGlvbihhKXtyZXR1cm4gSC5lUShhKX0sCmdBOmZ1bmN0aW9uKGEp
-e3JldHVybiBhLmxlbmd0aH0sCnNBOmZ1bmN0aW9uKGEsYil7aWYoISFhLmZpeGVkJGxlbmd0aClILnZo
-KFAuTDQoInNldCBsZW5ndGgiKSkKaWYoYjwwKXRocm93IEguYihQLlRFKGIsMCxudWxsLCJuZXdMZW5n
-dGgiLG51bGwpKQphLmxlbmd0aD1ifSwKcTpmdW5jdGlvbihhLGIpe0guU2MoYikKaWYoYj49YS5sZW5n
-dGh8fGI8MCl0aHJvdyBILmIoSC5IWShhLGIpKQpyZXR1cm4gYVtiXX0sClk6ZnVuY3Rpb24oYSxiLGMp
-e0gudDYoYSkuZC5iKGMpCmlmKCEhYS5pbW11dGFibGUkbGlzdClILnZoKFAuTDQoImluZGV4ZWQgc2V0
-IikpCmlmKGI+PWEubGVuZ3RofHxiPDApdGhyb3cgSC5iKEguSFkoYSxiKSkKYVtiXT1jfSwKJGliUTox
-LAokaWNYOjEsCiRpek06MX0KSi5Qby5wcm90b3R5cGU9e30KSi5tMS5wcm90b3R5cGU9ewpnbDpmdW5j
-dGlvbigpe3JldHVybiB0aGlzLmR9LApGOmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzLHI9cy5hLHE9ci5s
-ZW5ndGgKaWYocy5iIT09cSl0aHJvdyBILmIoSC5sayhyKSkKdD1zLmMKaWYodD49cSl7cy5zTShudWxs
-KQpyZXR1cm4hMX1zLnNNKHJbdF0pOysrcy5jCnJldHVybiEwfSwKc006ZnVuY3Rpb24oYSl7dGhpcy5k
-PXRoaXMuJHRpLmQuYihhKX0sCiRpQW46MX0KSi5xSS5wcm90b3R5cGU9ewp5dTpmdW5jdGlvbihhKXt2
-YXIgdAppZihhPj0tMjE0NzQ4MzY0OCYmYTw9MjE0NzQ4MzY0NylyZXR1cm4gYXwwCmlmKGlzRmluaXRl
-KGEpKXt0PWE8MD9NYXRoLmNlaWwoYSk6TWF0aC5mbG9vcihhKQpyZXR1cm4gdCswfXRocm93IEguYihQ
-Lkw0KCIiK2ErIi50b0ludCgpIikpfSwKelE6ZnVuY3Rpb24oYSl7aWYoYT4wKXtpZihhIT09MS8wKXJl
-dHVybiBNYXRoLnJvdW5kKGEpfWVsc2UgaWYoYT4tMS8wKXJldHVybiAwLU1hdGgucm91bmQoMC1hKQp0
-aHJvdyBILmIoUC5MNCgiIithKyIucm91bmQoKSIpKX0sCldaOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxy
-LHEKaWYoYjwyfHxiPjM2KXRocm93IEguYihQLlRFKGIsMiwzNiwicmFkaXgiLG51bGwpKQp0PWEudG9T
-dHJpbmcoYikKaWYoQy54Qi5tKHQsdC5sZW5ndGgtMSkhPT00MSlyZXR1cm4gdApzPS9eKFtcZGEtel0r
-KSg/OlwuKFtcZGEtel0rKSk/XChlXCsoXGQrKVwpJC8uZXhlYyh0KQppZihzPT1udWxsKUgudmgoUC5M
-NCgiVW5leHBlY3RlZCB0b1N0cmluZyByZXN1bHQ6ICIrdCkpCnI9cy5sZW5ndGgKaWYoMT49cilyZXR1
-cm4gSC5PSChzLDEpCnQ9c1sxXQppZigzPj1yKXJldHVybiBILk9IKHMsMykKcT0rc1szXQpyPXNbMl0K
-aWYociE9bnVsbCl7dCs9cgpxLT1yLmxlbmd0aH1yZXR1cm4gdCtDLnhCLkl4KCIwIixxKX0sCnc6ZnVu
-Y3Rpb24oYSl7aWYoYT09PTAmJjEvYTwwKXJldHVybiItMC4wIgplbHNlIHJldHVybiIiK2F9LApnaU86
-ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscD1hfDAKaWYoYT09PXApcmV0dXJuIDUzNjg3MDkxMSZwCnQ9
-TWF0aC5hYnMoYSkKcz1NYXRoLmxvZyh0KS8wLjY5MzE0NzE4MDU1OTk0NTN8MApyPU1hdGgucG93KDIs
-cykKcT10PDE/dC9yOnIvdApyZXR1cm4gNTM2ODcwOTExJigocSo5MDA3MTk5MjU0NzQwOTkyfDApKyhx
-KjM1NDIyNDMxODExNzY1MjF8MCkpKjU5OTE5NytzKjEyNTl9LAp6WTpmdW5jdGlvbihhLGIpe3ZhciB0
-PWElYgppZih0PT09MClyZXR1cm4gMAppZih0PjApcmV0dXJuIHQKaWYoYjwwKXJldHVybiB0LWIKZWxz
-ZSByZXR1cm4gdCtifSwKd0c6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihhPjApdD10aGlzLnAzKGEsYikK
-ZWxzZXt0PWI+MzE/MzE6Ygp0PWE+PnQ+Pj4wfXJldHVybiB0fSwKYmY6ZnVuY3Rpb24oYSxiKXtpZihi
-PDApdGhyb3cgSC5iKEgudEwoYikpCnJldHVybiB0aGlzLnAzKGEsYil9LApwMzpmdW5jdGlvbihhLGIp
-e3JldHVybiBiPjMxPzA6YT4+PmJ9LAokaUNQOjEsCiRpRks6MX0KSi5iVS5wcm90b3R5cGU9eyRpS046
-MX0KSi5WQS5wcm90b3R5cGU9e30KSi5Eci5wcm90b3R5cGU9ewptOmZ1bmN0aW9uKGEsYil7aWYoYjww
-KXRocm93IEguYihILkhZKGEsYikpCmlmKGI+PWEubGVuZ3RoKUgudmgoSC5IWShhLGIpKQpyZXR1cm4g
-YS5jaGFyQ29kZUF0KGIpfSwKVzpmdW5jdGlvbihhLGIpe2lmKGI+PWEubGVuZ3RoKXRocm93IEguYihI
-LkhZKGEsYikpCnJldHVybiBhLmNoYXJDb2RlQXQoYil9LApkZDpmdW5jdGlvbihhLGIpe3JldHVybiBu
-ZXcgSC51bihiLGEsMCl9LApoOmZ1bmN0aW9uKGEsYil7aWYodHlwZW9mIGIhPSJzdHJpbmciKXRocm93
-IEguYihQLkwzKGIsbnVsbCxudWxsKSkKcmV0dXJuIGErYn0sClRjOmZ1bmN0aW9uKGEsYil7dmFyIHQ9
-Yi5sZW5ndGgscz1hLmxlbmd0aAppZih0PnMpcmV0dXJuITEKcmV0dXJuIGI9PT10aGlzLkcoYSxzLXQp
-fSwKaTc6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscwpjPVAuakIoYixjLGEubGVuZ3RoKQp0PWEuc3Vi
-c3RyaW5nKDAsYikKcz1hLnN1YnN0cmluZyhjKQpyZXR1cm4gdCtkK3N9LApRaTpmdW5jdGlvbihhLGIs
-Yyl7dmFyIHQKaWYoIUgub2soYykpSC52aChILnRMKGMpKQppZih0eXBlb2YgYyE9PSJudW1iZXIiKXJl
-dHVybiBjLkooKQppZihjPDB8fGM+YS5sZW5ndGgpdGhyb3cgSC5iKFAuVEUoYywwLGEubGVuZ3RoLG51
-bGwsbnVsbCkpCnQ9YytiLmxlbmd0aAppZih0PmEubGVuZ3RoKXJldHVybiExCnJldHVybiBiPT09YS5z
-dWJzdHJpbmcoYyx0KX0sCm46ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5RaShhLGIsMCl9LApOajpm
-dW5jdGlvbihhLGIsYyl7aWYoIUgub2soYikpSC52aChILnRMKGIpKQppZihjPT1udWxsKWM9YS5sZW5n
-dGgKaWYodHlwZW9mIGIhPT0ibnVtYmVyIilyZXR1cm4gYi5KKCkKaWYoYjwwKXRocm93IEguYihQLngo
-YixudWxsKSkKaWYoYj5jKXRocm93IEguYihQLngoYixudWxsKSkKaWYoYz5hLmxlbmd0aCl0aHJvdyBI
-LmIoUC54KGMsbnVsbCkpCnJldHVybiBhLnN1YnN0cmluZyhiLGMpfSwKRzpmdW5jdGlvbihhLGIpe3Jl
-dHVybiB0aGlzLk5qKGEsYixudWxsKX0sCmhjOmZ1bmN0aW9uKGEpe3JldHVybiBhLnRvTG93ZXJDYXNl
-KCl9LApiUzpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT1hLnRyaW0oKSxwPXEubGVuZ3RoCmlmKHA9PT0w
-KXJldHVybiBxCmlmKHRoaXMuVyhxLDApPT09MTMzKXt0PUoubW0ocSwxKQppZih0PT09cClyZXR1cm4i
-In1lbHNlIHQ9MApzPXAtMQpyPXRoaXMubShxLHMpPT09MTMzP0ouYzEocSxzKTpwCmlmKHQ9PT0wJiZy
-PT09cClyZXR1cm4gcQpyZXR1cm4gcS5zdWJzdHJpbmcodCxyKX0sCkl4OmZ1bmN0aW9uKGEsYil7dmFy
-IHQscwppZigwPj1iKXJldHVybiIiCmlmKGI9PT0xfHxhLmxlbmd0aD09PTApcmV0dXJuIGEKaWYoYiE9
-PWI+Pj4wKXRocm93IEguYihDLkVxKQpmb3IodD1hLHM9IiI7ITA7KXtpZigoYiYxKT09PTEpcz10K3MK
-Yj1iPj4+MQppZihiPT09MClicmVhawp0Kz10fXJldHVybiBzfSwKWFU6ZnVuY3Rpb24oYSxiLGMpe3Zh
-ciB0CmlmKGM8MHx8Yz5hLmxlbmd0aCl0aHJvdyBILmIoUC5URShjLDAsYS5sZW5ndGgsbnVsbCxudWxs
-KSkKdD1hLmluZGV4T2YoYixjKQpyZXR1cm4gdH0sCk9ZOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMu
-WFUoYSxiLDApfSwKUGs6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKaWYoYz09bnVsbCljPWEubGVuZ3Ro
-CmVsc2UgaWYoYzwwfHxjPmEubGVuZ3RoKXRocm93IEguYihQLlRFKGMsMCxhLmxlbmd0aCxudWxsLG51
-bGwpKQp0PWIubGVuZ3RoCnM9YS5sZW5ndGgKaWYoYyt0PnMpYz1zLXQKcmV0dXJuIGEubGFzdEluZGV4
-T2YoYixjKX0sCmNuOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuUGsoYSxiLG51bGwpfSwKSXM6ZnVu
-Y3Rpb24oYSxiLGMpe3ZhciB0PWEubGVuZ3RoCmlmKGM+dCl0aHJvdyBILmIoUC5URShjLDAsdCxudWxs
-LG51bGwpKQpyZXR1cm4gSC5tMihhLGIsYyl9LAp0ZzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLklz
-KGEsYiwwKX0sCnc6ZnVuY3Rpb24oYSl7cmV0dXJuIGF9LApnaU86ZnVuY3Rpb24oYSl7dmFyIHQscyxy
-CmZvcih0PWEubGVuZ3RoLHM9MCxyPTA7cjx0Oysrcil7cz01MzY4NzA5MTEmcythLmNoYXJDb2RlQXQo
-cikKcz01MzY4NzA5MTEmcysoKDUyNDI4NyZzKTw8MTApCnNePXM+PjZ9cz01MzY4NzA5MTEmcysoKDY3
-MTA4ODYzJnMpPDwzKQpzXj1zPj4xMQpyZXR1cm4gNTM2ODcwOTExJnMrKCgxNjM4MyZzKTw8MTUpfSwK
-Z0E6ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofSwKcTpmdW5jdGlvbihhLGIpe0guU2MoYikKaWYo
-Yj49YS5sZW5ndGh8fCExKXRocm93IEguYihILkhZKGEsYikpCnJldHVybiBhW2JdfSwKJGl2WDoxLAok
-aXFVOjF9CkgucWoucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5sZW5ndGh9
-LApxOmZ1bmN0aW9uKGEsYil7cmV0dXJuIEMueEIubSh0aGlzLmEsSC5TYyhiKSl9fQpILmJRLnByb3Rv
-dHlwZT17fQpILmFMLnByb3RvdHlwZT17CmdrejpmdW5jdGlvbihhKXt2YXIgdD10aGlzCnJldHVybiBu
-ZXcgSC5hNyh0LHQuZ0EodCksSC5MaCh0KS5DKCJhNzxhTC5FPiIpKX0sCmdsMDpmdW5jdGlvbihhKXty
-ZXR1cm4gdGhpcy5nQSh0aGlzKT09PTB9LApIOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHE9dGhpcyxw
-PXEuZ0EocSkKaWYoYi5sZW5ndGghPT0wKXtpZihwPT09MClyZXR1cm4iIgp0PUguZChxLkUoMCwwKSkK
-aWYocCE9PXEuZ0EocSkpdGhyb3cgSC5iKFAuYTQocSkpCmZvcihzPXQscj0xO3I8cDsrK3Ipe3M9cyti
-K0guZChxLkUoMCxyKSkKaWYocCE9PXEuZ0EocSkpdGhyb3cgSC5iKFAuYTQocSkpfXJldHVybiBzLmNo
-YXJDb2RlQXQoMCk9PTA/czpzfWVsc2V7Zm9yKHI9MCxzPSIiO3I8cDsrK3Ipe3MrPUguZChxLkUoMCxy
-KSkKaWYocCE9PXEuZ0EocSkpdGhyb3cgSC5iKFAuYTQocSkpfXJldHVybiBzLmNoYXJDb2RlQXQoMCk9
-PTA/czpzfX0sCmV2OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuR0coMCxILkxoKHRoaXMpLkMoImEy
-KGFMLkUpIikuYihiKSl9LApFMjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC5MaCh0aGlzKQpyZXR1cm4g
-bmV3IEguQTgodGhpcyx0LktxKGMpLkMoIjEoYUwuRSkiKS5iKGIpLHQuQygiQDxhTC5FPiIpLktxKGMp
-LkMoIkE4PDEsMj4iKSl9LAp0dDpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcyxyPUguVk0oW10sSC5M
-aChzKS5DKCJqZDxhTC5FPiIpKQpDLk5tLnNBKHIscy5nQShzKSkKZm9yKHQ9MDt0PHMuZ0Eocyk7Kyt0
-KUMuTm0uWShyLHQscy5FKDAsdCkpCnJldHVybiByfSwKYnI6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMu
-dHQoYSwhMCl9fQpILm5ILnByb3RvdHlwZT17CmdVRDpmdW5jdGlvbigpe3ZhciB0PUouSG0odGhpcy5h
-KSxzPXRoaXMuYwppZihzPT1udWxsfHxzPnQpcmV0dXJuIHQKcmV0dXJuIHN9LApnQXM6ZnVuY3Rpb24o
-KXt2YXIgdD1KLkhtKHRoaXMuYSkscz10aGlzLmIKaWYocz50KXJldHVybiB0CnJldHVybiBzfSwKZ0E6
-ZnVuY3Rpb24oYSl7dmFyIHQscz1KLkhtKHRoaXMuYSkscj10aGlzLmIKaWYocj49cylyZXR1cm4gMAp0
-PXRoaXMuYwppZih0PT1udWxsfHx0Pj1zKXJldHVybiBzLXIKaWYodHlwZW9mIHQhPT0ibnVtYmVyIily
-ZXR1cm4gdC5ITigpCnJldHVybiB0LXJ9LApFOmZ1bmN0aW9uKGEsYil7dmFyIHQscz10aGlzLHI9cy5n
-QXMoKStiCmlmKGI+PTApe3Q9cy5nVUQoKQppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiBILnBZ
-KHQpCnQ9cj49dH1lbHNlIHQ9ITAKaWYodCl0aHJvdyBILmIoUC5DZihiLHMsImluZGV4IixudWxsLG51
-bGwpKQpyZXR1cm4gSi5HQShzLmEscil9fQpILmE3LnByb3RvdHlwZT17CmdsOmZ1bmN0aW9uKCl7cmV0
-dXJuIHRoaXMuZH0sCkY6ZnVuY3Rpb24oKXt2YXIgdCxzPXRoaXMscj1zLmEscT1KLlU2KHIpLHA9cS5n
-QShyKQppZihzLmIhPT1wKXRocm93IEguYihQLmE0KHIpKQp0PXMuYwppZih0Pj1wKXtzLnNJKG51bGwp
-CnJldHVybiExfXMuc0kocS5FKHIsdCkpOysrcy5jCnJldHVybiEwfSwKc0k6ZnVuY3Rpb24oYSl7dGhp
-cy5kPXRoaXMuJHRpLmQuYihhKX0sCiRpQW46MX0KSC5pMS5wcm90b3R5cGU9ewpna3o6ZnVuY3Rpb24o
-YSl7dmFyIHQ9SC5MaCh0aGlzKQpyZXR1cm4gbmV3IEguTUgoSi5JVCh0aGlzLmEpLHRoaXMuYix0LkMo
-IkA8MT4iKS5LcSh0LmNoWzFdKS5DKCJNSDwxLDI+IikpfSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIEou
-SG0odGhpcy5hKX19CkgueHkucHJvdG90eXBlPXskaWJROjF9CkguTUgucHJvdG90eXBlPXsKRjpmdW5j
-dGlvbigpe3ZhciB0PXRoaXMscz10LmIKaWYocy5GKCkpe3Quc0kodC5jLiQxKHMuZ2woKSkpCnJldHVy
-biEwfXQuc0kobnVsbCkKcmV0dXJuITF9LApnbDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmF9LApzSTpm
-dW5jdGlvbihhKXt0aGlzLmE9dGhpcy4kdGkuY2hbMV0uYihhKX19CkguQTgucHJvdG90eXBlPXsKZ0E6
-ZnVuY3Rpb24oYSl7cmV0dXJuIEouSG0odGhpcy5hKX0sCkU6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhp
-cy5iLiQxKEouR0EodGhpcy5hLGIpKX19CkguVTUucHJvdG90eXBlPXsKZ2t6OmZ1bmN0aW9uKGEpe3Jl
-dHVybiBuZXcgSC5TTyhKLklUKHRoaXMuYSksdGhpcy5iLHRoaXMuJHRpLkMoIlNPPDE+IikpfX0KSC5T
-Ty5wcm90b3R5cGU9ewpGOmZ1bmN0aW9uKCl7dmFyIHQscwpmb3IodD10aGlzLmEscz10aGlzLmI7dC5G
-KCk7KWlmKEgub1Qocy4kMSh0LmdsKCkpKSlyZXR1cm4hMApyZXR1cm4hMX0sCmdsOmZ1bmN0aW9uKCl7
-cmV0dXJuIHRoaXMuYS5nbCgpfX0KSC5TVS5wcm90b3R5cGU9e30KSC5SZS5wcm90b3R5cGU9ewpZOmZ1
-bmN0aW9uKGEsYixjKXtILkxoKHRoaXMpLkMoIlJlLkUiKS5iKGMpCnRocm93IEguYihQLkw0KCJDYW5u
-b3QgbW9kaWZ5IGFuIHVubW9kaWZpYWJsZSBsaXN0IikpfX0KSC5YQy5wcm90b3R5cGU9e30KSC53di5w
-cm90b3R5cGU9ewpnaU86ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5faGFzaENvZGUKaWYodCE9bnVsbCly
-ZXR1cm4gdAp0PTUzNjg3MDkxMSY2NjQ1OTcqSi5oZih0aGlzLmEpCnRoaXMuX2hhc2hDb2RlPXQKcmV0
-dXJuIHR9LAp3OmZ1bmN0aW9uKGEpe3JldHVybidTeW1ib2woIicrSC5kKHRoaXMuYSkrJyIpJ30sCkRO
-OmZ1bmN0aW9uKGEsYil7aWYoYj09bnVsbClyZXR1cm4hMQpyZXR1cm4gYiBpbnN0YW5jZW9mIEgud3Ym
-JnRoaXMuYT09Yi5hfSwKJGlHRDoxfQpILlBELnByb3RvdHlwZT17fQpILldVLnByb3RvdHlwZT17Cmds
-MDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nQSh0aGlzKT09PTB9LAp3OmZ1bmN0aW9uKGEpe3JldHVy
-biBQLm5PKHRoaXMpfSwKWTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC5MaCh0aGlzKQp0LmQuYihiKQp0
-LmNoWzFdLmIoYykKcmV0dXJuIEguZGMoKX0sCmdQdTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5xNChh
-LEguTGgodGhpcykuQygiTjM8MSwyPiIpKX0sCnE0OmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcwpyZXR1
-cm4gUC5sMChmdW5jdGlvbigpe3ZhciBzPWEKdmFyIHI9MCxxPTEscCxvLG4sbQpyZXR1cm4gZnVuY3Rp
-b24gJGFzeW5jJGdQdShjLGQpe2lmKGM9PT0xKXtwPWQKcj1xfXdoaWxlKHRydWUpc3dpdGNoKHIpe2Nh
-c2UgMDpvPXQuZ1YoKSxvPW8uZ2t6KG8pLG49SC5MaCh0KSxuPW4uQygiQDwxPiIpLktxKG4uY2hbMV0p
-LkMoIk4zPDEsMj4iKQpjYXNlIDI6aWYoIW8uRigpKXtyPTMKYnJlYWt9bT1vLmdsKCkKcj00CnJldHVy
-biBuZXcgUC5OMyhtLHQucSgwLG0pLG4pCmNhc2UgNDpyPTIKYnJlYWsKY2FzZSAzOnJldHVybiBQLlRo
-KCkKY2FzZSAxOnJldHVybiBQLlltKHApfX19LGIpfSwKJGlaMDoxfQpILkxQLnByb3RvdHlwZT17CmdB
-OmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmF9LAp4NDpmdW5jdGlvbihhKXtpZih0eXBlb2YgYSE9InN0
-cmluZyIpcmV0dXJuITEKaWYoIl9fcHJvdG9fXyI9PT1hKXJldHVybiExCnJldHVybiB0aGlzLmIuaGFz
-T3duUHJvcGVydHkoYSl9LApxOmZ1bmN0aW9uKGEsYil7aWYoIXRoaXMueDQoYikpcmV0dXJuIG51bGwK
-cmV0dXJuIHRoaXMuRChiKX0sCkQ6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYltILnkoYSldfSwKSzpm
-dW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHA9SC5MaCh0aGlzKQpwLkMoIn4oMSwyKSIpLmIoYikKdD10
-aGlzLmMKZm9yKHM9dC5sZW5ndGgscD1wLmNoWzFdLHI9MDtyPHM7KytyKXtxPXRbcl0KYi4kMihxLHAu
-Yih0aGlzLkQocSkpKX19LApnVjpmdW5jdGlvbigpe3JldHVybiBuZXcgSC5YUih0aGlzLEguTGgodGhp
-cykuQygiWFI8MT4iKSl9fQpILlhSLnByb3RvdHlwZT17CmdrejpmdW5jdGlvbihhKXt2YXIgdD10aGlz
-LmEuYwpyZXR1cm4gbmV3IEoubTEodCx0Lmxlbmd0aCxILnQ2KHQpLkMoIm0xPDE+IikpfSwKZ0E6ZnVu
-Y3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5jLmxlbmd0aH19CkguTEkucHJvdG90eXBlPXsKZ1dhOmZ1bmN0
-aW9uKCl7dmFyIHQ9dGhpcy5hCnJldHVybiB0fSwKZ25kOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10
-aGlzCmlmKHAuYz09PTEpcmV0dXJuIEMuaFUKdD1wLmQKcz10Lmxlbmd0aC1wLmUubGVuZ3RoLXAuZgpp
-ZihzPT09MClyZXR1cm4gQy5oVQpyPVtdCmZvcihxPTA7cTxzOysrcSl7aWYocT49dC5sZW5ndGgpcmV0
-dXJuIEguT0godCxxKQpyLnB1c2godFtxXSl9cmV0dXJuIEouekMocil9LApnVm06ZnVuY3Rpb24oKXt2
-YXIgdCxzLHIscSxwLG8sbixtLGw9dGhpcwppZihsLmMhPT0wKXJldHVybiBDLkR4CnQ9bC5lCnM9dC5s
-ZW5ndGgKcj1sLmQKcT1yLmxlbmd0aC1zLWwuZgppZihzPT09MClyZXR1cm4gQy5EeApwPW5ldyBILk41
-KHUuZW8pCmZvcihvPTA7bzxzOysrbyl7aWYobz49dC5sZW5ndGgpcmV0dXJuIEguT0godCxvKQpuPXRb
-b10KbT1xK28KaWYobTwwfHxtPj1yLmxlbmd0aClyZXR1cm4gSC5PSChyLG0pCnAuWSgwLG5ldyBILnd2
-KG4pLHJbbV0pfXJldHVybiBuZXcgSC5QRChwLHUuZ0YpfSwKJGl2UToxfQpILkNqLnByb3RvdHlwZT17
-CiQyOmZ1bmN0aW9uKGEsYil7dmFyIHQKSC55KGEpCnQ9dGhpcy5hCnQuYj10LmIrIiQiK0guZChhKQpD
-Lk5tLmkodGhpcy5iLGEpCkMuTm0uaSh0aGlzLmMsYik7Kyt0LmF9LAokUzoxMn0KSC5mOS5wcm90b3R5
-cGU9ewpxUzpmdW5jdGlvbihhKXt2YXIgdCxzLHI9dGhpcyxxPW5ldyBSZWdFeHAoci5hKS5leGVjKGEp
-CmlmKHE9PW51bGwpcmV0dXJuIG51bGwKdD1PYmplY3QuY3JlYXRlKG51bGwpCnM9ci5iCmlmKHMhPT0t
-MSl0LmFyZ3VtZW50cz1xW3MrMV0Kcz1yLmMKaWYocyE9PS0xKXQuYXJndW1lbnRzRXhwcj1xW3MrMV0K
-cz1yLmQKaWYocyE9PS0xKXQuZXhwcj1xW3MrMV0Kcz1yLmUKaWYocyE9PS0xKXQubWV0aG9kPXFbcysx
-XQpzPXIuZgppZihzIT09LTEpdC5yZWNlaXZlcj1xW3MrMV0KcmV0dXJuIHR9fQpILlcwLnByb3RvdHlw
-ZT17Cnc6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5iCmlmKHQ9PW51bGwpcmV0dXJuIk5vU3VjaE1ldGhv
-ZEVycm9yOiAiK0guZCh0aGlzLmEpCnJldHVybiJOb1N1Y2hNZXRob2RFcnJvcjogbWV0aG9kIG5vdCBm
-b3VuZDogJyIrdCsiJyBvbiBudWxsIn19CkguYXoucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXt2YXIg
-dCxzPXRoaXMscj0iTm9TdWNoTWV0aG9kRXJyb3I6IG1ldGhvZCBub3QgZm91bmQ6ICciLHE9cy5iCmlm
-KHE9PW51bGwpcmV0dXJuIk5vU3VjaE1ldGhvZEVycm9yOiAiK0guZChzLmEpCnQ9cy5jCmlmKHQ9PW51
-bGwpcmV0dXJuIHIrcSsiJyAoIitILmQocy5hKSsiKSIKcmV0dXJuIHIrcSsiJyBvbiAnIit0KyInICgi
-K0guZChzLmEpKyIpIn19CkgudlYucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEK
-cmV0dXJuIHQubGVuZ3RoPT09MD8iRXJyb3IiOiJFcnJvcjogIit0fX0KSC5icS5wcm90b3R5cGU9e30K
-SC5BbS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtpZih1LmJVLmMoYSkpaWYoYS4kdGhyb3duSnNF
-cnJvcj09bnVsbClhLiR0aHJvd25Kc0Vycm9yPXRoaXMuYQpyZXR1cm4gYX0sCiRTOjF9CkguWE8ucHJv
-dG90eXBlPXsKdzpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuYgppZihzIT1udWxsKXJldHVybiBzCnM9
-dGhpcy5hCnQ9cyE9PW51bGwmJnR5cGVvZiBzPT09Im9iamVjdCI/cy5zdGFjazpudWxsCnJldHVybiB0
-aGlzLmI9dD09bnVsbD8iIjp0fSwKJGlHejoxfQpILlRwLnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7
-dmFyIHQ9dGhpcy5jb25zdHJ1Y3RvcixzPXQ9PW51bGw/bnVsbDp0Lm5hbWUKcmV0dXJuIkNsb3N1cmUg
-JyIrSC5OUShzPT1udWxsPyJ1bmtub3duIjpzKSsiJyJ9LAokaUVIOjEsCmdRbDpmdW5jdGlvbigpe3Jl
-dHVybiB0aGlzfSwKJEM6IiQxIiwKJFI6MSwKJEQ6bnVsbH0KSC5sYy5wcm90b3R5cGU9e30KSC56eC5w
-cm90b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuJHN0YXRpY19uYW1lCmlmKHQ9PW51bGwp
-cmV0dXJuIkNsb3N1cmUgb2YgdW5rbm93biBzdGF0aWMgbWV0aG9kIgpyZXR1cm4iQ2xvc3VyZSAnIitI
-Lk5RKHQpKyInIn19CkguclQucHJvdG90eXBlPXsKRE46ZnVuY3Rpb24oYSxiKXt2YXIgdD10aGlzCmlm
-KGI9PW51bGwpcmV0dXJuITEKaWYodD09PWIpcmV0dXJuITAKaWYoIShiIGluc3RhbmNlb2YgSC5yVCkp
-cmV0dXJuITEKcmV0dXJuIHQuYT09PWIuYSYmdC5iPT09Yi5iJiZ0LmM9PT1iLmN9LApnaU86ZnVuY3Rp
-b24oYSl7dmFyIHQscz10aGlzLmMKaWYocz09bnVsbCl0PUguZVEodGhpcy5hKQplbHNlIHQ9dHlwZW9m
-IHMhPT0ib2JqZWN0Ij9KLmhmKHMpOkguZVEocykKcmV0dXJuKHReSC5lUSh0aGlzLmIpKT4+PjB9LAp3
-OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYwppZih0PT1udWxsKXQ9dGhpcy5hCnJldHVybiJDbG9zdXJl
-ICciK0guZCh0aGlzLmQpKyInIG9mICIrKCJJbnN0YW5jZSBvZiAnIitILmQoSC5NKHQpKSsiJyIpfX0K
-SC5FcS5wcm90b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3JldHVybiJSdW50aW1lRXJyb3I6ICIrSC5kKHRo
-aXMuYSl9fQpILmtZLnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIkFzc2VydGlvbiBmYWls
-ZWQ6ICIrUC5wKHRoaXMuYSl9fQpILk41LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0
-aGlzLmF9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYT09PTB9LApnVjpmdW5jdGlvbigpe3Jl
-dHVybiBuZXcgSC5pNSh0aGlzLEguTGgodGhpcykuQygiaTU8MT4iKSl9LAp4NDpmdW5jdGlvbihhKXt2
-YXIgdCxzCmlmKHR5cGVvZiBhPT0ic3RyaW5nIil7dD10aGlzLmIKaWYodD09bnVsbClyZXR1cm4hMQpy
-ZXR1cm4gdGhpcy5YdSh0LGEpfWVsc2V7cz10aGlzLkNYKGEpCnJldHVybiBzfX0sCkNYOmZ1bmN0aW9u
-KGEpe3ZhciB0PXRoaXMuZAppZih0PT1udWxsKXJldHVybiExCnJldHVybiB0aGlzLkZoKHRoaXMuQnQo
-dCxKLmhmKGEpJjB4M2ZmZmZmZiksYSk+PTB9LApxOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscD10
-aGlzLG89bnVsbAppZih0eXBlb2YgYj09InN0cmluZyIpe3Q9cC5iCmlmKHQ9PW51bGwpcmV0dXJuIG8K
-cz1wLmoyKHQsYikKcj1zPT1udWxsP286cy5iCnJldHVybiByfWVsc2UgaWYodHlwZW9mIGI9PSJudW1i
-ZXIiJiYoYiYweDNmZmZmZmYpPT09Yil7cT1wLmMKaWYocT09bnVsbClyZXR1cm4gbwpzPXAuajIocSxi
-KQpyPXM9PW51bGw/bzpzLmIKcmV0dXJuIHJ9ZWxzZSByZXR1cm4gcC5hYShiKX0sCmFhOmZ1bmN0aW9u
-KGEpe3ZhciB0LHMscj10aGlzLmQKaWYocj09bnVsbClyZXR1cm4gbnVsbAp0PXRoaXMuQnQocixKLmhm
-KGEpJjB4M2ZmZmZmZikKcz10aGlzLkZoKHQsYSkKaWYoczwwKXJldHVybiBudWxsCnJldHVybiB0W3Nd
-LmJ9LApZOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbj10aGlzLG09SC5MaChuKQptLmQu
-YihiKQptLmNoWzFdLmIoYykKaWYodHlwZW9mIGI9PSJzdHJpbmciKXt0PW4uYgpuLkVIKHQ9PW51bGw/
-bi5iPW4ueksoKTp0LGIsYyl9ZWxzZSBpZih0eXBlb2YgYj09Im51bWJlciImJihiJjB4M2ZmZmZmZik9
-PT1iKXtzPW4uYwpuLkVIKHM9PW51bGw/bi5jPW4ueksoKTpzLGIsYyl9ZWxzZXtyPW4uZAppZihyPT1u
-dWxsKXI9bi5kPW4ueksoKQpxPUouaGYoYikmMHgzZmZmZmZmCnA9bi5CdChyLHEpCmlmKHA9PW51bGwp
-bi5FSShyLHEsW24uSG4oYixjKV0pCmVsc2V7bz1uLkZoKHAsYikKaWYobz49MClwW29dLmI9YwplbHNl
-IHAucHVzaChuLkhuKGIsYykpfX19LApLOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyPXRoaXMKSC5MaChy
-KS5DKCJ+KDEsMikiKS5iKGIpCnQ9ci5lCnM9ci5yCmZvcig7dCE9bnVsbDspe2IuJDIodC5hLHQuYikK
-aWYocyE9PXIucil0aHJvdyBILmIoUC5hNChyKSkKdD10LmN9fSwKRUg6ZnVuY3Rpb24oYSxiLGMpe3Zh
-ciB0LHM9dGhpcyxyPUguTGgocykKci5kLmIoYikKci5jaFsxXS5iKGMpCnQ9cy5qMihhLGIpCmlmKHQ9
-PW51bGwpcy5FSShhLGIscy5IbihiLGMpKQplbHNlIHQuYj1jfSwKa3M6ZnVuY3Rpb24oKXt0aGlzLnI9
-dGhpcy5yKzEmNjcxMDg4NjN9LApIbjpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcyxyPUguTGgocyks
-cT1uZXcgSC5kYihyLmQuYihhKSxyLmNoWzFdLmIoYikpCmlmKHMuZT09bnVsbClzLmU9cy5mPXEKZWxz
-ZXt0PXMuZgpxLmQ9dApzLmY9dC5jPXF9KytzLmEKcy5rcygpCnJldHVybiBxfSwKRmg6ZnVuY3Rpb24o
-YSxiKXt2YXIgdCxzCmlmKGE9PW51bGwpcmV0dXJuLTEKdD1hLmxlbmd0aApmb3Iocz0wO3M8dDsrK3Mp
-aWYoSi5STShhW3NdLmEsYikpcmV0dXJuIHMKcmV0dXJuLTF9LAp3OmZ1bmN0aW9uKGEpe3JldHVybiBQ
-Lm5PKHRoaXMpfSwKajI6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYVtiXX0sCkJ0OmZ1bmN0aW9uKGEsYil7
-cmV0dXJuIGFbYl19LApFSTpmdW5jdGlvbihhLGIsYyl7YVtiXT1jfSwKcm46ZnVuY3Rpb24oYSxiKXtk
-ZWxldGUgYVtiXX0sClh1OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuajIoYSxiKSE9bnVsbH0sCnpL
-OmZ1bmN0aW9uKCl7dmFyIHQ9Ijxub24taWRlbnRpZmllci1rZXk+IixzPU9iamVjdC5jcmVhdGUobnVs
-bCkKdGhpcy5FSShzLHQscykKdGhpcy5ybihzLHQpCnJldHVybiBzfSwKJGlGbzoxfQpILmRiLnByb3Rv
-dHlwZT17fQpILmk1LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEuYX0sCmds
-MDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmE9PT0wfSwKZ2t6OmZ1bmN0aW9uKGEpe3ZhciB0PXRo
-aXMuYSxzPW5ldyBILk42KHQsdC5yLHRoaXMuJHRpLkMoIk42PDE+IikpCnMuYz10LmUKcmV0dXJuIHN9
-LAp0ZzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmEueDQoYil9fQpILk42LnByb3RvdHlwZT17Cmds
-OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZH0sCkY6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLHM9dC5hCmlm
-KHQuYiE9PXMucil0aHJvdyBILmIoUC5hNChzKSkKZWxzZXtzPXQuYwppZihzPT1udWxsKXt0LnNxWShu
-dWxsKQpyZXR1cm4hMX1lbHNle3Quc3FZKHMuYSkKdC5jPXQuYy5jCnJldHVybiEwfX19LApzcVk6ZnVu
-Y3Rpb24oYSl7dGhpcy5kPXRoaXMuJHRpLmQuYihhKX0sCiRpQW46MX0KSC5kQy5wcm90b3R5cGU9ewok
-MTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hKGEpfSwKJFM6MX0KSC53Ti5wcm90b3R5cGU9ewokMjpm
-dW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmEoYSxiKX0sCiRTOjQ0fQpILlZYLnByb3RvdHlwZT17CiQx
-OmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEoSC55KGEpKX0sCiRTOjQwfQpILlZSLnByb3RvdHlwZT17
-Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIlJlZ0V4cC8iK3RoaXMuYSsiLyIrdGhpcy5iLmZsYWdzfSwKZ0hj
-OmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQuYwppZihzIT1udWxsKXJldHVybiBzCnM9dC5iCnJldHVy
-biB0LmM9SC52NCh0LmEscy5tdWx0aWxpbmUsIXMuaWdub3JlQ2FzZSxzLnVuaWNvZGUscy5kb3RBbGws
-ITApfSwKZGQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbmV3IEguS1codGhpcyxiLDApfSwKVVo6ZnVuY3Rp
-b24oYSxiKXt2YXIgdCxzPXRoaXMuZ0hjKCkKcy5sYXN0SW5kZXg9Ygp0PXMuZXhlYyhhKQppZih0PT1u
-dWxsKXJldHVybiBudWxsCnJldHVybiBuZXcgSC5FSyh0KX0sCiRpdlg6MSwKJGl3TDoxfQpILkVLLnBy
-b3RvdHlwZT17CnE6ZnVuY3Rpb24oYSxiKXt2YXIgdApILlNjKGIpCnQ9dGhpcy5iCmlmKGI+PXQubGVu
-Z3RoKXJldHVybiBILk9IKHQsYikKcmV0dXJuIHRbYl19LAokaU9kOjEsCiRpaWI6MX0KSC5LVy5wcm90
-b3R5cGU9ewpna3o6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBILlBiKHRoaXMuYSx0aGlzLmIsdGhpcy5j
-KX19CkguUGIucHJvdG90eXBlPXsKZ2w6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kfSwKRjpmdW5jdGlv
-bigpe3ZhciB0LHMscixxLHA9dGhpcyxvPXAuYgppZihvPT1udWxsKXJldHVybiExCnQ9cC5jCmlmKHQ8
-PW8ubGVuZ3RoKXtzPXAuYQpyPXMuVVoobyx0KQppZihyIT1udWxsKXtwLmQ9cgpvPXIuYgp0PW8uaW5k
-ZXgKcT10K29bMF0ubGVuZ3RoCmlmKHQ9PT1xKXtpZihzLmIudW5pY29kZSl7bz1wLmMKdD1vKzEKcz1w
-LmIKaWYodDxzLmxlbmd0aCl7bz1KLnJZKHMpLm0ocyxvKQppZihvPj01NTI5NiYmbzw9NTYzMTkpe289
-Qy54Qi5tKHMsdCkKbz1vPj01NjMyMCYmbzw9NTczNDN9ZWxzZSBvPSExfWVsc2Ugbz0hMX1lbHNlIG89
-ITEKcT0obz9xKzE6cSkrMX1wLmM9cQpyZXR1cm4hMH19cC5iPXAuZD1udWxsCnJldHVybiExfSwKJGlB
-bjoxfQpILnRRLnByb3RvdHlwZT17CnE6ZnVuY3Rpb24oYSxiKXtILlNjKGIpCmlmKGIhPT0wKUgudmgo
-UC54KGIsbnVsbCkpCnJldHVybiB0aGlzLmN9LAokaU9kOjF9CkgudW4ucHJvdG90eXBlPXsKZ2t6OmZ1
-bmN0aW9uKGEpe3JldHVybiBuZXcgSC5TZCh0aGlzLmEsdGhpcy5iLHRoaXMuYyl9fQpILlNkLnByb3Rv
-dHlwZT17CkY6ZnVuY3Rpb24oKXt2YXIgdCxzLHI9dGhpcyxxPXIuYyxwPXIuYixvPXAubGVuZ3RoLG49
-ci5hLG09bi5sZW5ndGgKaWYocStvPm0pe3IuZD1udWxsCnJldHVybiExfXQ9bi5pbmRleE9mKHAscSkK
-aWYodDwwKXtyLmM9bSsxCnIuZD1udWxsCnJldHVybiExfXM9dCtvCnIuZD1uZXcgSC50USh0LHApCnIu
-Yz1zPT09ci5jP3MrMTpzCnJldHVybiEwfSwKZ2w6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kfSwKJGlB
-bjoxfQpILkVULnByb3RvdHlwZT17JGlFVDoxLCRpZXE6MX0KSC5MWi5wcm90b3R5cGU9ewpnQTpmdW5j
-dGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LAokaVhqOjF9CkguRGcucHJvdG90eXBlPXsKcTpmdW5jdGlv
-bihhLGIpe0guU2MoYikKSC5vZChiLGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfSwKWTpmdW5jdGlvbihh
-LGIsYyl7SC5JZyhjKQpILm9kKGIsYSxhLmxlbmd0aCkKYVtiXT1jfSwKJGliUToxLAokaWNYOjEsCiRp
-ek06MX0KSC5QZy5wcm90b3R5cGU9ewpZOmZ1bmN0aW9uKGEsYixjKXtILlNjKGMpCkgub2QoYixhLGEu
-bGVuZ3RoKQphW2JdPWN9LAokaWJROjEsCiRpY1g6MSwKJGl6TToxfQpILnhqLnByb3RvdHlwZT17CnE6
-ZnVuY3Rpb24oYSxiKXtILlNjKGIpCkgub2QoYixhLGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19CkguZEUu
-cHJvdG90eXBlPXsKcTpmdW5jdGlvbihhLGIpe0guU2MoYikKSC5vZChiLGEsYS5sZW5ndGgpCnJldHVy
-biBhW2JdfX0KSC5aQS5wcm90b3R5cGU9ewpxOmZ1bmN0aW9uKGEsYil7SC5TYyhiKQpILm9kKGIsYSxh
-Lmxlbmd0aCkKcmV0dXJuIGFbYl19fQpILndmLnByb3RvdHlwZT17CnE6ZnVuY3Rpb24oYSxiKXtILlNj
-KGIpCkgub2QoYixhLGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19CkguUHEucHJvdG90eXBlPXsKcTpmdW5j
-dGlvbihhLGIpe0guU2MoYikKSC5vZChiLGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfX0KSC5lRS5wcm90
-b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApxOmZ1bmN0aW9uKGEsYil7SC5T
-YyhiKQpILm9kKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19fQpILlY2LnByb3RvdHlwZT17CmdBOmZ1
-bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH0sCnE6ZnVuY3Rpb24oYSxiKXtILlNjKGIpCkgub2QoYixh
-LGEubGVuZ3RoKQpyZXR1cm4gYVtiXX0sCiRpVjY6MSwKJGluNjoxfQpILlJHLnByb3RvdHlwZT17fQpI
-LlZQLnByb3RvdHlwZT17fQpILldCLnByb3RvdHlwZT17fQpILlpHLnByb3RvdHlwZT17fQpILkpjLnBy
-b3RvdHlwZT17CkM6ZnVuY3Rpb24oYSl7cmV0dXJuIEguY0Uodi50eXBlVW5pdmVyc2UsdGhpcyxhKX0s
-CktxOmZ1bmN0aW9uKGEpe3JldHVybiBILnY1KHYudHlwZVVuaXZlcnNlLHRoaXMsYSl9fQpILkcucHJv
-dG90eXBlPXt9CkgudTkucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfX0KSC5o
-ei5wcm90b3R5cGU9e30KSC5pTS5wcm90b3R5cGU9e30KUC50aC5wcm90b3R5cGU9ewokMTpmdW5jdGlv
-bihhKXt2YXIgdD10aGlzLmEscz10LmEKdC5hPW51bGwKcy4kMCgpfSwKJFM6MTB9ClAuaGEucHJvdG90
-eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQscwp0aGlzLmEuYT11Lk0uYihhKQp0PXRoaXMuYgpzPXRo
-aXMuYwp0LmZpcnN0Q2hpbGQ/dC5yZW1vdmVDaGlsZChzKTp0LmFwcGVuZENoaWxkKHMpfSwKJFM6MjB9
-ClAuVnMucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt0aGlzLmEuJDAoKX0sCiRDOiIkMCIsCiRSOjAs
-CiRTOjB9ClAuRnQucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt0aGlzLmEuJDAoKX0sCiRDOiIkMCIs
-CiRSOjAsCiRTOjB9ClAuVzMucHJvdG90eXBlPXsKQ1k6ZnVuY3Rpb24oYSxiKXtpZihzZWxmLnNldFRp
-bWVvdXQhPW51bGwpc2VsZi5zZXRUaW1lb3V0KEgudFIobmV3IFAueUgodGhpcyxiKSwwKSxhKQplbHNl
-IHRocm93IEguYihQLkw0KCJgc2V0VGltZW91dCgpYCBub3QgZm91bmQuIikpfX0KUC55SC5wcm90b3R5
-cGU9ewokMDpmdW5jdGlvbigpe3RoaXMuYi4kMCgpfSwKJEM6IiQwIiwKJFI6MCwKJFM6Mn0KUC5paC5w
-cm90b3R5cGU9ewphTTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj10aGlzLiR0aQpyLkMoIjEvIikuYihi
-KQp0PSF0aGlzLmJ8fHIuQygiYjg8MT4iKS5jKGIpCnM9dGhpcy5hCmlmKHQpcy5YZihiKQplbHNlIHMu
-WDIoci5kLmIoYikpfSwKdzA6ZnVuY3Rpb24oYSxiKXt2YXIgdD10aGlzLmEKaWYodGhpcy5iKXQuWkwo
-YSxiKQplbHNlIHQuTmsoYSxiKX19ClAuV00ucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJu
-IHRoaXMuYS4kMigwLGEpfSwKJFM6NDl9ClAuU1gucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt0
-aGlzLmEuJDIoMSxuZXcgSC5icShhLHUubC5iKGIpKSl9LAokQzoiJDIiLAokUjoyLAokUzoyMX0KUC5H
-cy5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3RoaXMuYShILlNjKGEpLGIpfSwKJFM6MjZ9ClAu
-RnkucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4iSXRlcmF0aW9uTWFya2VyKCIrdGhpcy5i
-KyIsICIrSC5kKHRoaXMuYSkrIikifX0KUC5HVi5wcm90b3R5cGU9ewpnbDpmdW5jdGlvbigpe3ZhciB0
-PXRoaXMuYwppZih0PT1udWxsKXJldHVybiB0aGlzLmIKcmV0dXJuIHRoaXMuJHRpLmQuYih0LmdsKCkp
-fSwKRjpmdW5jdGlvbigpe3ZhciB0LHMscixxLHA9dGhpcwpmb3IoOyEwOyl7dD1wLmMKaWYodCE9bnVs
-bClpZih0LkYoKSlyZXR1cm4hMAplbHNlIHAuYz1udWxsCnM9ZnVuY3Rpb24oYSxiLGMpe3ZhciBvLG49
-Ygp3aGlsZSh0cnVlKXRyeXtyZXR1cm4gYShuLG8pfWNhdGNoKG0pe289bQpuPWN9fShwLmEsMCwxKQpp
-ZihzIGluc3RhbmNlb2YgUC5GeSl7cj1zLmIKaWYocj09PTIpe3Q9cC5kCmlmKHQ9PW51bGx8fHQubGVu
-Z3RoPT09MCl7cC5zRUMobnVsbCkKcmV0dXJuITF9aWYoMD49dC5sZW5ndGgpcmV0dXJuIEguT0godCwt
-MSkKcC5hPXQucG9wKCkKY29udGludWV9ZWxzZXt0PXMuYQppZihyPT09Myl0aHJvdyB0CmVsc2V7cT1K
-LklUKHQpCmlmKHEgaW5zdGFuY2VvZiBQLkdWKXt0PXAuZAppZih0PT1udWxsKXQ9cC5kPVtdCkMuTm0u
-aSh0LHAuYSkKcC5hPXEuYQpjb250aW51ZX1lbHNle3AuYz1xCmNvbnRpbnVlfX19fWVsc2V7cC5zRUMo
-cykKcmV0dXJuITB9fXJldHVybiExfSwKc0VDOmZ1bmN0aW9uKGEpe3RoaXMuYj10aGlzLiR0aS5kLmIo
-YSl9LAokaUFuOjF9ClAucTQucHJvdG90eXBlPXsKZ2t6OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5H
-Vih0aGlzLmEoKSx0aGlzLiR0aS5DKCJHVjwxPiIpKX19ClAuYjgucHJvdG90eXBlPXt9ClAuUGYucHJv
-dG90eXBlPXsKdzA6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihhPT1udWxsKWE9bmV3IFAubigpCnQ9dGhp
-cy5hCmlmKHQuYSE9PTApdGhyb3cgSC5iKFAuUFYoIkZ1dHVyZSBhbHJlYWR5IGNvbXBsZXRlZCIpKQp0
-Lk5rKGEsYil9LApwbTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy53MChhLG51bGwpfX0KUC5aZi5wcm90
-b3R5cGU9ewphTTpmdW5jdGlvbihhLGIpe3ZhciB0CnRoaXMuJHRpLkMoIjEvIikuYihiKQp0PXRoaXMu
-YQppZih0LmEhPT0wKXRocm93IEguYihQLlBWKCJGdXR1cmUgYWxyZWFkeSBjb21wbGV0ZWQiKSkKdC5Y
-ZihiKX19ClAuRmUucHJvdG90eXBlPXsKSFI6ZnVuY3Rpb24oYSl7aWYoKHRoaXMuYyYxNSkhPT02KXJl
-dHVybiEwCnJldHVybiB0aGlzLmIuYi5idih1LmFsLmIodGhpcy5kKSxhLmEsdS5jSix1LkspfSwKS3c6
-ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5lLHM9dS56LHI9dS5LLHE9dGhpcy4kdGkuQygiMi8iKSxwPXRo
-aXMuYi5iCmlmKHUuRS5jKHQpKXJldHVybiBxLmIocC5ycCh0LGEuYSxhLmIscyxyLHUubCkpCmVsc2Ug
-cmV0dXJuIHEuYihwLmJ2KHUudy5iKHQpLGEuYSxzLHIpKX19ClAudnMucHJvdG90eXBlPXsKU3E6ZnVu
-Y3Rpb24oYSxiLGMpe3ZhciB0LHMscixxPXRoaXMuJHRpCnEuS3EoYykuQygiMS8oMikiKS5iKGEpCnQ9
-JC5YMwppZih0IT09Qy5OVSl7Yy5DKCJAPDAvPiIpLktxKHEuZCkuQygiMSgyKSIpLmIoYSkKaWYoYiE9
-bnVsbCliPVAuVkgoYix0KX1zPW5ldyBQLnZzKCQuWDMsYy5DKCJ2czwwPiIpKQpyPWI9PW51bGw/MToz
-CnRoaXMueGYobmV3IFAuRmUocyxyLGEsYixxLkMoIkA8MT4iKS5LcShjKS5DKCJGZTwxLDI+IikpKQpy
-ZXR1cm4gc30sClc3OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuU3EoYSxudWxsLGIpfSwKUWQ6ZnVu
-Y3Rpb24oYSxiLGMpe3ZhciB0LHM9dGhpcy4kdGkKcy5LcShjKS5DKCIxLygyKSIpLmIoYSkKdD1uZXcg
-UC52cygkLlgzLGMuQygidnM8MD4iKSkKdGhpcy54ZihuZXcgUC5GZSh0LChiPT1udWxsPzE6Myl8MTYs
-YSxiLHMuQygiQDwxPiIpLktxKGMpLkMoIkZlPDEsMj4iKSkpCnJldHVybiB0fSwKeGY6ZnVuY3Rpb24o
-YSl7dmFyIHQscz10aGlzLHI9cy5hCmlmKHI8PTEpe2EuYT11LnguYihzLmMpCnMuYz1hfWVsc2V7aWYo
-cj09PTIpe3Q9dS5fLmIocy5jKQpyPXQuYQppZihyPDQpe3QueGYoYSkKcmV0dXJufXMuYT1yCnMuYz10
-LmN9UC5UayhudWxsLG51bGwscy5iLHUuTS5iKG5ldyBQLmRhKHMsYSkpKX19LApqUTpmdW5jdGlvbihh
-KXt2YXIgdCxzLHIscSxwLG89dGhpcyxuPXt9Cm4uYT1hCmlmKGE9PW51bGwpcmV0dXJuCnQ9by5hCmlm
-KHQ8PTEpe3M9dS54LmIoby5jKQpyPW8uYz1hCmlmKHMhPW51bGwpe2Zvcig7cT1yLmEscSE9bnVsbDty
-PXEpO3IuYT1zfX1lbHNle2lmKHQ9PT0yKXtwPXUuXy5iKG8uYykKdD1wLmEKaWYodDw0KXtwLmpRKGEp
-CnJldHVybn1vLmE9dApvLmM9cC5jfW4uYT1vLk44KGEpClAuVGsobnVsbCxudWxsLG8uYix1Lk0uYihu
-ZXcgUC5vUShuLG8pKSl9fSwKYWg6ZnVuY3Rpb24oKXt2YXIgdD11LnguYih0aGlzLmMpCnRoaXMuYz1u
-dWxsCnJldHVybiB0aGlzLk44KHQpfSwKTjg6ZnVuY3Rpb24oYSl7dmFyIHQscyxyCmZvcih0PWEscz1u
-dWxsO3QhPW51bGw7cz10LHQ9cil7cj10LmEKdC5hPXN9cmV0dXJuIHN9LApISDpmdW5jdGlvbihhKXt2
-YXIgdCxzPXRoaXMscj1zLiR0aQpyLkMoIjEvIikuYihhKQppZihyLkMoImI4PDE+IikuYyhhKSlpZihy
-LmMoYSkpUC5BOShhLHMpCmVsc2UgUC5rMyhhLHMpCmVsc2V7dD1zLmFoKCkKci5kLmIoYSkKcy5hPTQK
-cy5jPWEKUC5IWihzLHQpfX0sClgyOmZ1bmN0aW9uKGEpe3ZhciB0LHM9dGhpcwpzLiR0aS5kLmIoYSkK
-dD1zLmFoKCkKcy5hPTQKcy5jPWEKUC5IWihzLHQpfSwKWkw6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRo
-aXMKdS5sLmIoYikKdD1zLmFoKCkKcy5hPTgKcy5jPW5ldyBQLkN3KGEsYikKUC5IWihzLHQpfSwKWGY6
-ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPXQuJHRpCnMuQygiMS8iKS5iKGEpCmlmKHMuQygiYjg8MT4i
-KS5jKGEpKXt0LmNVKGEpCnJldHVybn10LmE9MQpQLlRrKG51bGwsbnVsbCx0LmIsdS5NLmIobmV3IFAu
-ckgodCxhKSkpfSwKY1U6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPXQuJHRpCnMuQygiYjg8MT4iKS5i
-KGEpCmlmKHMuYyhhKSl7aWYoYS5hPT09OCl7dC5hPTEKUC5UayhudWxsLG51bGwsdC5iLHUuTS5iKG5l
-dyBQLktGKHQsYSkpKX1lbHNlIFAuQTkoYSx0KQpyZXR1cm59UC5rMyhhLHQpfSwKTms6ZnVuY3Rpb24o
-YSxiKXt0aGlzLmE9MQpQLlRrKG51bGwsbnVsbCx0aGlzLmIsdS5NLmIobmV3IFAuWkwodGhpcyxhLGIp
-KSl9LAokaWI4OjF9ClAuZGEucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtQLkhaKHRoaXMuYSx0aGlz
-LmIpfSwKJFM6MH0KUC5vUS5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe1AuSFoodGhpcy5iLHRoaXMu
-YS5hKX0sCiRTOjB9ClAucFYucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnQu
-YT0wCnQuSEgoYSl9LAokUzoxMH0KUC5VNy5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3UubC5i
-KGIpCnRoaXMuYS5aTChhLGIpfSwKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuJDIoYSxudWxsKX0s
-CiRDOiIkMiIsCiREOmZ1bmN0aW9uKCl7cmV0dXJuW251bGxdfSwKJFM6Mjl9ClAudnIucHJvdG90eXBl
-PXsKJDA6ZnVuY3Rpb24oKXt0aGlzLmEuWkwodGhpcy5iLHRoaXMuYyl9LAokUzowfQpQLnJILnByb3Rv
-dHlwZT17CiQwOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5hCnQuWDIodC4kdGkuZC5iKHRoaXMuYikpfSwK
-JFM6MH0KUC5LRi5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe1AuQTkodGhpcy5iLHRoaXMuYSl9LAok
-UzowfQpQLlpMLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5hLlpMKHRoaXMuYix0aGlzLmMp
-fSwKJFM6MH0KUC5SVC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0LHMscixxLHAsbyxuPXRo
-aXMsbT1udWxsCnRyeXtyPW4uYwptPXIuYi5iLnp6KHUuZk8uYihyLmQpLHUueil9Y2F0Y2gocSl7dD1I
-LlJ1KHEpCnM9SC50cyhxKQppZihuLmQpe3I9dS5uLmIobi5hLmEuYykuYQpwPXQKcD1yPT1udWxsP3A9
-PW51bGw6cj09PXAKcj1wfWVsc2Ugcj0hMQpwPW4uYgppZihyKXAuYj11Lm4uYihuLmEuYS5jKQplbHNl
-IHAuYj1uZXcgUC5Ddyh0LHMpCnAuYT0hMApyZXR1cm59aWYodS5jLmMobSkpe2lmKG0gaW5zdGFuY2Vv
-ZiBQLnZzJiZtLmE+PTQpe2lmKG0uYT09PTgpe3I9bi5iCnIuYj11Lm4uYihtLmMpCnIuYT0hMH1yZXR1
-cm59bz1uLmEuYQpyPW4uYgpyLmI9bS5XNyhuZXcgUC5qWihvKSx1LnopCnIuYT0hMX19LAokUzoyfQpQ
-LmpaLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmF9LAokUzozOX0KUC5ycS5w
-cm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0LHMscixxLHAsbyxuLG09dGhpcwp0cnl7cj1tLmIK
-cT1yLiR0aQpwPXEuZApvPXAuYihtLmMpCm0uYS5iPXIuYi5iLmJ2KHEuQygiMi8oMSkiKS5iKHIuZCks
-byxxLkMoIjIvIikscCl9Y2F0Y2gobil7dD1ILlJ1KG4pCnM9SC50cyhuKQpyPW0uYQpyLmI9bmV3IFAu
-Q3codCxzKQpyLmE9ITB9fSwKJFM6Mn0KUC5SVy5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0
-LHMscixxLHAsbyxuLG0sbD10aGlzCnRyeXt0PXUubi5iKGwuYS5hLmMpCnE9bC5jCmlmKEgub1QocS5I
+SSgkYXN5bmMkR2Uscyl9LApxTzpmdW5jdGlvbihhKXt2YXIgdCxzPWEuZ2V0Qm91bmRpbmdDbGllbnRS
+ZWN0KCkscj1DLkNELnpRKCQuZmkoKS5vZmZzZXRIZWlnaHQpLHE9d2luZG93LmlubmVySGVpZ2h0LHA9
+Qy5DRC56USgkLkRXKCkub2Zmc2V0SGVpZ2h0KQppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBx
+LkhOKCkKdD1zLmJvdHRvbQppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiB0Lm9zKCkKaWYodD5x
+LShwKzE0KSlKLmRoKGEpCmVsc2V7cT1zLnRvcAppZih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBx
+LkooKQppZihxPHIrMTQpSi5kaChhKX19LApmRzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAKaWYo
+YSE9bnVsbCl7dD1kb2N1bWVudApzPXQuZ2V0RWxlbWVudEJ5SWQoIm8iK0guZChhKSkKcj10LnF1ZXJ5
+U2VsZWN0b3IoIi5saW5lLSIrSC5kKGIpKQppZihzIT1udWxsKXtMLnFPKHMpCkouZFIocykuaSgwLCJ0
+YXJnZXQiKX1lbHNlIGlmKHIhPW51bGwpTC5xTyhyLnBhcmVudEVsZW1lbnQpCmlmKHIhPW51bGwpSi5k
+Uih1LmguYShyLnBhcmVudE5vZGUpKS5pKDAsImhpZ2hsaWdodCIpfWVsc2V7dD1kb2N1bWVudApxPXUu
+aApILkRoKHEscSwiVCIsInF1ZXJ5U2VsZWN0b3JBbGwiKQp0PXQucXVlcnlTZWxlY3RvckFsbCgiLmxp
+bmUtbm8iKQpwPW5ldyBXLnd6KHQsdS5UKQppZihwLmdBKHApPT09MClyZXR1cm4KTC5xTyhxLmEoQy50
+NS5ndEgodCkpKX19LAphZjpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciB0LHMscj1MLkc2KHdpbmRvdy5s
+b2NhdGlvbi5ocmVmKSxxPUwuYUsod2luZG93LmxvY2F0aW9uLmhyZWYpCmlmKHIhPW51bGwpe3Q9ZG9j
+dW1lbnQuZ2V0RWxlbWVudEJ5SWQoIm8iK0guZChyKSkKaWYodCE9bnVsbClKLmRSKHQpLlIoMCwidGFy
+Z2V0Iil9aWYocSE9bnVsbCl7cz1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKCIubGluZS0iK0guZChxKSkK
+aWYocyE9bnVsbClKLmRSKHMucGFyZW50RWxlbWVudCkuUigwLCJoaWdobGlnaHQiKX1pZihhPT13aW5k
+b3cubG9jYXRpb24ucGF0aG5hbWUpe0wuZkcoYixjKQplLiQwKCl9ZWxzZSBMLkc3KGEsYixjLGQsZSl9
+LApRNDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj1QLmhLKGEpLHE9dS5OCnE9UC5GbChxLHEpCmZvcih0
+PXIuZ2hZKCksdD10LmdQdSh0KSx0PXQuZ2t6KHQpO3QuRigpOyl7cz10LmdsKCkKcS5ZKDAscy5hLHMu
+Yil9Zm9yKHQ9Yi5nUHUoYiksdD10Lmdreih0KTt0LkYoKTspe3M9dC5nbCgpCnEuWSgwLHMuYSxzLmIp
+fXEuWSgwLCJhdXRoVG9rZW4iLCQuVUUoKSkKcmV0dXJuIHIubm0oMCxxKS5aKDApfSwKVDE6ZnVuY3Rp
+b24oYSl7dmFyIHQscyxyLHEscCxvLG4sbSxsLGs9JC5oTCgpCkoubDUoaywiIikKaWYoYT09bnVsbCl7
+dD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJwIikKdC50ZXh0Q29udGVudD0iU2VlIGRldGFpbHMgYWJv
+dXQgYSBwcm9wb3NlZCBlZGl0LiIKQy5MdC5zUCh0LEguVk0oWyJwbGFjZWhvbGRlciJdLHUucykpCmsu
+YXBwZW5kQ2hpbGQodCkKQy5MdC5GRih0KQpyZXR1cm59cz1hLmQKcj0kLm5VKCkKcT1yLnpmKHMpCnA9
+YS5iCm89ZG9jdW1lbnQKbj1yLkhQKHMsSi5UMChvLnF1ZXJ5U2VsZWN0b3IoIi5yb290IikudGV4dENv
+bnRlbnQpKQptPWEuYwpsPW8uY3JlYXRlRWxlbWVudCgicCIpCmsuYXBwZW5kQ2hpbGQobCkKbC5hcHBl
+bmRDaGlsZChvLmNyZWF0ZVRleHROb2RlKEguZChwKSsiIGF0ICIpKQpyPXUuTgpyPVcuSjYoTC5RNChh
+LmUsUC5FRihbImxpbmUiLEouQWMobSldLHIscikpKQpyLmFwcGVuZENoaWxkKG8uY3JlYXRlVGV4dE5v
+ZGUoSC5kKG4pKyI6IitILmQobSkrIi4iKSkKbC5hcHBlbmRDaGlsZChyKQpKLmRoKGwpCkwuQ0MoYSxr
+LHEpCkwuRnooYSxrKX0sCkxIOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxq
+LGksaCxnPSQueVAoKQpKLmw1KGcsIiIpCmlmKGIuZ0EoYik9PT0wKXt0PWRvY3VtZW50CnM9dC5jcmVh
+dGVFbGVtZW50KCJwIikKZy5hcHBlbmRDaGlsZChzKQpzLmFwcGVuZENoaWxkKHQuY3JlYXRlVGV4dE5v
+ZGUoIk5vIHByb3Bvc2VkIGVkaXRzIikpfWVsc2UgZm9yKGc9Yi5nUHUoYiksZz1nLmdreihnKSx0PXUu
+USxyPXQuQygifigxKSIpLHE9dS5NLHQ9dC5jO2cuRigpOyl7cD1nLmdsKCkKbz1kb2N1bWVudApzPW8u
+Y3JlYXRlRWxlbWVudCgicCIpCm49JC55UCgpCm4uYXBwZW5kQ2hpbGQocykKcy5hcHBlbmRDaGlsZChv
+LmNyZWF0ZVRleHROb2RlKEguZChwLmEpKyI6IikpCm09by5jcmVhdGVFbGVtZW50KCJ1bCIpCm4uYXBw
+ZW5kQ2hpbGQobSkKZm9yKHA9Si5JVChwLmIpO3AuRigpOyl7bj1wLmdsKCkKbD1vLmNyZWF0ZUVsZW1l
+bnQoImxpIikKbS5hcHBlbmRDaGlsZChsKQpKLmRSKGwpLmkoMCwiZWRpdCIpCms9by5jcmVhdGVFbGVt
+ZW50KCJhIikKbC5hcHBlbmRDaGlsZChrKQprLmNsYXNzTGlzdC5hZGQoImVkaXQtbGluayIpCmo9bi5j
+Cmk9SC5kKGopCmsuc2V0QXR0cmlidXRlKCJkYXRhLSIrbmV3IFcuU3kobmV3IFcuaTcoaykpLk8oIm9m
+ZnNldCIpLGkpCmg9bi5hCmk9SC5kKGgpCmsuc2V0QXR0cmlidXRlKCJkYXRhLSIrbmV3IFcuU3kobmV3
+IFcuaTcoaykpLk8oImxpbmUiKSxpKQprLmFwcGVuZENoaWxkKG8uY3JlYXRlVGV4dE5vZGUoImxpbmUg
+IitILmQoaCkpKQppPXIuYShuZXcgTC5FRShqLGgsYSkpCnEuYShudWxsKQpXLkpFKGssImNsaWNrIixp
+LCExLHQpCmwuYXBwZW5kQ2hpbGQoby5jcmVhdGVUZXh0Tm9kZSgiOiAiK0guZChuLmIpKSl9fWlmKGMp
+TC5UMShudWxsKX0sCkZyOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHI9d2luZG93LmxvY2F0aW9uLHE9
+UC5oSygociYmQy5FeCkuZ0RyKHIpK0guZChhKSkKcj11Lk4Kcj1QLkZsKHIscikKaWYoYiE9bnVsbCly
+LlkoMCwib2Zmc2V0IixILmQoYikpCmlmKGMhPW51bGwpci5ZKDAsImxpbmUiLEguZChjKSkKci5ZKDAs
+ImF1dGhUb2tlbiIsJC5VRSgpKQpxPXEubm0oMCxyKQpyPXdpbmRvdy5oaXN0b3J5CnQ9dS56CnM9cS5a
+KDApCnIudG9TdHJpbmcKci5wdXNoU3RhdGUobmV3IFAuQmYoW10sW10pLlB2KFAuRmwodCx0KSksIiIs
+cyl9LApFbjpmdW5jdGlvbihhKXt2YXIgdD1KLm0oZG9jdW1lbnQucXVlcnlTZWxlY3RvcigiLnJvb3Qi
+KS50ZXh0Q29udGVudCwiLyIpCmlmKEMueEIubihhLHQpKXJldHVybiBDLnhCLkcoYSx0Lmxlbmd0aCkK
+ZWxzZSByZXR1cm4gYX0sCkJYOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyPXt9CnIuYT1hCmE9TC5Fbihh
+KQpyLmE9YQokLkQ5KCkudGV4dENvbnRlbnQ9YQp0PWRvY3VtZW50CnM9dS5oCkguRGgocyxzLCJUIiwi
+cXVlcnlTZWxlY3RvckFsbCIpCnQ9bmV3IFcud3oodC5xdWVyeVNlbGVjdG9yQWxsKCIubmF2LXBhbmVs
+IC5uYXYtbGluayIpLHUuVCkKdC5LKHQsbmV3IEwuVlMocikpfSwKQkU6ZnVuY3Rpb24oYSxiLGMpe3Zh
+ciB0PSIucmVnaW9ucyIscz1kb2N1bWVudCxyPXMucXVlcnlTZWxlY3Rvcih0KSxxPXMucXVlcnlTZWxl
+Y3RvcigiLmNvZGUiKQpKLnRIKHIsYi5hLCQuS0coKSkKSi50SChxLGIuYiwkLktHKCkpCkwuTEgoYSxi
+LmQsYykKTC52VSgpCkwueVgoIi5jb2RlIiwhMCkKTC55WCh0LCEwKX0sCnRYOmZ1bmN0aW9uKGEsYil7
+dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaixpLGgsZz1kb2N1bWVudCxmPWcuY3JlYXRlRWxlbWVudCgi
+dWwiKQphLmFwcGVuZENoaWxkKGYpCmZvcih0PWIubGVuZ3RoLHM9dS5NLHI9MDtyPGIubGVuZ3RoO2Iu
+bGVuZ3RoPT09dHx8KDAsSC5saykoYiksKytyKXtxPWJbcl0KcD1nLmNyZWF0ZUVsZW1lbnQoImxpIikK
+Zi5hcHBlbmRDaGlsZChwKQpvPUouUkUocCkKaWYocS5hPT09Qy5ZMil7by5nUChwKS5pKDAsImRpciIp
+Cm49Zy5jcmVhdGVFbGVtZW50KCJzcGFuIikKcC5hcHBlbmRDaGlsZChuKQpvPUouUkUobikKby5nUChu
+KS5pKDAsImFycm93IikKby5zaGYobiwiJiN4MjVCQzsiKQptPWcuY3JlYXRlRWxlbWVudCgic3BhbiIp
+CnAuYXBwZW5kQ2hpbGQobSkKSi5sNShtLCImI3gxRjRDMTsiKQpwLmFwcGVuZENoaWxkKGcuY3JlYXRl
+VGV4dE5vZGUocS5iKSkKTC50WChwLHEuYykKTC5reihuKX1lbHNle28uc2hmKHAsIiYjeDFGNEM0OyIp
+Cmw9Zy5jcmVhdGVFbGVtZW50KCJhIikKcC5hcHBlbmRDaGlsZChsKQpvPUouUkUobCkKby5nUChsKS5p
+KDAsIm5hdi1saW5rIikKbC5zZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5TeShuZXcgVy5pNyhsKSku
+TygibmFtZSIpLHEuZCkKbC5zZXRBdHRyaWJ1dGUoImhyZWYiLHEuZSkKbC5hcHBlbmRDaGlsZChnLmNy
+ZWF0ZVRleHROb2RlKHEuYikpCm89by5nVmwobCkKaz1vLiR0aQpqPWsuQygifigxKSIpLmEobmV3IEwu
+VEQoKSkKcy5hKG51bGwpClcuSkUoby5hLG8uYixqLCExLGsuYykKaT1xLmYKaWYodHlwZW9mIGkhPT0i
+bnVtYmVyIilyZXR1cm4gaS5vcygpCmlmKGk+MCl7aD1nLmNyZWF0ZUVsZW1lbnQoInNwYW4iKQpwLmFw
+cGVuZENoaWxkKGgpCkouZFIoaCkuaSgwLCJlZGl0LWNvdW50IikKbz0iIitpKyIgIgppZihpPT09MSlr
+PSJlZGl0IgplbHNlIGs9ImVkaXRzIgpoLnNldEF0dHJpYnV0ZSgidGl0bGUiLG8raykKaC5hcHBlbmRD
+aGlsZChnLmNyZWF0ZVRleHROb2RlKEMuam4uWihpKSkpfX19fSwKRno6ZnVuY3Rpb24oYSxiKXt2YXIg
+dCxzLHIscSxwLG8sbixtLGwsayxqLGk9YS5hCmlmKGk9PW51bGwpcmV0dXJuCnQ9ZG9jdW1lbnQKcz10
+LmNyZWF0ZUVsZW1lbnQoInAiKQpyPWIuYXBwZW5kQ2hpbGQocykKcz10LmNyZWF0ZUVsZW1lbnQoInNw
+YW4iKQpxPXUucwpKLk11KHMsSC5WTShbInR5cGUtZGVzY3JpcHRpb24iXSxxKSkKcy5hcHBlbmRDaGls
+ZCh0LmNyZWF0ZVRleHROb2RlKCJBY3Rpb25zIikpCnIuYXBwZW5kQ2hpbGQocykKci5hcHBlbmRDaGls
+ZCh0LmNyZWF0ZVRleHROb2RlKCI6IikpCnA9dC5jcmVhdGVFbGVtZW50KCJwIikKYi5hcHBlbmRDaGls
+ZChwKQpmb3Iocz1pLmxlbmd0aCxvPXUuWCxuPTA7bjxpLmxlbmd0aDtpLmxlbmd0aD09PXN8fCgwLEgu
+bGspKGkpLCsrbil7bT1pW25dCmw9dC5jcmVhdGVFbGVtZW50KCJhIikKcC5hcHBlbmRDaGlsZChsKQps
+LmFwcGVuZENoaWxkKHQuY3JlYXRlVGV4dE5vZGUobS5hKSkKbC5zZXRBdHRyaWJ1dGUoImhyZWYiLG0u
+YikKaz1vLmEoSC5WTShbImFkZC1oaW50LWxpbmsiLCJiZWZvcmUtYXBwbHkiLCJidXR0b24iXSxxKSkK
+aj1KLmRSKGwpCmouVjEoMCkKai5GVigwLGspfX0sCkNDOmZ1bmN0aW9uKGE4LGE5LGIwKXt2YXIgdCxz
+LHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZSxkLGMsYixhLGEwLGExLGEyLGEzLGE0LGE1LGE2LGE3
+CmZvcih0PWE4LmYscz10Lmxlbmd0aCxyPXUucyxxPXUuWCxwPXUuUSxvPXAuQygifigxKSIpLG49dS5N
+LHA9cC5jLG09MDttPHQubGVuZ3RoO3QubGVuZ3RoPT09c3x8KDAsSC5saykodCksKyttKXtsPXRbbV0K
+az1kb2N1bWVudApqPWsuY3JlYXRlRWxlbWVudCgicCIpCmk9cS5hKEguVk0oWyJ0cmFjZSJdLHIpKQpo
+PUouZFIoaikKaC5WMSgwKQpoLkZWKDAsaSkKZz1hOS5hcHBlbmRDaGlsZChqKQpqPWsuY3JlYXRlRWxl
+bWVudCgic3BhbiIpCmk9cS5hKEguVk0oWyJ0eXBlLWRlc2NyaXB0aW9uIl0scikpCmg9Si5kUihqKQpo
+LlYxKDApCmguRlYoMCxpKQpqLmFwcGVuZENoaWxkKGsuY3JlYXRlVGV4dE5vZGUobC5hKSkKZy5hcHBl
+bmRDaGlsZChqKQpnLmFwcGVuZENoaWxkKGsuY3JlYXRlVGV4dE5vZGUoIjoiKSkKaj1rLmNyZWF0ZUVs
+ZW1lbnQoInVsIikKaT1xLmEoSC5WTShbInRyYWNlIl0scikpCmg9Si5kUihqKQpoLlYxKDApCmguRlYo
+MCxpKQpmPWcuYXBwZW5kQ2hpbGQoaikKZm9yKGo9bC5iLGk9ai5sZW5ndGgsZT0wO2U8ai5sZW5ndGg7
+ai5sZW5ndGg9PT1pfHwoMCxILmxrKShqKSwrK2Upe2Q9altlXQpjPWsuY3JlYXRlRWxlbWVudCgibGki
+KQpmLmFwcGVuZENoaWxkKGMpCmI9ay5jcmVhdGVFbGVtZW50KCJzcGFuIikKYT1xLmEoSC5WTShbImZ1
+bmN0aW9uIl0scikpCmg9Si5kUihiKQpoLlYxKDApCmguRlYoMCxhKQphPWQuYgpMLmtEKGIsYT09bnVs
+bD8idW5rbm93biI6YSkKYy5hcHBlbmRDaGlsZChiKQphMD1kLmMKaWYoYTAhPW51bGwpe2MuYXBwZW5k
+Q2hpbGQoay5jcmVhdGVUZXh0Tm9kZSgiICgiKSkKYTE9YTAuYgphMj1rLmNyZWF0ZUVsZW1lbnQoImEi
+KQphMi5hcHBlbmRDaGlsZChrLmNyZWF0ZVRleHROb2RlKEguZChhMC5jKSsiOiIrSC5kKGExKSkpCmEy
+LnNldEF0dHJpYnV0ZSgiaHJlZiIsYTAuYSkKYTIuY2xhc3NMaXN0LmFkZCgibmF2LWxpbmsiKQpjLmFw
+cGVuZENoaWxkKGEyKQpjLmFwcGVuZENoaWxkKGsuY3JlYXRlVGV4dE5vZGUoIikiKSl9Yy5hcHBlbmRD
+aGlsZChrLmNyZWF0ZVRleHROb2RlKCI6ICIpKQpiPWQuYQpMLmtEKGMsYj09bnVsbD8idW5rbm93biI6
+YikKYj1kLmQKaWYoYi5sZW5ndGghPT0wKXthPWsuY3JlYXRlRWxlbWVudCgicCIpCmEzPXEuYShILlZN
+KFsiZHJhd2VyIiwiYmVmb3JlLWFwcGx5Il0scikpCmg9Si5kUihhKQpoLlYxKDApCmguRlYoMCxhMykK
+YTQ9Yy5hcHBlbmRDaGlsZChhKQpmb3IoYT1iLmxlbmd0aCxhNT0wO2E1PGIubGVuZ3RoO2IubGVuZ3Ro
+PT09YXx8KDAsSC5saykoYiksKythNSl7YTY9YlthNV0KYTM9ay5jcmVhdGVFbGVtZW50KCJidXR0b24i
+KQphNz1vLmEobmV3IEwuQVMoYTYsYTApKQpuLmEobnVsbCkKVy5KRShhMywiY2xpY2siLGE3LCExLHAp
+CmEzLmFwcGVuZENoaWxkKGsuY3JlYXRlVGV4dE5vZGUoTS5PWChhNi5hKSkpCmE0LmFwcGVuZENoaWxk
+KGEzKX19fX19LAprRDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj1ILlZNKGIuc3BsaXQoIi4iKSx1LnMp
+LHE9Qy5ObS5ndEgocikscD1kb2N1bWVudAphLmFwcGVuZENoaWxkKHAuY3JlYXRlVGV4dE5vZGUocSkp
+CmZvcihxPUgucUMociwxLG51bGwsdS5OKSxxPW5ldyBILmE3KHEscS5nQShxKSxxLiR0aS5DKCJhNzxh
+TC5FPiIpKSx0PUouUkUoYSk7cS5GKCk7KXtzPXEuZAp0Lm56KGEsImJlZm9yZWVuZCIsIiYjODIwMzsu
+IixudWxsLG51bGwpCmEuYXBwZW5kQ2hpbGQocC5jcmVhdGVUZXh0Tm9kZShzKSl9fSwKZTpmdW5jdGlv
+biBlKCl7fSwKVlc6ZnVuY3Rpb24gVlcoYSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwK
+b1o6ZnVuY3Rpb24gb1ooKXt9LApqcjpmdW5jdGlvbiBqcigpe30sCnFsOmZ1bmN0aW9uIHFsKCl7fSwK
+eTg6ZnVuY3Rpb24geTgoKXt9LApIaTpmdW5jdGlvbiBIaSgpe30sCkJUOmZ1bmN0aW9uIEJUKCl7fSwK
+TDpmdW5jdGlvbiBMKCl7fSwKV3g6ZnVuY3Rpb24gV3goYSxiKXt0aGlzLmE9YQp0aGlzLmI9Yn0sCkFP
+OmZ1bmN0aW9uIEFPKGEpe3RoaXMuYT1hfSwKZE46ZnVuY3Rpb24gZE4oYSl7dGhpcy5hPWF9LApIbzpm
+dW5jdGlvbiBIbyhhKXt0aGlzLmE9YX0sCnh6OmZ1bmN0aW9uIHh6KGEsYil7dGhpcy5hPWEKdGhpcy5i
+PWJ9LApJQzpmdW5jdGlvbiBJQygpe30sCmZDOmZ1bmN0aW9uIGZDKGEsYil7dGhpcy5hPWEKdGhpcy5i
+PWJ9LApuVDpmdW5jdGlvbiBuVChhLGIsYyl7dGhpcy5hPWEKdGhpcy5iPWIKdGhpcy5jPWN9LApCWjpm
+dW5jdGlvbiBCWihhKXt0aGlzLmE9YX0sCkdIOmZ1bmN0aW9uIEdIKCl7fSwKRUU6ZnVuY3Rpb24gRUUo
+YSxiLGMpe3RoaXMuYT1hCnRoaXMuYj1iCnRoaXMuYz1jfSwKUUw6ZnVuY3Rpb24gUUwoYSxiKXt0aGlz
+LmE9YQp0aGlzLmI9Yn0sClZTOmZ1bmN0aW9uIFZTKGEpe3RoaXMuYT1hfSwKVEQ6ZnVuY3Rpb24gVEQo
+KXt9LApBUzpmdW5jdGlvbiBBUyhhLGIpe3RoaXMuYT1hCnRoaXMuYj1ifSwKWEE6ZnVuY3Rpb24gWEEo
+KXt9LAptSzpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbj1ILlZNKFtdLHUuZmgpCmZvcih0PUou
+SVQodS5SLmEoYSkpO3QuRigpOyl7cz10LmdsKCkKcj1KLlU2KHMpCnE9TC5wMihILmMoci5xKHMsInR5
+cGUiKSkpCnA9SC5jKHIucShzLCJuYW1lIikpCm89ci5xKHMsInN1YnRyZWUiKQpvPW89PW51bGw/bnVs
+bDpMLm1LKG8pCkMuTm0uaShuLG5ldyBMLlpaKHEscCxvLEguYyhyLnEocywicGF0aCIpKSxILmMoci5x
+KHMsImhyZWYiKSksSC5XWShyLnEocywiZWRpdENvdW50IikpKSl9cmV0dXJuIG59LApWRDpmdW5jdGlv
+bihhKXt2YXIgdCxzLHI9SC5WTShbXSx1LkopCmZvcih0PWEubGVuZ3RoLHM9MDtzPGEubGVuZ3RoO2Eu
+bGVuZ3RoPT09dHx8KDAsSC5saykoYSksKytzKUMuTm0uaShyLGFbc10uTHQoKSkKcmV0dXJuIHJ9LApw
+MjpmdW5jdGlvbihhKXtzd2l0Y2goYSl7Y2FzZSJkaXJlY3RvcnkiOnJldHVybiBDLlkyCmNhc2UiZmls
+ZSI6cmV0dXJuIEMucmYKZGVmYXVsdDp0aHJvdyBILmIoUC5QVigiVW5yZWNvZ25pemVkIG5hdmlnYXRp
+b24gdHJlZSBub2RlIHR5cGU6ICIrSC5kKGEpKSl9fSwKdnk6ZnVuY3Rpb24oYSl7c3dpdGNoKGEpe2Nh
+c2UgQy5ZMjpyZXR1cm4iZGlyZWN0b3J5IgpjYXNlIEMucmY6cmV0dXJuImZpbGUifXRocm93IEguYihQ
+LlBWKCJVbnJlY29nbml6ZWQgbmF2aWdhdGlvbiB0cmVlIG5vZGUgdHlwZTogIithLlooMCkpKX0sClpa
+OmZ1bmN0aW9uIFpaKGEsYixjLGQsZSxmKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uYz1jCl8uZD1k
+Cl8uZT1lCl8uZj1mfSwKTzk6ZnVuY3Rpb24gTzkoYSl7dGhpcy5iPWF9LApJVjpmdW5jdGlvbiBJVihh
+LGIsYyxkKXt2YXIgXz10aGlzCl8uZD1hCl8uZT1iCl8uZj1jCl8ucj1kfX0sWD17CkNMOmZ1bmN0aW9u
+KGEsYil7dmFyIHQscyxyLHEscCxvPWIueFooYSkKYi5oSyhhKQppZihvIT1udWxsKWE9Si5LVihhLG8u
+bGVuZ3RoKQp0PXUucwpzPUguVk0oW10sdCkKcj1ILlZNKFtdLHQpCnQ9YS5sZW5ndGgKaWYodCE9PTAm
+JmIucjQoQy54Qi5XKGEsMCkpKXtpZigwPj10KXJldHVybiBILmsoYSwwKQpDLk5tLmkocixhWzBdKQpx
+PTF9ZWxzZXtDLk5tLmkociwiIikKcT0wfWZvcihwPXE7cDx0OysrcClpZihiLnI0KEMueEIuVyhhLHAp
+KSl7Qy5ObS5pKHMsQy54Qi5OaihhLHEscCkpCkMuTm0uaShyLGFbcF0pCnE9cCsxfWlmKHE8dCl7Qy5O
+bS5pKHMsQy54Qi5HKGEscSkpCkMuTm0uaShyLCIiKX1yZXR1cm4gbmV3IFguV0QoYixvLHMscil9LApX
+RDpmdW5jdGlvbiBXRChhLGIsYyxkKXt2YXIgXz10aGlzCl8uYT1hCl8uYj1iCl8uZD1jCl8uZT1kfSwK
+STc6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBYLmR2KGEpfSwKZHY6ZnVuY3Rpb24gZHYoYSl7dGhpcy5h
+PWF9fSxPPXsKUmg6ZnVuY3Rpb24oKXt2YXIgdCxzPW51bGwKaWYoUC51bygpLmdGaSgpIT09ImZpbGUi
+KXJldHVybiAkLkViKCkKdD1QLnVvKCkKaWYoIUMueEIuVGModC5nSWkodCksIi8iKSlyZXR1cm4gJC5F
+YigpCmlmKFAuS0wocywiYS9iIixzLHMscyxzLHMpLnQ0KCk9PT0iYVxcYiIpcmV0dXJuICQuS2soKQpy
+ZXR1cm4gJC5iRCgpfSwKekw6ZnVuY3Rpb24gekwoKXt9fSxFPXtPRjpmdW5jdGlvbiBPRihhLGIsYyl7
+dGhpcy5kPWEKdGhpcy5lPWIKdGhpcy5mPWN9fSxGPXtydTpmdW5jdGlvbiBydShhLGIsYyxkKXt2YXIg
+Xz10aGlzCl8uZD1hCl8uZT1iCl8uZj1jCl8ucj1kfX0sRD17ClJYOmZ1bmN0aW9uKCl7dmFyIHQscyxy
+LHEscD1udWxsCnRyeXtwPVAudW8oKX1jYXRjaCh0KXtpZih1Lmc4LmIoSC5SdSh0KSkpe3M9JC5GZgpp
+ZihzIT1udWxsKXJldHVybiBzCnRocm93IHR9ZWxzZSB0aHJvdyB0fWlmKEouUk0ocCwkLkk2KSlyZXR1
+cm4gJC5GZgokLkk2PXAKaWYoJC5IaygpPT0kLkViKCkpcz0kLkZmPXAuWkkoIi4iKS5aKDApCmVsc2V7
+cj1wLnQ0KCkKcT1yLmxlbmd0aC0xCnM9JC5GZj1xPT09MD9yOkMueEIuTmoociwwLHEpfXJldHVybiBz
+fX0KdmFyIHc9W0MsSCxKLFAsVyxNLFUsQixULEwsWCxPLEUsRixEXQpodW5rSGVscGVycy5zZXRGdW5j
+dGlvbk5hbWVzSWZOZWNlc3NhcnkodykKdmFyICQ9e30KSC5GSy5wcm90b3R5cGU9e30KSi52Qi5wcm90
+b3R5cGU9ewpETjpmdW5jdGlvbihhLGIpe3JldHVybiBhPT09Yn0sCmdpTzpmdW5jdGlvbihhKXtyZXR1
+cm4gSC5lUShhKX0sClo6ZnVuY3Rpb24oYSl7cmV0dXJuIkluc3RhbmNlIG9mICciK0guZChILmxoKGEp
+KSsiJyJ9LAplNzpmdW5jdGlvbihhLGIpe3Uuby5hKGIpCnRocm93IEguYihQLmxyKGEsYi5nV2EoKSxi
+LmduZCgpLGIuZ1ZtKCkpKX19CkoueUUucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4gU3Ry
+aW5nKGEpfSwKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiBhPzUxOTAxODoyMTgxNTl9LAokaWEyOjF9Ckou
+WUUucHJvdG90eXBlPXsKRE46ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbnVsbD09Yn0sClo6ZnVuY3Rpb24o
+YSl7cmV0dXJuIm51bGwifSwKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiAwfSwKZTc6ZnVuY3Rpb24oYSxi
+KXtyZXR1cm4gdGhpcy5TaihhLHUuby5hKGIpKX0sCiRpYzg6MX0KSi5NRi5wcm90b3R5cGU9ewpnaU86
+ZnVuY3Rpb24oYSl7cmV0dXJuIDB9LApaOmZ1bmN0aW9uKGEpe3JldHVybiBTdHJpbmcoYSl9LAokaXZt
+OjF9CkouaUMucHJvdG90eXBlPXt9Ckoua2QucHJvdG90eXBlPXt9CkouYzUucHJvdG90eXBlPXsKWjpm
+dW5jdGlvbihhKXt2YXIgdD1hWyQud1EoKV0KaWYodD09bnVsbClyZXR1cm4gdGhpcy50KGEpCnJldHVy
+biJKYXZhU2NyaXB0IGZ1bmN0aW9uIGZvciAiK0guZChKLkFjKHQpKX0sCiRTOmZ1bmN0aW9uKCl7cmV0
+dXJue2Z1bmM6MSxvcHQ6WywsLCwsLCwsLCwsLCwsLCxdfX0sCiRpRUg6MX0KSi5qZC5wcm90b3R5cGU9
+ewppOmZ1bmN0aW9uKGEsYil7SC50NihhKS5jLmEoYikKaWYoISFhLmZpeGVkJGxlbmd0aClILnZoKFAu
+TDQoImFkZCIpKQphLnB1c2goYil9LApXNDpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKCEhYS5maXhlZCRs
+ZW5ndGgpSC52aChQLkw0KCJyZW1vdmVBdCIpKQp0PWEubGVuZ3RoCmlmKGI+PXQpdGhyb3cgSC5iKFAu
+TzcoYixudWxsKSkKcmV0dXJuIGEuc3BsaWNlKGIsMSlbMF19LApVRzpmdW5jdGlvbihhLGIsYyl7dmFy
+IHQscyxyCkgudDYoYSkuQygiY1g8MT4iKS5hKGMpCmlmKCEhYS5maXhlZCRsZW5ndGgpSC52aChQLkw0
+KCJpbnNlcnRBbGwiKSkKdD1hLmxlbmd0aApQLndBKGIsMCx0LCJpbmRleCIpCnM9Yy5sZW5ndGgKdGhp
+cy5zQShhLHQrcykKcj1iK3MKdGhpcy5ZVyhhLHIsYS5sZW5ndGgsYSxiKQp0aGlzLnZnKGEsYixyLGMp
+fSwKbXY6ZnVuY3Rpb24oYSl7aWYoISFhLmZpeGVkJGxlbmd0aClILnZoKFAuTDQoInJlbW92ZUxhc3Qi
+KSkKaWYoYS5sZW5ndGg9PT0wKXRocm93IEguYihILkhZKGEsLTEpKQpyZXR1cm4gYS5wb3AoKX0sCkZW
+OmZ1bmN0aW9uKGEsYil7dmFyIHQKSC50NihhKS5DKCJjWDwxPiIpLmEoYikKaWYoISFhLmZpeGVkJGxl
+bmd0aClILnZoKFAuTDQoImFkZEFsbCIpKQpmb3IodD1KLklUKGIpO3QuRigpOylhLnB1c2godC5nbCgp
+KX0sCks6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzCkgudDYoYSkuQygifigxKSIpLmEoYikKdD1hLmxlbmd0
+aApmb3Iocz0wO3M8dDsrK3Mpe2IuJDEoYVtzXSkKaWYoYS5sZW5ndGghPT10KXRocm93IEguYihQLmE0
+KGEpKX19LApFMjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC50NihhKQpyZXR1cm4gbmV3IEgubEooYSx0
+LktxKGMpLkMoIjEoMikiKS5hKGIpLHQuQygiQDwxPiIpLktxKGMpLkMoImxKPDEsMj4iKSl9LApIOmZ1
+bmN0aW9uKGEsYil7dmFyIHQscz1uZXcgQXJyYXkoYS5sZW5ndGgpCnMuZml4ZWQkbGVuZ3RoPUFycmF5
+CmZvcih0PTA7dDxhLmxlbmd0aDsrK3QpdGhpcy5ZKHMsdCxILmQoYVt0XSkpCnJldHVybiBzLmpvaW4o
+Yil9LApOMDpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIKZC5hKGIpCkgudDYoYSkuS3EoZCkuQygi
+MSgxLDIpIikuYShjKQp0PWEubGVuZ3RoCmZvcihzPWIscj0wO3I8dDsrK3Ipe3M9Yy4kMihzLGFbcl0p
+CmlmKGEubGVuZ3RoIT09dCl0aHJvdyBILmIoUC5hNChhKSl9cmV0dXJuIHN9LApIdDpmdW5jdGlvbihh
+LGIpe3ZhciB0LHMscixxLHAsbz1ILnQ2KGEpCm8uQygiYTIoMSkiKS5hKGIpCm8uQygiMSgpIikuYShu
+dWxsKQp0PWEubGVuZ3RoCmZvcihzPW51bGwscj0hMSxxPTA7cTx0OysrcSl7cD1hW3FdCmlmKEgub1Qo
+Yi4kMShwKSkpe2lmKHIpdGhyb3cgSC5iKEguZFUoKSkKcz1wCnI9ITB9aWYodCE9PWEubGVuZ3RoKXRo
+cm93IEguYihQLmE0KGEpKX1pZihyKXJldHVybiBzCnRocm93IEguYihILldwKCkpfSwKRTpmdW5jdGlv
+bihhLGIpe2lmKGI8MHx8Yj49YS5sZW5ndGgpcmV0dXJuIEguayhhLGIpCnJldHVybiBhW2JdfSwKRDY6
+ZnVuY3Rpb24oYSxiLGMpe2lmKGI8MHx8Yj5hLmxlbmd0aCl0aHJvdyBILmIoUC5URShiLDAsYS5sZW5n
+dGgsInN0YXJ0IixudWxsKSkKaWYoYzxifHxjPmEubGVuZ3RoKXRocm93IEguYihQLlRFKGMsYixhLmxl
+bmd0aCwiZW5kIixudWxsKSkKaWYoYj09PWMpcmV0dXJuIEguVk0oW10sSC50NihhKSkKcmV0dXJuIEgu
+Vk0oYS5zbGljZShiLGMpLEgudDYoYSkpfSwKZ3RIOmZ1bmN0aW9uKGEpe2lmKGEubGVuZ3RoPjApcmV0
+dXJuIGFbMF0KdGhyb3cgSC5iKEguV3AoKSl9LApnclo6ZnVuY3Rpb24oYSl7dmFyIHQ9YS5sZW5ndGgK
+aWYodD4wKXJldHVybiBhW3QtMV0KdGhyb3cgSC5iKEguV3AoKSl9LApZVzpmdW5jdGlvbihhLGIsYyxk
+LGUpe3ZhciB0LHMscj1ILnQ2KGEpCnIuQygiY1g8MT4iKS5hKGQpCmlmKCEhYS5pbW11dGFibGUkbGlz
+dClILnZoKFAuTDQoInNldFJhbmdlIikpClAuakIoYixjLGEubGVuZ3RoKQp0PWMtYgppZih0PT09MCly
+ZXR1cm4KUC5rMShlLCJza2lwQ291bnQiKQpyLkMoInpNPDE+IikuYShkKQpyPUouVTYoZCkKaWYoZSt0
+PnIuZ0EoZCkpdGhyb3cgSC5iKEguYXIoKSkKaWYoZTxiKWZvcihzPXQtMTtzPj0wOy0tcylhW2Irc109
+ci5xKGQsZStzKQplbHNlIGZvcihzPTA7czx0OysrcylhW2Irc109ci5xKGQsZStzKX0sCnZnOmZ1bmN0
+aW9uKGEsYixjLGQpe3JldHVybiB0aGlzLllXKGEsYixjLGQsMCl9LApWcjpmdW5jdGlvbihhLGIpe3Zh
+ciB0LHMKSC50NihhKS5DKCJhMigxKSIpLmEoYikKdD1hLmxlbmd0aApmb3Iocz0wO3M8dDsrK3Mpe2lm
+KEgub1QoYi4kMShhW3NdKSkpcmV0dXJuITAKaWYoYS5sZW5ndGghPT10KXRocm93IEguYihQLmE0KGEp
+KX1yZXR1cm4hMX0sCnRnOmZ1bmN0aW9uKGEsYil7dmFyIHQKZm9yKHQ9MDt0PGEubGVuZ3RoOysrdClp
+ZihKLlJNKGFbdF0sYikpcmV0dXJuITAKcmV0dXJuITF9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIGEu
+bGVuZ3RoPT09MH0sCmdvcjpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGghPT0wfSwKWjpmdW5jdGlv
+bihhKXtyZXR1cm4gUC5XRShhLCJbIiwiXSIpfSwKZ2t6OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgSi5t
+MShhLGEubGVuZ3RoLEgudDYoYSkuQygibTE8MT4iKSl9LApnaU86ZnVuY3Rpb24oYSl7cmV0dXJuIEgu
+ZVEoYSl9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApzQTpmdW5jdGlvbihhLGIpe2lm
+KCEhYS5maXhlZCRsZW5ndGgpSC52aChQLkw0KCJzZXQgbGVuZ3RoIikpCmlmKGI8MCl0aHJvdyBILmIo
+UC5URShiLDAsbnVsbCwibmV3TGVuZ3RoIixudWxsKSkKYS5sZW5ndGg9Yn0sCnE6ZnVuY3Rpb24oYSxi
+KXtILldZKGIpCmlmKGI+PWEubGVuZ3RofHxiPDApdGhyb3cgSC5iKEguSFkoYSxiKSkKcmV0dXJuIGFb
+Yl19LApZOmZ1bmN0aW9uKGEsYixjKXtILnQ2KGEpLmMuYShjKQppZighIWEuaW1tdXRhYmxlJGxpc3Qp
+SC52aChQLkw0KCJpbmRleGVkIHNldCIpKQppZihiPj1hLmxlbmd0aHx8YjwwKXRocm93IEguYihILkhZ
+KGEsYikpCmFbYl09Y30sCiRpYlE6MSwKJGljWDoxLAokaXpNOjF9CkouUG8ucHJvdG90eXBlPXt9Ckou
+bTEucHJvdG90eXBlPXsKZ2w6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kfSwKRjpmdW5jdGlvbigpe3Zh
+ciB0LHM9dGhpcyxyPXMuYSxxPXIubGVuZ3RoCmlmKHMuYiE9PXEpdGhyb3cgSC5iKEgubGsocikpCnQ9
+cy5jCmlmKHQ+PXEpe3Muc00obnVsbCkKcmV0dXJuITF9cy5zTShyW3RdKTsrK3MuYwpyZXR1cm4hMH0s
+CnNNOmZ1bmN0aW9uKGEpe3RoaXMuZD10aGlzLiR0aS5jLmEoYSl9LAokaUFuOjF9CkoucUkucHJvdG90
+eXBlPXsKeXU6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoYT49LTIxNDc0ODM2NDgmJmE8PTIxNDc0ODM2NDcp
+cmV0dXJuIGF8MAppZihpc0Zpbml0ZShhKSl7dD1hPDA/TWF0aC5jZWlsKGEpOk1hdGguZmxvb3IoYSkK
+cmV0dXJuIHQrMH10aHJvdyBILmIoUC5MNCgiIithKyIudG9JbnQoKSIpKX0sCnpROmZ1bmN0aW9uKGEp
+e2lmKGE+MCl7aWYoYSE9PTEvMClyZXR1cm4gTWF0aC5yb3VuZChhKX1lbHNlIGlmKGE+LTEvMClyZXR1
+cm4gMC1NYXRoLnJvdW5kKDAtYSkKdGhyb3cgSC5iKFAuTDQoIiIrYSsiLnJvdW5kKCkiKSl9LApXWjpm
+dW5jdGlvbihhLGIpe3ZhciB0LHMscixxCmlmKGI8Mnx8Yj4zNil0aHJvdyBILmIoUC5URShiLDIsMzYs
+InJhZGl4IixudWxsKSkKdD1hLnRvU3RyaW5nKGIpCmlmKEMueEIubSh0LHQubGVuZ3RoLTEpIT09NDEp
+cmV0dXJuIHQKcz0vXihbXGRhLXpdKykoPzpcLihbXGRhLXpdKykpP1woZVwrKFxkKylcKSQvLmV4ZWMo
+dCkKaWYocz09bnVsbClILnZoKFAuTDQoIlVuZXhwZWN0ZWQgdG9TdHJpbmcgcmVzdWx0OiAiK3QpKQpy
+PXMubGVuZ3RoCmlmKDE+PXIpcmV0dXJuIEguayhzLDEpCnQ9c1sxXQppZigzPj1yKXJldHVybiBILmso
+cywzKQpxPStzWzNdCnI9c1syXQppZihyIT1udWxsKXt0Kz1yCnEtPXIubGVuZ3RofXJldHVybiB0K0Mu
+eEIuSXgoIjAiLHEpfSwKWjpmdW5jdGlvbihhKXtpZihhPT09MCYmMS9hPDApcmV0dXJuIi0wLjAiCmVs
+c2UgcmV0dXJuIiIrYX0sCmdpTzpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwPWF8MAppZihhPT09cCly
+ZXR1cm4gNTM2ODcwOTExJnAKdD1NYXRoLmFicyhhKQpzPU1hdGgubG9nKHQpLzAuNjkzMTQ3MTgwNTU5
+OTQ1M3wwCnI9TWF0aC5wb3coMixzKQpxPXQ8MT90L3I6ci90CnJldHVybiA1MzY4NzA5MTEmKChxKjkw
+MDcxOTkyNTQ3NDA5OTJ8MCkrKHEqMzU0MjI0MzE4MTE3NjUyMXwwKSkqNTk5MTk3K3MqMTI1OX0sCnpZ
+OmZ1bmN0aW9uKGEsYil7dmFyIHQ9YSViCmlmKHQ9PT0wKXJldHVybiAwCmlmKHQ+MClyZXR1cm4gdApp
+ZihiPDApcmV0dXJuIHQtYgplbHNlIHJldHVybiB0K2J9LAp3RzpmdW5jdGlvbihhLGIpe3ZhciB0Cmlm
+KGE+MCl0PXRoaXMucDMoYSxiKQplbHNle3Q9Yj4zMT8zMTpiCnQ9YT4+dD4+PjB9cmV0dXJuIHR9LApi
+ZjpmdW5jdGlvbihhLGIpe2lmKGI8MCl0aHJvdyBILmIoSC5JKGIpKQpyZXR1cm4gdGhpcy5wMyhhLGIp
+fSwKcDM6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYj4zMT8wOmE+Pj5ifSwKJGlDUDoxLAokaWxmOjF9Ckou
+YlUucHJvdG90eXBlPXskaUlmOjF9CkouVkEucHJvdG90eXBlPXt9CkouRHIucHJvdG90eXBlPXsKbTpm
+dW5jdGlvbihhLGIpe2lmKGI8MCl0aHJvdyBILmIoSC5IWShhLGIpKQppZihiPj1hLmxlbmd0aClILnZo
+KEguSFkoYSxiKSkKcmV0dXJuIGEuY2hhckNvZGVBdChiKX0sClc6ZnVuY3Rpb24oYSxiKXtpZihiPj1h
+Lmxlbmd0aCl0aHJvdyBILmIoSC5IWShhLGIpKQpyZXR1cm4gYS5jaGFyQ29kZUF0KGIpfSwKZGQ6ZnVu
+Y3Rpb24oYSxiKXtyZXR1cm4gbmV3IEguTkYoYixhLDApfSwKaDpmdW5jdGlvbihhLGIpe2lmKHR5cGVv
+ZiBiIT0ic3RyaW5nIil0aHJvdyBILmIoUC5MMyhiLG51bGwsbnVsbCkpCnJldHVybiBhK2J9LApUYzpm
+dW5jdGlvbihhLGIpe3ZhciB0PWIubGVuZ3RoLHM9YS5sZW5ndGgKaWYodD5zKXJldHVybiExCnJldHVy
+biBiPT09dGhpcy5HKGEscy10KX0sCmk3OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMKYz1QLmpCKGIs
+YyxhLmxlbmd0aCkKdD1hLnN1YnN0cmluZygwLGIpCnM9YS5zdWJzdHJpbmcoYykKcmV0dXJuIHQrZCtz
+fSwKUWk6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0CmlmKCFILm9rKGMpKUgudmgoSC5JKGMpKQppZih0eXBl
+b2YgYyE9PSJudW1iZXIiKXJldHVybiBjLkooKQppZihjPDB8fGM+YS5sZW5ndGgpdGhyb3cgSC5iKFAu
+VEUoYywwLGEubGVuZ3RoLG51bGwsbnVsbCkpCnQ9YytiLmxlbmd0aAppZih0PmEubGVuZ3RoKXJldHVy
+biExCnJldHVybiBiPT09YS5zdWJzdHJpbmcoYyx0KX0sCm46ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhp
+cy5RaShhLGIsMCl9LApOajpmdW5jdGlvbihhLGIsYyl7aWYoIUgub2soYikpSC52aChILkkoYikpCmlm
+KGM9PW51bGwpYz1hLmxlbmd0aAppZih0eXBlb2YgYiE9PSJudW1iZXIiKXJldHVybiBiLkooKQppZihi
+PDApdGhyb3cgSC5iKFAuTzcoYixudWxsKSkKaWYoYj5jKXRocm93IEguYihQLk83KGIsbnVsbCkpCmlm
+KGM+YS5sZW5ndGgpdGhyb3cgSC5iKFAuTzcoYyxudWxsKSkKcmV0dXJuIGEuc3Vic3RyaW5nKGIsYyl9
+LApHOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuTmooYSxiLG51bGwpfSwKaGM6ZnVuY3Rpb24oYSl7
+cmV0dXJuIGEudG9Mb3dlckNhc2UoKX0sCmJTOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPWEudHJpbSgp
+LHA9cS5sZW5ndGgKaWYocD09PTApcmV0dXJuIHEKaWYodGhpcy5XKHEsMCk9PT0xMzMpe3Q9Si5tbShx
+LDEpCmlmKHQ9PT1wKXJldHVybiIifWVsc2UgdD0wCnM9cC0xCnI9dGhpcy5tKHEscyk9PT0xMzM/Si5j
+MShxLHMpOnAKaWYodD09PTAmJnI9PT1wKXJldHVybiBxCnJldHVybiBxLnN1YnN0cmluZyh0LHIpfSwK
+SXg6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzCmlmKDA+PWIpcmV0dXJuIiIKaWYoYj09PTF8fGEubGVuZ3Ro
+PT09MClyZXR1cm4gYQppZihiIT09Yj4+PjApdGhyb3cgSC5iKEMuRXEpCmZvcih0PWEscz0iIjshMDsp
+e2lmKChiJjEpPT09MSlzPXQrcwpiPWI+Pj4xCmlmKGI9PT0wKWJyZWFrCnQrPXR9cmV0dXJuIHN9LApY
+VTpmdW5jdGlvbihhLGIsYyl7dmFyIHQKaWYoYzwwfHxjPmEubGVuZ3RoKXRocm93IEguYihQLlRFKGMs
+MCxhLmxlbmd0aCxudWxsLG51bGwpKQp0PWEuaW5kZXhPZihiLGMpCnJldHVybiB0fSwKT1k6ZnVuY3Rp
+b24oYSxiKXtyZXR1cm4gdGhpcy5YVShhLGIsMCl9LApQazpmdW5jdGlvbihhLGIsYyl7dmFyIHQscwpp
+ZihjPT1udWxsKWM9YS5sZW5ndGgKZWxzZSBpZihjPDB8fGM+YS5sZW5ndGgpdGhyb3cgSC5iKFAuVEUo
+YywwLGEubGVuZ3RoLG51bGwsbnVsbCkpCnQ9Yi5sZW5ndGgKcz1hLmxlbmd0aAppZihjK3Q+cyljPXMt
+dApyZXR1cm4gYS5sYXN0SW5kZXhPZihiLGMpfSwKY246ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5Q
+ayhhLGIsbnVsbCl9LApJczpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9YS5sZW5ndGgKaWYoYz50KXRocm93
+IEguYihQLlRFKGMsMCx0LG51bGwsbnVsbCkpCnJldHVybiBILm0yKGEsYixjKX0sCnRnOmZ1bmN0aW9u
+KGEsYil7cmV0dXJuIHRoaXMuSXMoYSxiLDApfSwKWjpmdW5jdGlvbihhKXtyZXR1cm4gYX0sCmdpTzpm
+dW5jdGlvbihhKXt2YXIgdCxzLHIKZm9yKHQ9YS5sZW5ndGgscz0wLHI9MDtyPHQ7KytyKXtzPTUzNjg3
+MDkxMSZzK2EuY2hhckNvZGVBdChyKQpzPTUzNjg3MDkxMSZzKygoNTI0Mjg3JnMpPDwxMCkKc149cz4+
+Nn1zPTUzNjg3MDkxMSZzKygoNjcxMDg4NjMmcyk8PDMpCnNePXM+PjExCnJldHVybiA1MzY4NzA5MTEm
+cysoKDE2MzgzJnMpPDwxNSl9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApxOmZ1bmN0
+aW9uKGEsYil7SC5XWShiKQppZihiPj1hLmxlbmd0aHx8ITEpdGhyb3cgSC5iKEguSFkoYSxiKSkKcmV0
+dXJuIGFbYl19LAokaXZYOjEsCiRpcVU6MX0KSC5xai5wcm90b3R5cGU9ewpnQTpmdW5jdGlvbihhKXty
+ZXR1cm4gdGhpcy5hLmxlbmd0aH0sCnE6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gQy54Qi5tKHRoaXMuYSxI
+LldZKGIpKX19CkguYlEucHJvdG90eXBlPXt9CkguYUwucHJvdG90eXBlPXsKZ2t6OmZ1bmN0aW9uKGEp
+e3ZhciB0PXRoaXMKcmV0dXJuIG5ldyBILmE3KHQsdC5nQSh0KSxILkxoKHQpLkMoImE3PGFMLkU+Iikp
+fSwKZ2wwOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmdBKHRoaXMpPT09MH0sCkg6ZnVuY3Rpb24oYSxi
+KXt2YXIgdCxzLHIscT10aGlzLHA9cS5nQShxKQppZihiLmxlbmd0aCE9PTApe2lmKHA9PT0wKXJldHVy
+biIiCnQ9SC5kKHEuRSgwLDApKQppZihwIT09cS5nQShxKSl0aHJvdyBILmIoUC5hNChxKSkKZm9yKHM9
+dCxyPTE7cjxwOysrcil7cz1zK2IrSC5kKHEuRSgwLHIpKQppZihwIT09cS5nQShxKSl0aHJvdyBILmIo
+UC5hNChxKSl9cmV0dXJuIHMuY2hhckNvZGVBdCgwKT09MD9zOnN9ZWxzZXtmb3Iocj0wLHM9IiI7cjxw
+Oysrcil7cys9SC5kKHEuRSgwLHIpKQppZihwIT09cS5nQShxKSl0aHJvdyBILmIoUC5hNChxKSl9cmV0
+dXJuIHMuY2hhckNvZGVBdCgwKT09MD9zOnN9fSwKZXY6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5H
+RygwLEguTGgodGhpcykuQygiYTIoYUwuRSkiKS5hKGIpKX0sCkUyOmZ1bmN0aW9uKGEsYixjKXt2YXIg
+dD1ILkxoKHRoaXMpCnJldHVybiBuZXcgSC5sSih0aGlzLHQuS3EoYykuQygiMShhTC5FKSIpLmEoYiks
+dC5DKCJAPGFMLkU+IikuS3EoYykuQygibEo8MSwyPiIpKX0sCnR0OmZ1bmN0aW9uKGEsYil7dmFyIHQs
+cz10aGlzLHI9SC5WTShbXSxILkxoKHMpLkMoImpkPGFMLkU+IikpCkMuTm0uc0EocixzLmdBKHMpKQpm
+b3IodD0wO3Q8cy5nQShzKTsrK3QpQy5ObS5ZKHIsdCxzLkUoMCx0KSkKcmV0dXJuIHJ9LApicjpmdW5j
+dGlvbihhKXtyZXR1cm4gdGhpcy50dChhLCEwKX19CkgubkgucHJvdG90eXBlPXsKZ1VEOmZ1bmN0aW9u
+KCl7dmFyIHQ9Si5IKHRoaXMuYSkscz10aGlzLmMKaWYocz09bnVsbHx8cz50KXJldHVybiB0CnJldHVy
+biBzfSwKZ0FzOmZ1bmN0aW9uKCl7dmFyIHQ9Si5IKHRoaXMuYSkscz10aGlzLmIKaWYocz50KXJldHVy
+biB0CnJldHVybiBzfSwKZ0E6ZnVuY3Rpb24oYSl7dmFyIHQscz1KLkgodGhpcy5hKSxyPXRoaXMuYgpp
+ZihyPj1zKXJldHVybiAwCnQ9dGhpcy5jCmlmKHQ9PW51bGx8fHQ+PXMpcmV0dXJuIHMtcgppZih0eXBl
+b2YgdCE9PSJudW1iZXIiKXJldHVybiB0LkhOKCkKcmV0dXJuIHQtcn0sCkU6ZnVuY3Rpb24oYSxiKXt2
+YXIgdCxzPXRoaXMscj1zLmdBcygpK2IKaWYoYj49MCl7dD1zLmdVRCgpCmlmKHR5cGVvZiB0IT09Im51
+bWJlciIpcmV0dXJuIEgucFkodCkKdD1yPj10fWVsc2UgdD0hMAppZih0KXRocm93IEguYihQLnQoYixz
+LCJpbmRleCIsbnVsbCxudWxsKSkKcmV0dXJuIEouR0Eocy5hLHIpfX0KSC5hNy5wcm90b3R5cGU9ewpn
+bDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmR9LApGOmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzLHI9cy5h
+LHE9Si5VNihyKSxwPXEuZ0EocikKaWYocy5iIT09cCl0aHJvdyBILmIoUC5hNChyKSkKdD1zLmMKaWYo
+dD49cCl7cy5zSShudWxsKQpyZXR1cm4hMX1zLnNJKHEuRShyLHQpKTsrK3MuYwpyZXR1cm4hMH0sCnNJ
+OmZ1bmN0aW9uKGEpe3RoaXMuZD10aGlzLiR0aS5jLmEoYSl9LAokaUFuOjF9CkguaTEucHJvdG90eXBl
+PXsKZ2t6OmZ1bmN0aW9uKGEpe3ZhciB0PUguTGgodGhpcykKcmV0dXJuIG5ldyBILk1IKEouSVQodGhp
+cy5hKSx0aGlzLmIsdC5DKCJAPDE+IikuS3EodC5RWzFdKS5DKCJNSDwxLDI+IikpfSwKZ0E6ZnVuY3Rp
+b24oYSl7cmV0dXJuIEouSCh0aGlzLmEpfX0KSC54eS5wcm90b3R5cGU9eyRpYlE6MX0KSC5NSC5wcm90
+b3R5cGU9ewpGOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQuYgppZihzLkYoKSl7dC5zSSh0LmMuJDEo
+cy5nbCgpKSkKcmV0dXJuITB9dC5zSShudWxsKQpyZXR1cm4hMX0sCmdsOmZ1bmN0aW9uKCl7cmV0dXJu
+IHRoaXMuYX0sCnNJOmZ1bmN0aW9uKGEpe3RoaXMuYT10aGlzLiR0aS5RWzFdLmEoYSl9fQpILmxKLnBy
+b3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiBKLkgodGhpcy5hKX0sCkU6ZnVuY3Rpb24oYSxi
+KXtyZXR1cm4gdGhpcy5iLiQxKEouR0EodGhpcy5hLGIpKX19CkguVTUucHJvdG90eXBlPXsKZ2t6OmZ1
+bmN0aW9uKGEpe3JldHVybiBuZXcgSC52RyhKLklUKHRoaXMuYSksdGhpcy5iLHRoaXMuJHRpLkMoInZH
+PDE+IikpfX0KSC52Ry5wcm90b3R5cGU9ewpGOmZ1bmN0aW9uKCl7dmFyIHQscwpmb3IodD10aGlzLmEs
+cz10aGlzLmI7dC5GKCk7KWlmKEgub1Qocy4kMSh0LmdsKCkpKSlyZXR1cm4hMApyZXR1cm4hMX0sCmds
+OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYS5nbCgpfX0KSC5TVS5wcm90b3R5cGU9e30KSC5SZS5wcm90
+b3R5cGU9ewpZOmZ1bmN0aW9uKGEsYixjKXtILkxoKHRoaXMpLkMoIlJlLkUiKS5hKGMpCnRocm93IEgu
+YihQLkw0KCJDYW5ub3QgbW9kaWZ5IGFuIHVubW9kaWZpYWJsZSBsaXN0IikpfX0KSC53Mi5wcm90b3R5
+cGU9e30KSC53di5wcm90b3R5cGU9ewpnaU86ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5faGFzaENvZGUK
+aWYodCE9bnVsbClyZXR1cm4gdAp0PTUzNjg3MDkxMSY2NjQ1OTcqSi5oZih0aGlzLmEpCnRoaXMuX2hh
+c2hDb2RlPXQKcmV0dXJuIHR9LApaOmZ1bmN0aW9uKGEpe3JldHVybidTeW1ib2woIicrSC5kKHRoaXMu
+YSkrJyIpJ30sCkROOmZ1bmN0aW9uKGEsYil7aWYoYj09bnVsbClyZXR1cm4hMQpyZXR1cm4gYiBpbnN0
+YW5jZW9mIEgud3YmJnRoaXMuYT09Yi5hfSwKJGlHRDoxfQpILlBELnByb3RvdHlwZT17fQpILldVLnBy
+b3RvdHlwZT17CmdsMDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nQSh0aGlzKT09PTB9LApaOmZ1bmN0
+aW9uKGEpe3JldHVybiBQLm5PKHRoaXMpfSwKWTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC5MaCh0aGlz
+KQp0LmMuYShiKQp0LlFbMV0uYShjKQpyZXR1cm4gSC5kYygpfSwKZ1B1OmZ1bmN0aW9uKGEpe3JldHVy
+biB0aGlzLnE0KGEsSC5MaCh0aGlzKS5DKCJOMzwxLDI+IikpfSwKcTQ6ZnVuY3Rpb24oYSxiKXt2YXIg
+dD10aGlzCnJldHVybiBQLmwwKGZ1bmN0aW9uKCl7dmFyIHM9YQp2YXIgcj0wLHE9MSxwLG8sbixtCnJl
+dHVybiBmdW5jdGlvbiAkYXN5bmMkZ1B1KGMsZCl7aWYoYz09PTEpe3A9ZApyPXF9d2hpbGUodHJ1ZSlz
+d2l0Y2gocil7Y2FzZSAwOm89dC5nVigpLG89by5na3oobyksbj1ILkxoKHQpLG49bi5DKCJAPDE+Iiku
+S3Eobi5RWzFdKS5DKCJOMzwxLDI+IikKY2FzZSAyOmlmKCFvLkYoKSl7cj0zCmJyZWFrfW09by5nbCgp
+CnI9NApyZXR1cm4gbmV3IFAuTjMobSx0LnEoMCxtKSxuKQpjYXNlIDQ6cj0yCmJyZWFrCmNhc2UgMzpy
+ZXR1cm4gUC5UaCgpCmNhc2UgMTpyZXR1cm4gUC5ZbShwKX19fSxiKX0sCiRpWjA6MX0KSC5MUC5wcm90
+b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfSwKeDQ6ZnVuY3Rpb24oYSl7aWYodHlw
+ZW9mIGEhPSJzdHJpbmciKXJldHVybiExCmlmKCJfX3Byb3RvX18iPT09YSlyZXR1cm4hMQpyZXR1cm4g
+dGhpcy5iLmhhc093blByb3BlcnR5KGEpfSwKcTpmdW5jdGlvbihhLGIpe2lmKCF0aGlzLng0KGIpKXJl
+dHVybiBudWxsCnJldHVybiB0aGlzLkQoYil9LApEOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmJbSC5j
+KGEpXX0sCks6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwPUguTGgodGhpcykKcC5DKCJ+KDEsMiki
+KS5hKGIpCnQ9dGhpcy5jCmZvcihzPXQubGVuZ3RoLHA9cC5RWzFdLHI9MDtyPHM7KytyKXtxPXRbcl0K
+Yi4kMihxLHAuYSh0aGlzLkQocSkpKX19LApnVjpmdW5jdGlvbigpe3JldHVybiBuZXcgSC5YUih0aGlz
+LEguTGgodGhpcykuQygiWFI8MT4iKSl9fQpILlhSLnByb3RvdHlwZT17CmdrejpmdW5jdGlvbihhKXt2
+YXIgdD10aGlzLmEuYwpyZXR1cm4gbmV3IEoubTEodCx0Lmxlbmd0aCxILnQ2KHQpLkMoIm0xPDE+Iikp
+fSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5jLmxlbmd0aH19CkguTEkucHJvdG90eXBlPXsK
+Z1dhOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5hCnJldHVybiB0fSwKZ25kOmZ1bmN0aW9uKCl7dmFyIHQs
+cyxyLHEscD10aGlzCmlmKHAuYz09PTEpcmV0dXJuIEMuaFUKdD1wLmQKcz10Lmxlbmd0aC1wLmUubGVu
+Z3RoLXAuZgppZihzPT09MClyZXR1cm4gQy5oVQpyPVtdCmZvcihxPTA7cTxzOysrcSl7aWYocT49dC5s
+ZW5ndGgpcmV0dXJuIEguayh0LHEpCnIucHVzaCh0W3FdKX1yZXR1cm4gSi51bihyKX0sCmdWbTpmdW5j
+dGlvbigpe3ZhciB0LHMscixxLHAsbyxuLG0sbD10aGlzCmlmKGwuYyE9PTApcmV0dXJuIEMuRHgKdD1s
+LmUKcz10Lmxlbmd0aApyPWwuZApxPXIubGVuZ3RoLXMtbC5mCmlmKHM9PT0wKXJldHVybiBDLkR4CnA9
+bmV3IEguTjUodS5lbykKZm9yKG89MDtvPHM7KytvKXtpZihvPj10Lmxlbmd0aClyZXR1cm4gSC5rKHQs
+bykKbj10W29dCm09cStvCmlmKG08MHx8bT49ci5sZW5ndGgpcmV0dXJuIEguayhyLG0pCnAuWSgwLG5l
+dyBILnd2KG4pLHJbbV0pfXJldHVybiBuZXcgSC5QRChwLHUuZ0YpfSwKJGl2UToxfQpILkNqLnByb3Rv
+dHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7dmFyIHQKSC5jKGEpCnQ9dGhpcy5hCnQuYj10LmIrIiQiK0gu
+ZChhKQpDLk5tLmkodGhpcy5iLGEpCkMuTm0uaSh0aGlzLmMsYik7Kyt0LmF9LAokUzoxMn0KSC5mOS5w
+cm90b3R5cGU9ewpxUzpmdW5jdGlvbihhKXt2YXIgdCxzLHI9dGhpcyxxPW5ldyBSZWdFeHAoci5hKS5l
+eGVjKGEpCmlmKHE9PW51bGwpcmV0dXJuIG51bGwKdD1PYmplY3QuY3JlYXRlKG51bGwpCnM9ci5iCmlm
+KHMhPT0tMSl0LmFyZ3VtZW50cz1xW3MrMV0Kcz1yLmMKaWYocyE9PS0xKXQuYXJndW1lbnRzRXhwcj1x
+W3MrMV0Kcz1yLmQKaWYocyE9PS0xKXQuZXhwcj1xW3MrMV0Kcz1yLmUKaWYocyE9PS0xKXQubWV0aG9k
+PXFbcysxXQpzPXIuZgppZihzIT09LTEpdC5yZWNlaXZlcj1xW3MrMV0KcmV0dXJuIHR9fQpILlcwLnBy
+b3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5iCmlmKHQ9PW51bGwpcmV0dXJuIk5vU3Vj
+aE1ldGhvZEVycm9yOiAiK0guZCh0aGlzLmEpCnJldHVybiJOb1N1Y2hNZXRob2RFcnJvcjogbWV0aG9k
+IG5vdCBmb3VuZDogJyIrdCsiJyBvbiBudWxsIn19CkguYXoucHJvdG90eXBlPXsKWjpmdW5jdGlvbihh
+KXt2YXIgdCxzPXRoaXMscj0iTm9TdWNoTWV0aG9kRXJyb3I6IG1ldGhvZCBub3QgZm91bmQ6ICciLHE9
+cy5iCmlmKHE9PW51bGwpcmV0dXJuIk5vU3VjaE1ldGhvZEVycm9yOiAiK0guZChzLmEpCnQ9cy5jCmlm
+KHQ9PW51bGwpcmV0dXJuIHIrcSsiJyAoIitILmQocy5hKSsiKSIKcmV0dXJuIHIrcSsiJyBvbiAnIit0
+KyInICgiK0guZChzLmEpKyIpIn19CkgudlYucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXt2YXIgdD10
+aGlzLmEKcmV0dXJuIHQubGVuZ3RoPT09MD8iRXJyb3IiOiJFcnJvcjogIit0fX0KSC5icS5wcm90b3R5
+cGU9e30KSC5BbS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtpZih1LlcuYihhKSlpZihhLiR0aHJv
+d25Kc0Vycm9yPT1udWxsKWEuJHRocm93bkpzRXJyb3I9dGhpcy5hCnJldHVybiBhfSwKJFM6MX0KSC5Y
+Ty5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3ZhciB0LHM9dGhpcy5iCmlmKHMhPW51bGwpcmV0dXJu
+IHMKcz10aGlzLmEKdD1zIT09bnVsbCYmdHlwZW9mIHM9PT0ib2JqZWN0Ij9zLnN0YWNrOm51bGwKcmV0
+dXJuIHRoaXMuYj10PT1udWxsPyIiOnR9LAokaUd6OjF9CkguVHAucHJvdG90eXBlPXsKWjpmdW5jdGlv
+bihhKXt2YXIgdD10aGlzLmNvbnN0cnVjdG9yLHM9dD09bnVsbD9udWxsOnQubmFtZQpyZXR1cm4iQ2xv
+c3VyZSAnIitILk5RKHM9PW51bGw/InVua25vd24iOnMpKyInIn0sCiRpRUg6MSwKZ1FsOmZ1bmN0aW9u
+KCl7cmV0dXJuIHRoaXN9LAokQzoiJDEiLAokUjoxLAokRDpudWxsfQpILmxjLnByb3RvdHlwZT17fQpI
+Lnp4LnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy4kc3RhdGljX25hbWUKaWYodD09
+bnVsbClyZXR1cm4iQ2xvc3VyZSBvZiB1bmtub3duIHN0YXRpYyBtZXRob2QiCnJldHVybiJDbG9zdXJl
+ICciK0guTlEodCkrIicifX0KSC5qeS5wcm90b3R5cGU9ewpETjpmdW5jdGlvbihhLGIpe3ZhciB0PXRo
+aXMKaWYoYj09bnVsbClyZXR1cm4hMQppZih0PT09YilyZXR1cm4hMAppZighKGIgaW5zdGFuY2VvZiBI
+Lmp5KSlyZXR1cm4hMQpyZXR1cm4gdC5hPT09Yi5hJiZ0LmI9PT1iLmImJnQuYz09PWIuY30sCmdpTzpm
+dW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuYwppZihzPT1udWxsKXQ9SC5lUSh0aGlzLmEpCmVsc2UgdD10
+eXBlb2YgcyE9PSJvYmplY3QiP0ouaGYocyk6SC5lUShzKQpyZXR1cm4odF5ILmVRKHRoaXMuYikpPj4+
+MH0sClo6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5jCmlmKHQ9PW51bGwpdD10aGlzLmEKcmV0dXJuIkNs
+b3N1cmUgJyIrSC5kKHRoaXMuZCkrIicgb2YgIisoIkluc3RhbmNlIG9mICciK0guZChILmxoKHQpKSsi
+JyIpfX0KSC5FcS5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiJSdW50aW1lRXJyb3I6ICIr
+SC5kKHRoaXMuYSl9fQpILmtZLnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7cmV0dXJuIkFzc2VydGlv
+biBmYWlsZWQ6ICIrUC5oKHRoaXMuYSl9fQpILk41LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3Jl
+dHVybiB0aGlzLmF9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYT09PTB9LApnVjpmdW5jdGlv
+bigpe3JldHVybiBuZXcgSC5pNSh0aGlzLEguTGgodGhpcykuQygiaTU8MT4iKSl9LAp4NDpmdW5jdGlv
+bihhKXt2YXIgdCxzCmlmKHR5cGVvZiBhPT0ic3RyaW5nIil7dD10aGlzLmIKaWYodD09bnVsbClyZXR1
+cm4hMQpyZXR1cm4gdGhpcy5YdSh0LGEpfWVsc2V7cz10aGlzLkNYKGEpCnJldHVybiBzfX0sCkNYOmZ1
+bmN0aW9uKGEpe3ZhciB0PXRoaXMuZAppZih0PT1udWxsKXJldHVybiExCnJldHVybiB0aGlzLkZoKHRo
+aXMuQnQodCxKLmhmKGEpJjB4M2ZmZmZmZiksYSk+PTB9LApxOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxy
+LHEscD10aGlzLG89bnVsbAppZih0eXBlb2YgYj09InN0cmluZyIpe3Q9cC5iCmlmKHQ9PW51bGwpcmV0
+dXJuIG8Kcz1wLmoyKHQsYikKcj1zPT1udWxsP286cy5iCnJldHVybiByfWVsc2UgaWYodHlwZW9mIGI9
+PSJudW1iZXIiJiYoYiYweDNmZmZmZmYpPT09Yil7cT1wLmMKaWYocT09bnVsbClyZXR1cm4gbwpzPXAu
+ajIocSxiKQpyPXM9PW51bGw/bzpzLmIKcmV0dXJuIHJ9ZWxzZSByZXR1cm4gcC5hYShiKX0sCmFhOmZ1
+bmN0aW9uKGEpe3ZhciB0LHMscj10aGlzLmQKaWYocj09bnVsbClyZXR1cm4gbnVsbAp0PXRoaXMuQnQo
+cixKLmhmKGEpJjB4M2ZmZmZmZikKcz10aGlzLkZoKHQsYSkKaWYoczwwKXJldHVybiBudWxsCnJldHVy
+biB0W3NdLmJ9LApZOmZ1bmN0aW9uKGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbj10aGlzLG09SC5MaChu
+KQptLmMuYShiKQptLlFbMV0uYShjKQppZih0eXBlb2YgYj09InN0cmluZyIpe3Q9bi5iCm4uRUgodD09
+bnVsbD9uLmI9bi56SygpOnQsYixjKX1lbHNlIGlmKHR5cGVvZiBiPT0ibnVtYmVyIiYmKGImMHgzZmZm
+ZmZmKT09PWIpe3M9bi5jCm4uRUgocz09bnVsbD9uLmM9bi56SygpOnMsYixjKX1lbHNle3I9bi5kCmlm
+KHI9PW51bGwpcj1uLmQ9bi56SygpCnE9Si5oZihiKSYweDNmZmZmZmYKcD1uLkJ0KHIscSkKaWYocD09
+bnVsbCluLkVJKHIscSxbbi5IbihiLGMpXSkKZWxzZXtvPW4uRmgocCxiKQppZihvPj0wKXBbb10uYj1j
+CmVsc2UgcC5wdXNoKG4uSG4oYixjKSl9fX0sCks6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9dGhpcwpI
+LkxoKHIpLkMoIn4oMSwyKSIpLmEoYikKdD1yLmUKcz1yLnIKZm9yKDt0IT1udWxsOyl7Yi4kMih0LmEs
+dC5iKQppZihzIT09ci5yKXRocm93IEguYihQLmE0KHIpKQp0PXQuY319LApFSDpmdW5jdGlvbihhLGIs
+Yyl7dmFyIHQscz10aGlzLHI9SC5MaChzKQpyLmMuYShiKQpyLlFbMV0uYShjKQp0PXMuajIoYSxiKQpp
+Zih0PT1udWxsKXMuRUkoYSxiLHMuSG4oYixjKSkKZWxzZSB0LmI9Y30sCmtzOmZ1bmN0aW9uKCl7dGhp
+cy5yPXRoaXMucisxJjY3MTA4ODYzfSwKSG46ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRoaXMscj1ILkxo
+KHMpLHE9bmV3IEguZGIoci5jLmEoYSksci5RWzFdLmEoYikpCmlmKHMuZT09bnVsbClzLmU9cy5mPXEK
+ZWxzZXt0PXMuZgpxLmQ9dApzLmY9dC5jPXF9KytzLmEKcy5rcygpCnJldHVybiBxfSwKRmg6ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzCmlmKGE9PW51bGwpcmV0dXJuLTEKdD1hLmxlbmd0aApmb3Iocz0wO3M8dDsr
+K3MpaWYoSi5STShhW3NdLmEsYikpcmV0dXJuIHMKcmV0dXJuLTF9LApaOmZ1bmN0aW9uKGEpe3JldHVy
+biBQLm5PKHRoaXMpfSwKajI6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYVtiXX0sCkJ0OmZ1bmN0aW9uKGEs
+Yil7cmV0dXJuIGFbYl19LApFSTpmdW5jdGlvbihhLGIsYyl7YVtiXT1jfSwKcm46ZnVuY3Rpb24oYSxi
+KXtkZWxldGUgYVtiXX0sClh1OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuajIoYSxiKSE9bnVsbH0s
+CnpLOmZ1bmN0aW9uKCl7dmFyIHQ9Ijxub24taWRlbnRpZmllci1rZXk+IixzPU9iamVjdC5jcmVhdGUo
+bnVsbCkKdGhpcy5FSShzLHQscykKdGhpcy5ybihzLHQpCnJldHVybiBzfSwKJGlGbzoxfQpILmRiLnBy
+b3RvdHlwZT17fQpILmk1LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEuYX0s
+CmdsMDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmE9PT0wfSwKZ2t6OmZ1bmN0aW9uKGEpe3ZhciB0
+PXRoaXMuYSxzPW5ldyBILk42KHQsdC5yLHRoaXMuJHRpLkMoIk42PDE+IikpCnMuYz10LmUKcmV0dXJu
+IHN9LAp0ZzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmEueDQoYil9fQpILk42LnByb3RvdHlwZT17
+CmdsOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZH0sCkY6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLHM9dC5h
+CmlmKHQuYiE9PXMucil0aHJvdyBILmIoUC5hNChzKSkKZWxzZXtzPXQuYwppZihzPT1udWxsKXt0LnNx
+WShudWxsKQpyZXR1cm4hMX1lbHNle3Quc3FZKHMuYSkKdC5jPXQuYy5jCnJldHVybiEwfX19LApzcVk6
+ZnVuY3Rpb24oYSl7dGhpcy5kPXRoaXMuJHRpLmMuYShhKX0sCiRpQW46MX0KSC5yLnByb3RvdHlwZT17
+CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEoYSl9LAokUzoxfQpILmRDLnByb3RvdHlwZT17CiQy
+OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYShhLGIpfSwKJFM6NDR9Ckgud04ucHJvdG90eXBlPXsK
+JDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYShILmMoYSkpfSwKJFM6NDB9CkguVlIucHJvdG90eXBl
+PXsKWjpmdW5jdGlvbihhKXtyZXR1cm4iUmVnRXhwLyIrdGhpcy5hKyIvIit0aGlzLmIuZmxhZ3N9LApn
+SGM6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLHM9dC5jCmlmKHMhPW51bGwpcmV0dXJuIHMKcz10LmIKcmV0
+dXJuIHQuYz1ILnY0KHQuYSxzLm11bHRpbGluZSwhcy5pZ25vcmVDYXNlLHMudW5pY29kZSxzLmRvdEFs
+bCwhMCl9LApkZDpmdW5jdGlvbihhLGIpe3JldHVybiBuZXcgSC5LVyh0aGlzLGIsMCl9LApVWjpmdW5j
+dGlvbihhLGIpe3ZhciB0LHM9dGhpcy5nSGMoKQpzLmxhc3RJbmRleD1iCnQ9cy5leGVjKGEpCmlmKHQ9
+PW51bGwpcmV0dXJuIG51bGwKcmV0dXJuIG5ldyBILkVLKHQpfSwKJGl2WDoxLAokaXdMOjF9CkguRUsu
+cHJvdG90eXBlPXsKcTpmdW5jdGlvbihhLGIpe3ZhciB0CkguV1koYikKdD10aGlzLmIKaWYoYj49dC5s
+ZW5ndGgpcmV0dXJuIEguayh0LGIpCnJldHVybiB0W2JdfSwKJGlPZDoxLAokaWliOjF9CkguS1cucHJv
+dG90eXBlPXsKZ2t6OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgSC5QYih0aGlzLmEsdGhpcy5iLHRoaXMu
+Yyl9fQpILlBiLnByb3RvdHlwZT17CmdsOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZH0sCkY6ZnVuY3Rp
+b24oKXt2YXIgdCxzLHIscSxwPXRoaXMsbz1wLmIKaWYobz09bnVsbClyZXR1cm4hMQp0PXAuYwppZih0
+PD1vLmxlbmd0aCl7cz1wLmEKcj1zLlVaKG8sdCkKaWYociE9bnVsbCl7cC5kPXIKbz1yLmIKdD1vLmlu
+ZGV4CnE9dCtvWzBdLmxlbmd0aAppZih0PT09cSl7aWYocy5iLnVuaWNvZGUpe289cC5jCnQ9bysxCnM9
+cC5iCmlmKHQ8cy5sZW5ndGgpe289Si5yWShzKS5tKHMsbykKaWYobz49NTUyOTYmJm88PTU2MzE5KXtv
+PUMueEIubShzLHQpCm89bz49NTYzMjAmJm88PTU3MzQzfWVsc2Ugbz0hMX1lbHNlIG89ITF9ZWxzZSBv
+PSExCnE9KG8/cSsxOnEpKzF9cC5jPXEKcmV0dXJuITB9fXAuYj1wLmQ9bnVsbApyZXR1cm4hMX0sCiRp
+QW46MX0KSC50US5wcm90b3R5cGU9ewpxOmZ1bmN0aW9uKGEsYil7SC5XWShiKQppZihiIT09MClILnZo
+KFAuTzcoYixudWxsKSkKcmV0dXJuIHRoaXMuY30sCiRpT2Q6MX0KSC5ORi5wcm90b3R5cGU9ewpna3o6
+ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBILlNkKHRoaXMuYSx0aGlzLmIsdGhpcy5jKX19CkguU2QucHJv
+dG90eXBlPXsKRjpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzLHE9ci5jLHA9ci5iLG89cC5sZW5ndGgs
+bj1yLmEsbT1uLmxlbmd0aAppZihxK28+bSl7ci5kPW51bGwKcmV0dXJuITF9dD1uLmluZGV4T2YocCxx
+KQppZih0PDApe3IuYz1tKzEKci5kPW51bGwKcmV0dXJuITF9cz10K28Kci5kPW5ldyBILnRRKHQscCkK
+ci5jPXM9PT1yLmM/cysxOnMKcmV0dXJuITB9LApnbDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmR9LAok
+aUFuOjF9CkguZUgucHJvdG90eXBlPXskaWVIOjEsJGllcToxfQpILkxaLnByb3RvdHlwZT17CmdBOmZ1
+bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH0sCiRpWGo6MX0KSC5EZy5wcm90b3R5cGU9ewpxOmZ1bmN0
+aW9uKGEsYil7SC5XWShiKQpILm9kKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19LApZOmZ1bmN0aW9u
+KGEsYixjKXtILmRqKGMpCkgub2QoYixhLGEubGVuZ3RoKQphW2JdPWN9LAokaWJROjEsCiRpY1g6MSwK
+JGl6TToxfQpILlBnLnByb3RvdHlwZT17Clk6ZnVuY3Rpb24oYSxiLGMpe0guV1koYykKSC5vZChiLGEs
+YS5sZW5ndGgpCmFbYl09Y30sCiRpYlE6MSwKJGljWDoxLAokaXpNOjF9CkgueGoucHJvdG90eXBlPXsK
+cTpmdW5jdGlvbihhLGIpe0guV1koYikKSC5vZChiLGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfX0KSC5k
+RS5wcm90b3R5cGU9ewpxOmZ1bmN0aW9uKGEsYil7SC5XWShiKQpILm9kKGIsYSxhLmxlbmd0aCkKcmV0
+dXJuIGFbYl19fQpILlpBLnByb3RvdHlwZT17CnE6ZnVuY3Rpb24oYSxiKXtILldZKGIpCkgub2QoYixh
+LGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19Ckgud2YucHJvdG90eXBlPXsKcTpmdW5jdGlvbihhLGIpe0gu
+V1koYikKSC5vZChiLGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfX0KSC5QcS5wcm90b3R5cGU9ewpxOmZ1
+bmN0aW9uKGEsYil7SC5XWShiKQpILm9kKGIsYSxhLmxlbmd0aCkKcmV0dXJuIGFbYl19fQpILmVFLnBy
+b3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH0sCnE6ZnVuY3Rpb24oYSxiKXtI
+LldZKGIpCkgub2QoYixhLGEubGVuZ3RoKQpyZXR1cm4gYVtiXX19CkguVjYucHJvdG90eXBlPXsKZ0E6
+ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofSwKcTpmdW5jdGlvbihhLGIpe0guV1koYikKSC5vZChi
+LGEsYS5sZW5ndGgpCnJldHVybiBhW2JdfSwKJGlWNjoxLAokaW42OjF9CkguUkcucHJvdG90eXBlPXt9
+CkguVlAucHJvdG90eXBlPXt9CkguV0IucHJvdG90eXBlPXt9CkguWkcucHJvdG90eXBlPXt9CkguSmMu
+cHJvdG90eXBlPXsKQzpmdW5jdGlvbihhKXtyZXR1cm4gSC5jRSh2LnR5cGVVbml2ZXJzZSx0aGlzLGEp
+fSwKS3E6ZnVuY3Rpb24oYSl7cmV0dXJuIEgudjUodi50eXBlVW5pdmVyc2UsdGhpcyxhKX19CkguRVQu
+cHJvdG90eXBlPXt9CkgudTkucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfX0K
+SC54LnByb3RvdHlwZT17fQpQLnRoLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMu
+YSxzPXQuYQp0LmE9bnVsbApzLiQwKCl9LAokUzoxMH0KUC5oYS5wcm90b3R5cGU9ewokMTpmdW5jdGlv
+bihhKXt2YXIgdCxzCnRoaXMuYS5hPXUuTS5hKGEpCnQ9dGhpcy5iCnM9dGhpcy5jCnQuZmlyc3RDaGls
+ZD90LnJlbW92ZUNoaWxkKHMpOnQuYXBwZW5kQ2hpbGQocyl9LAokUzoyMH0KUC5Wcy5wcm90b3R5cGU9
+ewokMDpmdW5jdGlvbigpe3RoaXMuYS4kMCgpfSwKJEM6IiQwIiwKJFI6MCwKJFM6MH0KUC5GdC5wcm90
+b3R5cGU9ewokMDpmdW5jdGlvbigpe3RoaXMuYS4kMCgpfSwKJEM6IiQwIiwKJFI6MCwKJFM6MH0KUC5X
+My5wcm90b3R5cGU9ewpDWTpmdW5jdGlvbihhLGIpe2lmKHNlbGYuc2V0VGltZW91dCE9bnVsbClzZWxm
+LnNldFRpbWVvdXQoSC50UihuZXcgUC55SCh0aGlzLGIpLDApLGEpCmVsc2UgdGhyb3cgSC5iKFAuTDQo
+ImBzZXRUaW1lb3V0KClgIG5vdCBmb3VuZC4iKSl9fQpQLnlILnByb3RvdHlwZT17CiQwOmZ1bmN0aW9u
+KCl7dGhpcy5iLiQwKCl9LAokQzoiJDAiLAokUjowLAokUzoyfQpQLmloLnByb3RvdHlwZT17CmFNOmZ1
+bmN0aW9uKGEsYil7dmFyIHQscyxyPXRoaXMuJHRpCnIuQygiMS8iKS5hKGIpCnQ9IXRoaXMuYnx8ci5D
+KCJiODwxPiIpLmIoYikKcz10aGlzLmEKaWYodClzLlhmKGIpCmVsc2Ugcy5YMihyLmMuYShiKSl9LAp3
+MDpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGI9PW51bGwpYj1QLnYwKGEpCnQ9dGhpcy5hCmlmKHRoaXMu
+Yil0LlpMKGEsYikKZWxzZSB0Lk5rKGEsYil9fQpQLldNLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEp
+e3JldHVybiB0aGlzLmEuJDIoMCxhKX0sCiRTOjQ5fQpQLlNYLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9u
+KGEsYil7dGhpcy5hLiQyKDEsbmV3IEguYnEoYSx1LmwuYShiKSkpfSwKJEM6IiQyIiwKJFI6MiwKJFM6
+MjF9ClAuR3MucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt0aGlzLmEoSC5XWShhKSxiKX0sCiRT
+OjI2fQpQLkZ5LnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7cmV0dXJuIkl0ZXJhdGlvbk1hcmtlcigi
+K3RoaXMuYisiLCAiK0guZCh0aGlzLmEpKyIpIn19ClAuR1YucHJvdG90eXBlPXsKZ2w6ZnVuY3Rpb24o
+KXt2YXIgdD10aGlzLmMKaWYodD09bnVsbClyZXR1cm4gdGhpcy5iCnJldHVybiB0aGlzLiR0aS5jLmEo
+dC5nbCgpKX0sCkY6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwPXRoaXMKZm9yKDshMDspe3Q9cC5jCmlm
+KHQhPW51bGwpaWYodC5GKCkpcmV0dXJuITAKZWxzZSBwLmM9bnVsbApzPWZ1bmN0aW9uKGEsYixjKXt2
+YXIgbyxuPWIKd2hpbGUodHJ1ZSl0cnl7cmV0dXJuIGEobixvKX1jYXRjaChtKXtvPW0Kbj1jfX0ocC5h
+LDAsMSkKaWYocyBpbnN0YW5jZW9mIFAuRnkpe3I9cy5iCmlmKHI9PT0yKXt0PXAuZAppZih0PT1udWxs
+fHx0Lmxlbmd0aD09PTApe3Auc0VDKG51bGwpCnJldHVybiExfWlmKDA+PXQubGVuZ3RoKXJldHVybiBI
+LmsodCwtMSkKcC5hPXQucG9wKCkKY29udGludWV9ZWxzZXt0PXMuYQppZihyPT09Myl0aHJvdyB0CmVs
+c2V7cT1KLklUKHQpCmlmKHEgaW5zdGFuY2VvZiBQLkdWKXt0PXAuZAppZih0PT1udWxsKXQ9cC5kPVtd
+CkMuTm0uaSh0LHAuYSkKcC5hPXEuYQpjb250aW51ZX1lbHNle3AuYz1xCmNvbnRpbnVlfX19fWVsc2V7
+cC5zRUMocykKcmV0dXJuITB9fXJldHVybiExfSwKc0VDOmZ1bmN0aW9uKGEpe3RoaXMuYj10aGlzLiR0
+aS5jLmEoYSl9LAokaUFuOjF9ClAucTQucHJvdG90eXBlPXsKZ2t6OmZ1bmN0aW9uKGEpe3JldHVybiBu
+ZXcgUC5HVih0aGlzLmEoKSx0aGlzLiR0aS5DKCJHVjwxPiIpKX19ClAuYjgucHJvdG90eXBlPXt9ClAu
+UGYucHJvdG90eXBlPXsKdzA6ZnVuY3Rpb24oYSxiKXt2YXIgdApQLlVJKGEsImVycm9yIix1LkspCnQ9
+dGhpcy5hCmlmKHQuYSE9PTApdGhyb3cgSC5iKFAuUFYoIkZ1dHVyZSBhbHJlYWR5IGNvbXBsZXRlZCIp
+KQp0Lk5rKGEsYj09bnVsbD9QLnYwKGEpOmIpfSwKcG06ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMudzAo
+YSxudWxsKX19ClAuWmYucHJvdG90eXBlPXsKYU06ZnVuY3Rpb24oYSxiKXt2YXIgdAp0aGlzLiR0aS5D
+KCIxLyIpLmEoYikKdD10aGlzLmEKaWYodC5hIT09MCl0aHJvdyBILmIoUC5QVigiRnV0dXJlIGFscmVh
+ZHkgY29tcGxldGVkIikpCnQuWGYoYil9fQpQLkZlLnByb3RvdHlwZT17CkhSOmZ1bmN0aW9uKGEpe2lm
+KCh0aGlzLmMmMTUpIT09NilyZXR1cm4hMApyZXR1cm4gdGhpcy5iLmIuYnYodS5hbC5hKHRoaXMuZCks
+YS5hLHUueSx1LkspfSwKS3c6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5lLHM9dS56LHI9dS5LLHE9dGhp
+cy4kdGkuQygiMi8iKSxwPXRoaXMuYi5iCmlmKHUuYWcuYih0KSlyZXR1cm4gcS5hKHAucnAodCxhLmEs
+YS5iLHMscix1LmwpKQplbHNlIHJldHVybiBxLmEocC5idih1LmJJLmEodCksYS5hLHMscikpfX0KUC52
+cy5wcm90b3R5cGU9ewpTcTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHE9dGhpcy4kdGkKcS5LcShj
+KS5DKCIxLygyKSIpLmEoYSkKdD0kLlgzCmlmKHQhPT1DLk5VKXtjLkMoIkA8MC8+IikuS3EocS5jKS5D
+KCIxKDIpIikuYShhKQppZihiIT1udWxsKWI9UC5WSChiLHQpfXM9bmV3IFAudnMoJC5YMyxjLkMoInZz
+PDA+IikpCnI9Yj09bnVsbD8xOjMKdGhpcy54ZihuZXcgUC5GZShzLHIsYSxiLHEuQygiQDwxPiIpLktx
+KGMpLkMoIkZlPDEsMj4iKSkpCnJldHVybiBzfSwKVzc6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5T
+cShhLG51bGwsYil9LApRZDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscz10aGlzLiR0aQpzLktxKGMpLkMo
+IjEvKDIpIikuYShhKQp0PW5ldyBQLnZzKCQuWDMsYy5DKCJ2czwwPiIpKQp0aGlzLnhmKG5ldyBQLkZl
+KHQsMTksYSxiLHMuQygiQDwxPiIpLktxKGMpLkMoIkZlPDEsMj4iKSkpCnJldHVybiB0fSwKeGY6ZnVu
+Y3Rpb24oYSl7dmFyIHQscz10aGlzLHI9cy5hCmlmKHI8PTEpe2EuYT11LnguYShzLmMpCnMuYz1hfWVs
+c2V7aWYocj09PTIpe3Q9dS5fLmEocy5jKQpyPXQuYQppZihyPDQpe3QueGYoYSkKcmV0dXJufXMuYT1y
+CnMuYz10LmN9UC5UayhudWxsLG51bGwscy5iLHUuTS5hKG5ldyBQLmRhKHMsYSkpKX19LApqUTpmdW5j
+dGlvbihhKXt2YXIgdCxzLHIscSxwLG89dGhpcyxuPXt9Cm4uYT1hCmlmKGE9PW51bGwpcmV0dXJuCnQ9
+by5hCmlmKHQ8PTEpe3M9dS54LmEoby5jKQpyPW8uYz1hCmlmKHMhPW51bGwpe2Zvcig7cT1yLmEscSE9
+bnVsbDtyPXEpO3IuYT1zfX1lbHNle2lmKHQ9PT0yKXtwPXUuXy5hKG8uYykKdD1wLmEKaWYodDw0KXtw
+LmpRKGEpCnJldHVybn1vLmE9dApvLmM9cC5jfW4uYT1vLk44KGEpClAuVGsobnVsbCxudWxsLG8uYix1
+Lk0uYShuZXcgUC5vUShuLG8pKSl9fSwKYWg6ZnVuY3Rpb24oKXt2YXIgdD11LnguYSh0aGlzLmMpCnRo
+aXMuYz1udWxsCnJldHVybiB0aGlzLk44KHQpfSwKTjg6ZnVuY3Rpb24oYSl7dmFyIHQscyxyCmZvcih0
+PWEscz1udWxsO3QhPW51bGw7cz10LHQ9cil7cj10LmEKdC5hPXN9cmV0dXJuIHN9LApISDpmdW5jdGlv
+bihhKXt2YXIgdCxzPXRoaXMscj1zLiR0aQpyLkMoIjEvIikuYShhKQppZihyLkMoImI4PDE+IikuYihh
+KSlpZihyLmIoYSkpUC5BOShhLHMpCmVsc2UgUC5rMyhhLHMpCmVsc2V7dD1zLmFoKCkKci5jLmEoYSkK
+cy5hPTQKcy5jPWEKUC5IWihzLHQpfX0sClgyOmZ1bmN0aW9uKGEpe3ZhciB0LHM9dGhpcwpzLiR0aS5j
+LmEoYSkKdD1zLmFoKCkKcy5hPTQKcy5jPWEKUC5IWihzLHQpfSwKWkw6ZnVuY3Rpb24oYSxiKXt2YXIg
+dCxzLHI9dGhpcwp1LmwuYShiKQp0PXIuYWgoKQpzPVAuVGwoYSxiKQpyLmE9OApyLmM9cwpQLkhaKHIs
+dCl9LApYZjpmdW5jdGlvbihhKXt2YXIgdD10aGlzLHM9dC4kdGkKcy5DKCIxLyIpLmEoYSkKaWYocy5D
+KCJiODwxPiIpLmIoYSkpe3QuY1UoYSkKcmV0dXJufXQuYT0xClAuVGsobnVsbCxudWxsLHQuYix1Lk0u
+YShuZXcgUC5ySCh0LGEpKSl9LApjVTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLHM9dC4kdGkKcy5DKCJi
+ODwxPiIpLmEoYSkKaWYocy5iKGEpKXtpZihhLmE9PT04KXt0LmE9MQpQLlRrKG51bGwsbnVsbCx0LmIs
+dS5NLmEobmV3IFAuS0YodCxhKSkpfWVsc2UgUC5BOShhLHQpCnJldHVybn1QLmszKGEsdCl9LApOazpm
+dW5jdGlvbihhLGIpe3RoaXMuYT0xClAuVGsobnVsbCxudWxsLHRoaXMuYix1Lk0uYShuZXcgUC5aTCh0
+aGlzLGEsYikpKX0sCiRpYjg6MX0KUC5kYS5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe1AuSFoodGhp
+cy5hLHRoaXMuYil9LAokUzowfQpQLm9RLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7UC5IWih0aGlz
+LmIsdGhpcy5hLmEpfSwKJFM6MH0KUC5wVi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdD10
+aGlzLmEKdC5hPTAKdC5ISChhKX0sCiRTOjEwfQpQLlU3LnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEs
+Yil7dS5sLmEoYikKdGhpcy5hLlpMKGEsYil9LAokMTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy4kMihh
+LG51bGwpfSwKJEM6IiQyIiwKJEQ6ZnVuY3Rpb24oKXtyZXR1cm5bbnVsbF19LAokUzoyOX0KUC52ci5w
+cm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3RoaXMuYS5aTCh0aGlzLmIsdGhpcy5jKX0sCiRTOjB9ClAu
+ckgucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmEKdC5YMih0LiR0aS5jLmEodGhp
+cy5iKSl9LAokUzowfQpQLktGLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7UC5BOSh0aGlzLmIsdGhp
+cy5hKX0sCiRTOjB9ClAuWkwucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt0aGlzLmEuWkwodGhpcy5i
+LHRoaXMuYyl9LAokUzowfQpQLlJULnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEs
+cCxvLG49dGhpcyxtPW51bGwKdHJ5e3I9bi5jCm09ci5iLmIuenoodS5mTy5hKHIuZCksdS56KX1jYXRj
+aChxKXt0PUguUnUocSkKcz1ILnRzKHEpCmlmKG4uZCl7cj11Lm4uYShuLmEuYS5jKS5hCnA9dApwPXI9
+PW51bGw/cD09bnVsbDpyPT09cApyPXB9ZWxzZSByPSExCnA9bi5iCmlmKHIpcC5iPXUubi5hKG4uYS5h
+LmMpCmVsc2UgcC5iPVAuVGwodCxzKQpwLmE9ITAKcmV0dXJufWlmKHUuYy5iKG0pKXtpZihtIGluc3Rh
+bmNlb2YgUC52cyYmbS5hPj00KXtpZihtLmE9PT04KXtyPW4uYgpyLmI9dS5uLmEobS5jKQpyLmE9ITB9
+cmV0dXJufW89bi5hLmEKcj1uLmIKci5iPW0uVzcobmV3IFAualoobyksdS56KQpyLmE9ITF9fSwKJFM6
+Mn0KUC5qWi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfSwKJFM6Mzl9ClAu
+cnEucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwLG8sbixtPXRoaXMKdHJ5e3I9
+bS5iCnE9ci4kdGkKcD1xLmMKbz1wLmEobS5jKQptLmEuYj1yLmIuYi5idihxLkMoIjIvKDEpIikuYShy
+LmQpLG8scS5DKCIyLyIpLHApfWNhdGNoKG4pe3Q9SC5SdShuKQpzPUgudHMobikKcj1tLmEKci5iPVAu
+VGwodCxzKQpyLmE9ITB9fSwKJFM6Mn0KUC5SVy5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3ZhciB0
+LHMscixxLHAsbyxuLG0sbD10aGlzCnRyeXt0PXUubi5hKGwuYS5hLmMpCnE9bC5jCmlmKEgub1QocS5I
Uih0KSkmJnEuZSE9bnVsbCl7cD1sLmIKcC5iPXEuS3codCkKcC5hPSExfX1jYXRjaChvKXtzPUguUnUo
-bykKcj1ILnRzKG8pCnE9dS5uLmIobC5hLmEuYykKcD1xLmEKbj1zCm09bC5iCmlmKHA9PW51bGw/bj09
-bnVsbDpwPT09biltLmI9cQplbHNlIG0uYj1uZXcgUC5DdyhzLHIpCm0uYT0hMH19LAokUzoyfQpQLk9N
-LnByb3RvdHlwZT17fQpQLnFoLnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj10aGlz
-LHE9e30scD1uZXcgUC52cygkLlgzLHUuZkopCnEuYT0wCnQ9SC5MaChyKQpzPXQuQygifigxKSIpLmIo
-bmV3IFAuQjUocSxyKSkKdS5NLmIobmV3IFAudU8ocSxwKSkKVy5KRShyLmEsci5iLHMsITEsdC5kKQpy
-ZXR1cm4gcH19ClAuQjUucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7SC5MaCh0aGlzLmIpLmQuYihh
-KTsrK3RoaXMuYS5hfSwKJFM6ZnVuY3Rpb24oKXtyZXR1cm4gSC5MaCh0aGlzLmIpLkMoImM4KDEpIil9
-fQpQLnVPLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7dGhpcy5iLkhIKHRoaXMuYS5hKX0sCiRTOjB9
-ClAuTU8ucHJvdG90eXBlPXt9ClAua1QucHJvdG90eXBlPXt9ClAueEkucHJvdG90eXBlPXt9ClAuQ3cu
-cHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4gSC5kKHRoaXMuYSl9LAokaVhTOjF9ClAubTAu
-cHJvdG90eXBlPXskaUpCOjF9ClAucEsucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt2YXIgdCxzPXRo
-aXMuYSxyPXMuYQpzPXI9PW51bGw/cy5hPW5ldyBQLm4oKTpyCnI9dGhpcy5iCmlmKHI9PW51bGwpdGhy
-b3cgSC5iKHMpCnQ9SC5iKHMpCnQuc3RhY2s9ci53KDApCnRocm93IHR9LAokUzowfQpQLkppLnByb3Rv
-dHlwZT17CmJIOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPW51bGwKdS5NLmIoYSkKdHJ5e2lmKEMuTlU9
-PT0kLlgzKXthLiQwKCkKcmV0dXJufVAuVDgocSxxLHRoaXMsYSx1LkgpfWNhdGNoKHIpe3Q9SC5SdShy
-KQpzPUgudHMocikKUC5MMihxLHEsdGhpcyx0LHUubC5iKHMpKX19LApEbDpmdW5jdGlvbihhLGIsYyl7
-dmFyIHQscyxyLHE9bnVsbApjLkMoIn4oMCkiKS5iKGEpCmMuYihiKQp0cnl7aWYoQy5OVT09PSQuWDMp
-e2EuJDEoYikKcmV0dXJufVAueXYocSxxLHRoaXMsYSxiLHUuSCxjKX1jYXRjaChyKXt0PUguUnUocikK
-cz1ILnRzKHIpClAuTDIocSxxLHRoaXMsdCx1LmwuYihzKSl9fSwKUlQ6ZnVuY3Rpb24oYSxiKXtyZXR1
-cm4gbmV3IFAuaGoodGhpcyxiLkMoIjAoKSIpLmIoYSksYil9LApHWTpmdW5jdGlvbihhKXtyZXR1cm4g
-bmV3IFAuVnAodGhpcyx1Lk0uYihhKSl9LApQeTpmdW5jdGlvbihhLGIpe3JldHVybiBuZXcgUC5PUih0
-aGlzLGIuQygifigwKSIpLmIoYSksYil9LApxOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG51bGx9LAp6ejpm
-dW5jdGlvbihhLGIpe2IuQygiMCgpIikuYihhKQppZigkLlgzPT09Qy5OVSlyZXR1cm4gYS4kMCgpCnJl
-dHVybiBQLlQ4KG51bGwsbnVsbCx0aGlzLGEsYil9LApidjpmdW5jdGlvbihhLGIsYyxkKXtjLkMoIkA8
-MD4iKS5LcShkKS5DKCIxKDIpIikuYihhKQpkLmIoYikKaWYoJC5YMz09PUMuTlUpcmV0dXJuIGEuJDEo
-YikKcmV0dXJuIFAueXYobnVsbCxudWxsLHRoaXMsYSxiLGMsZCl9LApycDpmdW5jdGlvbihhLGIsYyxk
-LGUsZil7ZC5DKCJAPDA+IikuS3EoZSkuS3EoZikuQygiMSgyLDMpIikuYihhKQplLmIoYikKZi5iKGMp
-CmlmKCQuWDM9PT1DLk5VKXJldHVybiBhLiQyKGIsYykKcmV0dXJuIFAuUXgobnVsbCxudWxsLHRoaXMs
-YSxiLGMsZCxlLGYpfSwKTGo6ZnVuY3Rpb24oYSxiLGMsZCl7cmV0dXJuIGIuQygiQDwwPiIpLktxKGMp
-LktxKGQpLkMoIjEoMiwzKSIpLmIoYSl9fQpQLmhqLnByb3RvdHlwZT17CiQwOmZ1bmN0aW9uKCl7cmV0
-dXJuIHRoaXMuYS56eih0aGlzLmIsdGhpcy5jKX0sCiRTOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYy5D
-KCIwKCkiKX19ClAuVnAucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hLmJIKHRo
-aXMuYil9LAokUzoyfQpQLk9SLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYwpy
-ZXR1cm4gdGhpcy5hLkRsKHRoaXMuYix0LmIoYSksdCl9LAokUzpmdW5jdGlvbigpe3JldHVybiB0aGlz
-LmMuQygifigwKSIpfX0KUC5iNi5wcm90b3R5cGU9ewpna3o6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxz
-PW5ldyBQLmxtKHQsdC5yLEguTGgodCkuQygibG08MT4iKSkKcy5jPXQuZQpyZXR1cm4gc30sCmdBOmZ1
-bmN0aW9uKGEpe3JldHVybiB0aGlzLmF9LAp0ZzpmdW5jdGlvbihhLGIpe3ZhciB0LHMKaWYodHlwZW9m
-IGI9PSJzdHJpbmciJiZiIT09Il9fcHJvdG9fXyIpe3Q9dGhpcy5iCmlmKHQ9PW51bGwpcmV0dXJuITEK
-cmV0dXJuIHUueS5iKHRbYl0pIT1udWxsfWVsc2V7cz10aGlzLlBSKGIpCnJldHVybiBzfX0sClBSOmZ1
-bmN0aW9uKGEpe3ZhciB0PXRoaXMuZAppZih0PT1udWxsKXJldHVybiExCnJldHVybiB0aGlzLkRGKHRb
-dGhpcy5OKGEpXSxhKT49MH0sCmk6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9dGhpcwpILkxoKHIpLmQu
-YihiKQppZih0eXBlb2YgYj09InN0cmluZyImJmIhPT0iX19wcm90b19fIil7dD1yLmIKcmV0dXJuIHIu
-YlEodD09bnVsbD9yLmI9UC5UMigpOnQsYil9ZWxzZSBpZih0eXBlb2YgYj09Im51bWJlciImJihiJjEw
-NzM3NDE4MjMpPT09Yil7cz1yLmMKcmV0dXJuIHIuYlEocz09bnVsbD9yLmM9UC5UMigpOnMsYil9ZWxz
-ZSByZXR1cm4gci5CNyhiKX0sCkI3OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxPXRoaXMKSC5MaChxKS5k
-LmIoYSkKdD1xLmQKaWYodD09bnVsbCl0PXEuZD1QLlQyKCkKcz1xLk4oYSkKcj10W3NdCmlmKHI9PW51
-bGwpdFtzXT1bcS55byhhKV0KZWxzZXtpZihxLkRGKHIsYSk+PTApcmV0dXJuITEKci5wdXNoKHEueW8o
-YSkpfXJldHVybiEwfSwKUjpmdW5jdGlvbihhLGIpe3ZhciB0PXRoaXMKaWYodHlwZW9mIGI9PSJzdHJp
-bmciJiZiIT09Il9fcHJvdG9fXyIpcmV0dXJuIHQuTCh0LmIsYikKZWxzZSBpZih0eXBlb2YgYj09Im51
-bWJlciImJihiJjEwNzM3NDE4MjMpPT09YilyZXR1cm4gdC5MKHQuYyxiKQplbHNlIHJldHVybiB0LnFn
-KGIpfSwKcWc6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscD10aGlzLG89cC5kCmlmKG89PW51bGwpcmV0
-dXJuITEKdD1wLk4oYSkKcz1vW3RdCnI9cC5ERihzLGEpCmlmKHI8MClyZXR1cm4hMQpxPXMuc3BsaWNl
-KHIsMSlbMF0KaWYoMD09PXMubGVuZ3RoKWRlbGV0ZSBvW3RdCnAuR1MocSkKcmV0dXJuITB9LApiUTpm
-dW5jdGlvbihhLGIpe0guTGgodGhpcykuZC5iKGIpCmlmKHUueS5iKGFbYl0pIT1udWxsKXJldHVybiEx
-CmFbYl09dGhpcy55byhiKQpyZXR1cm4hMH0sCkw6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihhPT1udWxs
-KXJldHVybiExCnQ9dS55LmIoYVtiXSkKaWYodD09bnVsbClyZXR1cm4hMQp0aGlzLkdTKHQpCmRlbGV0
-ZSBhW2JdCnJldHVybiEwfSwKUzpmdW5jdGlvbigpe3RoaXMucj0xMDczNzQxODIzJnRoaXMucisxfSwK
-eW86ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLHI9bmV3IFAuYm4oSC5MaChzKS5kLmIoYSkpCmlmKHMu
-ZT09bnVsbClzLmU9cy5mPXIKZWxzZXt0PXMuZgpyLmM9dApzLmY9dC5iPXJ9KytzLmEKcy5TKCkKcmV0
-dXJuIHJ9LApHUzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLHM9YS5jLHI9YS5iCmlmKHM9PW51bGwpdC5l
-PXIKZWxzZSBzLmI9cgppZihyPT1udWxsKXQuZj1zCmVsc2Ugci5jPXM7LS10LmEKdC5TKCl9LApOOmZ1
-bmN0aW9uKGEpe3JldHVybiBKLmhmKGEpJjEwNzM3NDE4MjN9LApERjpmdW5jdGlvbihhLGIpe3ZhciB0
-LHMKaWYoYT09bnVsbClyZXR1cm4tMQp0PWEubGVuZ3RoCmZvcihzPTA7czx0OysrcylpZihKLlJNKGFb
-c10uYSxiKSlyZXR1cm4gcwpyZXR1cm4tMX19ClAuYm4ucHJvdG90eXBlPXt9ClAubG0ucHJvdG90eXBl
-PXsKZ2w6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kfSwKRjpmdW5jdGlvbigpe3ZhciB0PXRoaXMscz10
-LmEKaWYodC5iIT09cy5yKXRocm93IEguYihQLmE0KHMpKQplbHNle3M9dC5jCmlmKHM9PW51bGwpe3Qu
-c2oobnVsbCkKcmV0dXJuITF9ZWxzZXt0LnNqKHQuJHRpLmQuYihzLmEpKQp0LmM9dC5jLmIKcmV0dXJu
-ITB9fX0sCnNqOmZ1bmN0aW9uKGEpe3RoaXMuZD10aGlzLiR0aS5kLmIoYSl9LAokaUFuOjF9ClAubVcu
-cHJvdG90eXBlPXt9ClAudXkucHJvdG90eXBlPXskaWJROjEsJGljWDoxLCRpek06MX0KUC5sRC5wcm90
-b3R5cGU9ewpna3o6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBILmE3KGEsdGhpcy5nQShhKSxILnpLKGEp
-LkMoImE3PGxELkU+IikpfSwKRTpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnEoYSxiKX0sCks6ZnVu
-Y3Rpb24oYSxiKXt2YXIgdCxzCkgueksoYSkuQygifihsRC5FKSIpLmIoYikKdD10aGlzLmdBKGEpCmZv
-cihzPTA7czx0Oysrcyl7Yi4kMSh0aGlzLnEoYSxzKSkKaWYodCE9PXRoaXMuZ0EoYSkpdGhyb3cgSC5i
-KFAuYTQoYSkpfX0sCmdvcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nQShhKSE9PTB9LApFMjpmdW5j
-dGlvbihhLGIsYyl7dmFyIHQ9SC56SyhhKQpyZXR1cm4gbmV3IEguQTgoYSx0LktxKGMpLkMoIjEobEQu
-RSkiKS5iKGIpLHQuQygiQDxsRC5FPiIpLktxKGMpLkMoIkE4PDEsMj4iKSl9LApkdTpmdW5jdGlvbihh
-LGIsYyxkKXt2YXIgdApILnpLKGEpLkMoImxELkUiKS5iKGQpClAuakIoYixjLHRoaXMuZ0EoYSkpCmZv
-cih0PWI7dDxjOysrdCl0aGlzLlkoYSx0LGQpfSwKdzpmdW5jdGlvbihhKXtyZXR1cm4gUC5XRShhLCJb
-IiwiXSIpfX0KUC5pbC5wcm90b3R5cGU9e30KUC5yYS5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIp
-e3ZhciB0LHM9dGhpcy5hCmlmKCFzLmEpdGhpcy5iLmErPSIsICIKcy5hPSExCnM9dGhpcy5iCnQ9cy5h
-Kz1ILmQoYSkKcy5hPXQrIjogIgpzLmErPUguZChiKX0sCiRTOjR9ClAuWWsucHJvdG90eXBlPXsKSzpm
-dW5jdGlvbihhLGIpe3ZhciB0LHMKSC5MaCh0aGlzKS5DKCJ+KFlrLkssWWsuVikiKS5iKGIpCmZvcih0
-PUouSVQodGhpcy5nVigpKTt0LkYoKTspe3M9dC5nbCgpCmIuJDIocyx0aGlzLnEoMCxzKSl9fSwKZ1B1
-OmZ1bmN0aW9uKGEpe3JldHVybiBKLk0xKHRoaXMuZ1YoKSxuZXcgUC55USh0aGlzKSxILkxoKHRoaXMp
-LkMoIk4zPFlrLkssWWsuVj4iKSl9LAp4NDpmdW5jdGlvbihhKXtyZXR1cm4gSi56bCh0aGlzLmdWKCks
-YSl9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gSi5IbSh0aGlzLmdWKCkpfSwKZ2wwOmZ1bmN0aW9uKGEp
-e3JldHVybiBKLnVVKHRoaXMuZ1YoKSl9LAp3OmZ1bmN0aW9uKGEpe3JldHVybiBQLm5PKHRoaXMpfSwK
-JGlaMDoxfQpQLnlRLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYSxzPUguTGgo
-dCkKcy5DKCJZay5LIikuYihhKQpyZXR1cm4gbmV3IFAuTjMoYSx0LnEoMCxhKSxzLkMoIkA8WWsuSz4i
-KS5LcShzLkMoIllrLlYiKSkuQygiTjM8MSwyPiIpKX0sCiRTOmZ1bmN0aW9uKCl7cmV0dXJuIEguTGgo
-dGhpcy5hKS5DKCJOMzxZay5LLFlrLlY+KFlrLkspIil9fQpQLktQLnByb3RvdHlwZT17Clk6ZnVuY3Rp
-b24oYSxiLGMpe3ZhciB0PUguTGgodGhpcykKdC5kLmIoYikKdC5jaFsxXS5iKGMpCnRocm93IEguYihQ
-Lkw0KCJDYW5ub3QgbW9kaWZ5IHVubW9kaWZpYWJsZSBtYXAiKSl9fQpQLlBuLnByb3RvdHlwZT17CnE6
-ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5hLnEoMCxiKX0sClk6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0
-PUguTGgodGhpcykKdGhpcy5hLlkoMCx0LmQuYihiKSx0LmNoWzFdLmIoYykpfSwKeDQ6ZnVuY3Rpb24o
-YSl7cmV0dXJuIHRoaXMuYS54NChhKX0sCks6ZnVuY3Rpb24oYSxiKXt0aGlzLmEuSygwLEguTGgodGhp
-cykuQygifigxLDIpIikuYihiKSl9LApnbDA6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0
-LmdsMCh0KX0sCmdBOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpyZXR1cm4gdC5nQSh0KX0sCnc6ZnVu
-Y3Rpb24oYSl7cmV0dXJuIEouaih0aGlzLmEpfSwKZ1B1OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpy
-ZXR1cm4gdC5nUHUodCl9LAokaVowOjF9ClAuR2oucHJvdG90eXBlPXt9ClAubGYucHJvdG90eXBlPXsK
-dzpmdW5jdGlvbihhKXtyZXR1cm4gUC5XRSh0aGlzLCJ7IiwifSIpfX0KUC5Wai5wcm90b3R5cGU9eyRp
-YlE6MSwkaWNYOjEsJGl4dToxfQpQLlh2LnByb3RvdHlwZT17CkZWOmZ1bmN0aW9uKGEsYil7dmFyIHQK
-Zm9yKHQ9Si5JVChILkxoKHRoaXMpLkMoImNYPDE+IikuYihiKSk7dC5GKCk7KXRoaXMuaSgwLHQuZ2wo
-KSl9LAp3OmZ1bmN0aW9uKGEpe3JldHVybiBQLldFKHRoaXMsInsiLCJ9Iil9LApIOmZ1bmN0aW9uKGEs
-Yil7dmFyIHQscz1QLnJqKHRoaXMsdGhpcy5yLEguTGgodGhpcykuZCkKaWYoIXMuRigpKXJldHVybiIi
-CmlmKGI9PT0iIil7dD0iIgpkbyB0Kz1ILmQocy5kKQp3aGlsZShzLkYoKSl9ZWxzZXt0PUguZChzLmQp
-CmZvcig7cy5GKCk7KXQ9dCtiK0guZChzLmQpfXJldHVybiB0LmNoYXJDb2RlQXQoMCk9PTA/dDp0fSwK
-JGliUToxLAokaWNYOjEsCiRpeHU6MX0KUC5uWS5wcm90b3R5cGU9e30KUC5UQy5wcm90b3R5cGU9e30K
-UC5SVS5wcm90b3R5cGU9e30KUC51dy5wcm90b3R5cGU9ewpxOmZ1bmN0aW9uKGEsYil7dmFyIHQscz10
-aGlzLmIKaWYocz09bnVsbClyZXR1cm4gdGhpcy5jLnEoMCxiKQplbHNlIGlmKHR5cGVvZiBiIT0ic3Ry
-aW5nIilyZXR1cm4gbnVsbAplbHNle3Q9c1tiXQpyZXR1cm4gdHlwZW9mIHQ9PSJ1bmRlZmluZWQiP3Ro
-aXMuZmIoYik6dH19LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5iPT1udWxsP3RoaXMuYy5hOnRo
-aXMuQ2YoKS5sZW5ndGh9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZ0EodGhpcyk9PT0wfSwK
-Z1Y6ZnVuY3Rpb24oKXtpZih0aGlzLmI9PW51bGwpe3ZhciB0PXRoaXMuYwpyZXR1cm4gbmV3IEguaTUo
-dCxILkxoKHQpLkMoImk1PDE+IikpfXJldHVybiBuZXcgUC5pOCh0aGlzKX0sClk6ZnVuY3Rpb24oYSxi
-LGMpe3ZhciB0LHMscj10aGlzCmlmKHIuYj09bnVsbClyLmMuWSgwLGIsYykKZWxzZSBpZihyLng0KGIp
-KXt0PXIuYgp0W2JdPWMKcz1yLmEKaWYocz09bnVsbD90IT1udWxsOnMhPT10KXNbYl09bnVsbH1lbHNl
-IHIuWEsoKS5ZKDAsYixjKX0sCng0OmZ1bmN0aW9uKGEpe2lmKHRoaXMuYj09bnVsbClyZXR1cm4gdGhp
-cy5jLng0KGEpCnJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcy5h
-LGEpfSwKSzpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHA9dGhpcwp1LmNBLmIoYikKaWYocC5iPT1u
-dWxsKXJldHVybiBwLmMuSygwLGIpCnQ9cC5DZigpCmZvcihzPTA7czx0Lmxlbmd0aDsrK3Mpe3I9dFtz
-XQpxPXAuYltyXQppZih0eXBlb2YgcT09InVuZGVmaW5lZCIpe3E9UC5RZShwLmFbcl0pCnAuYltyXT1x
-fWIuJDIocixxKQppZih0IT09cC5jKXRocm93IEguYihQLmE0KHApKX19LApDZjpmdW5jdGlvbigpe3Zh
-ciB0PXUuai5iKHRoaXMuYykKaWYodD09bnVsbCl0PXRoaXMuYz1ILlZNKE9iamVjdC5rZXlzKHRoaXMu
-YSksdS5zKQpyZXR1cm4gdH0sClhLOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxvPXRoaXMKaWYoby5i
-PT1udWxsKXJldHVybiBvLmMKdD1QLkZsKHUuTix1LnopCnM9by5DZigpCmZvcihyPTA7cT1zLmxlbmd0
-aCxyPHE7KytyKXtwPXNbcl0KdC5ZKDAscCxvLnEoMCxwKSl9aWYocT09PTApQy5ObS5pKHMsbnVsbCkK
-ZWxzZSBDLk5tLnNBKHMsMCkKby5hPW8uYj1udWxsCnJldHVybiBvLmM9dH0sCmZiOmZ1bmN0aW9uKGEp
-e3ZhciB0CmlmKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcy5hLGEpKXJl
-dHVybiBudWxsCnQ9UC5RZSh0aGlzLmFbYV0pCnJldHVybiB0aGlzLmJbYV09dH19ClAuaTgucHJvdG90
-eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0LmdBKHQpfSwKRTpmdW5jdGlv
-bihhLGIpe3ZhciB0PXRoaXMuYQppZih0LmI9PW51bGwpdD10LmdWKCkuRSgwLGIpCmVsc2V7dD10LkNm
-KCkKaWYoYjwwfHxiPj10Lmxlbmd0aClyZXR1cm4gSC5PSCh0LGIpCnQ9dFtiXX1yZXR1cm4gdH0sCmdr
-ejpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKaWYodC5iPT1udWxsKXt0PXQuZ1YoKQp0PXQuZ2t6KHQp
-fWVsc2V7dD10LkNmKCkKdD1uZXcgSi5tMSh0LHQubGVuZ3RoLEgudDYodCkuQygibTE8MT4iKSl9cmV0
-dXJuIHR9LAp0ZzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmEueDQoYil9fQpQLkNWLnByb3RvdHlw
-ZT17CnlyOmZ1bmN0aW9uKGEsYTAsYTEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoLGcsZixl
-LGQsYyxiPSJJbnZhbGlkIGJhc2U2NCBlbmNvZGluZyBsZW5ndGggIgphMT1QLmpCKGEwLGExLGEubGVu
-Z3RoKQp0PSQuVjcoKQpmb3Iocz1hMCxyPXMscT1udWxsLHA9LTEsbz0tMSxuPTA7czxhMTtzPW0pe209
-cysxCmw9Qy54Qi5XKGEscykKaWYobD09PTM3KXtrPW0rMgppZihrPD1hMSl7aj1ILm9vKEMueEIuVyhh
-LG0pKQppPUgub28oQy54Qi5XKGEsbSsxKSkKaD1qKjE2K2ktKGkmMjU2KQppZihoPT09MzcpaD0tMQpt
-PWt9ZWxzZSBoPS0xfWVsc2UgaD1sCmlmKDA8PWgmJmg8PTEyNyl7aWYoaDwwfHxoPj10Lmxlbmd0aCly
-ZXR1cm4gSC5PSCh0LGgpCmc9dFtoXQppZihnPj0wKXtoPUMueEIubSgiQUJDREVGR0hJSktMTU5PUFFS
-U1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyIsZykKaWYoaD09PWwp
-Y29udGludWUKbD1ofWVsc2V7aWYoZz09PS0xKXtpZihwPDApe2Y9cT09bnVsbD9udWxsOnEuYS5sZW5n
-dGgKaWYoZj09bnVsbClmPTAKcD1mKyhzLXIpCm89c30rK24KaWYobD09PTYxKWNvbnRpbnVlfWw9aH1p
-ZihnIT09LTIpe2lmKHE9PW51bGwpcT1uZXcgUC5SbigiIikKcS5hKz1DLnhCLk5qKGEscixzKQpxLmEr
-PUguTHcobCkKcj1tCmNvbnRpbnVlfX10aHJvdyBILmIoUC5ycigiSW52YWxpZCBiYXNlNjQgZGF0YSIs
-YSxzKSl9aWYocSE9bnVsbCl7Zj1xLmErPUMueEIuTmooYSxyLGExKQplPWYubGVuZ3RoCmlmKHA+PTAp
-UC54TShhLG8sYTEscCxuLGUpCmVsc2V7ZD1DLmpuLnpZKGUtMSw0KSsxCmlmKGQ9PT0xKXRocm93IEgu
-YihQLnJyKGIsYSxhMSkpCmZvcig7ZDw0Oyl7Zis9Ij0iCnEuYT1mOysrZH19Zj1xLmEKcmV0dXJuIEMu
-eEIuaTcoYSxhMCxhMSxmLmNoYXJDb2RlQXQoMCk9PTA/ZjpmKX1jPWExLWEwCmlmKHA+PTApUC54TShh
-LG8sYTEscCxuLGMpCmVsc2V7ZD1DLmpuLnpZKGMsNCkKaWYoZD09PTEpdGhyb3cgSC5iKFAucnIoYixh
-LGExKSkKaWYoZD4xKWE9Qy54Qi5pNyhhLGExLGExLGQ9PT0yPyI9PSI6Ij0iKX1yZXR1cm4gYX19ClAu
-VTgucHJvdG90eXBlPXt9ClAuVWsucHJvdG90eXBlPXt9ClAud0kucHJvdG90eXBlPXt9ClAuWmkucHJv
-dG90eXBlPXt9ClAuVWQucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXt2YXIgdD1QLnAodGhpcy5hKQpy
-ZXR1cm4odGhpcy5iIT1udWxsPyJDb252ZXJ0aW5nIG9iamVjdCB0byBhbiBlbmNvZGFibGUgb2JqZWN0
-IGZhaWxlZDoiOiJDb252ZXJ0aW5nIG9iamVjdCBkaWQgbm90IHJldHVybiBhbiBlbmNvZGFibGUgb2Jq
-ZWN0OiIpKyIgIit0fX0KUC5LOC5wcm90b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3JldHVybiJDeWNsaWMg
-ZXJyb3IgaW4gSlNPTiBzdHJpbmdpZnkifX0KUC5ieS5wcm90b3R5cGU9ewpwVzpmdW5jdGlvbihhLGIs
-Yyl7dmFyIHQKdS5lcC5iKGMpCnQ9UC5CUyhiLHRoaXMuZ0hlKCkuYSkKcmV0dXJuIHR9LApPQjpmdW5j
-dGlvbihhLGIpe3ZhciB0CnUuYmMuYihiKQp0PVAudVgoYSx0aGlzLmdaRSgpLmIsbnVsbCkKcmV0dXJu
-IHR9LApnWkU6ZnVuY3Rpb24oKXtyZXR1cm4gQy5uWH0sCmdIZTpmdW5jdGlvbigpe3JldHVybiBDLkEz
-fX0KUC5vai5wcm90b3R5cGU9e30KUC5NeC5wcm90b3R5cGU9e30KUC5TaC5wcm90b3R5cGU9ewp2cDpm
-dW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbj1hLmxlbmd0aApmb3IodD1KLnJZKGEpLHM9dGhpcy5j
-LHI9MCxxPTA7cTxuOysrcSl7cD10LlcoYSxxKQppZihwPjkyKWNvbnRpbnVlCmlmKHA8MzIpe2lmKHE+
-cilzLmErPUMueEIuTmooYSxyLHEpCnI9cSsxCnMuYSs9SC5Mdyg5MikKc3dpdGNoKHApe2Nhc2UgODpz
-LmErPUguTHcoOTgpCmJyZWFrCmNhc2UgOTpzLmErPUguTHcoMTE2KQpicmVhawpjYXNlIDEwOnMuYSs9
-SC5MdygxMTApCmJyZWFrCmNhc2UgMTI6cy5hKz1ILkx3KDEwMikKYnJlYWsKY2FzZSAxMzpzLmErPUgu
-THcoMTE0KQpicmVhawpkZWZhdWx0OnMuYSs9SC5MdygxMTcpCnMuYSs9SC5Mdyg0OCkKcy5hKz1ILkx3
-KDQ4KQpvPXA+Pj40JjE1CnMuYSs9SC5MdyhvPDEwPzQ4K286ODcrbykKbz1wJjE1CnMuYSs9SC5Mdyhv
-PDEwPzQ4K286ODcrbykKYnJlYWt9fWVsc2UgaWYocD09PTM0fHxwPT09OTIpe2lmKHE+cilzLmErPUMu
-eEIuTmooYSxyLHEpCnI9cSsxCnMuYSs9SC5Mdyg5MikKcy5hKz1ILkx3KHApfX1pZihyPT09MClzLmEr
-PUguZChhKQplbHNlIGlmKHI8bilzLmErPXQuTmooYSxyLG4pfSwKSm46ZnVuY3Rpb24oYSl7dmFyIHQs
-cyxyLHEKZm9yKHQ9dGhpcy5hLHM9dC5sZW5ndGgscj0wO3I8czsrK3Ipe3E9dFtyXQppZihhPT1udWxs
-P3E9PW51bGw6YT09PXEpdGhyb3cgSC5iKG5ldyBQLks4KGEsbnVsbCkpfUMuTm0uaSh0LGEpfSwKaVU6
-ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscD10aGlzCmlmKHAudE0oYSkpcmV0dXJuCnAuSm4oYSkKdHJ5
-e3Q9cC5iLiQxKGEpCmlmKCFwLnRNKHQpKXtyPVAuR3koYSxudWxsLHAuZ1ZLKCkpCnRocm93IEguYihy
-KX1yPXAuYQppZigwPj1yLmxlbmd0aClyZXR1cm4gSC5PSChyLC0xKQpyLnBvcCgpfWNhdGNoKHEpe3M9
-SC5SdShxKQpyPVAuR3koYSxzLHAuZ1ZLKCkpCnRocm93IEguYihyKX19LAp0TTpmdW5jdGlvbihhKXt2
-YXIgdCxzLHI9dGhpcwppZih0eXBlb2YgYT09Im51bWJlciIpe2lmKCFpc0Zpbml0ZShhKSlyZXR1cm4h
-MQpyLmMuYSs9Qy5DRC53KGEpCnJldHVybiEwfWVsc2UgaWYoYT09PSEwKXtyLmMuYSs9InRydWUiCnJl
-dHVybiEwfWVsc2UgaWYoYT09PSExKXtyLmMuYSs9ImZhbHNlIgpyZXR1cm4hMH1lbHNlIGlmKGE9PW51
-bGwpe3IuYy5hKz0ibnVsbCIKcmV0dXJuITB9ZWxzZSBpZih0eXBlb2YgYT09InN0cmluZyIpe3Q9ci5j
-CnQuYSs9JyInCnIudnAoYSkKdC5hKz0nIicKcmV0dXJuITB9ZWxzZSBpZih1LmouYyhhKSl7ci5Kbihh
-KQpyLmxLKGEpCnQ9ci5hCmlmKDA+PXQubGVuZ3RoKXJldHVybiBILk9IKHQsLTEpCnQucG9wKCkKcmV0
-dXJuITB9ZWxzZSBpZih1LkcuYyhhKSl7ci5KbihhKQpzPXIuancoYSkKdD1yLmEKaWYoMD49dC5sZW5n
-dGgpcmV0dXJuIEguT0godCwtMSkKdC5wb3AoKQpyZXR1cm4gc31lbHNlIHJldHVybiExfSwKbEs6ZnVu
-Y3Rpb24oYSl7dmFyIHQscyxyPXRoaXMuYwpyLmErPSJbIgp0PUouVTYoYSkKaWYodC5nb3IoYSkpe3Ro
-aXMuaVUodC5xKGEsMCkpCmZvcihzPTE7czx0LmdBKGEpOysrcyl7ci5hKz0iLCIKdGhpcy5pVSh0LnEo
-YSxzKSl9fXIuYSs9Il0ifSwKanc6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG49dGhpcyxtPXt9
-CmlmKGEuZ2wwKGEpKXtuLmMuYSs9Int9IgpyZXR1cm4hMH10PWEuZ0EoYSkqMgpzPW5ldyBBcnJheSh0
-KQpzLmZpeGVkJGxlbmd0aD1BcnJheQpyPW0uYT0wCm0uYj0hMAphLksoMCxuZXcgUC50aShtLHMpKQpp
-ZighbS5iKXJldHVybiExCnE9bi5jCnEuYSs9InsiCmZvcihwPSciJztyPHQ7cis9MixwPScsIicpe3Eu
-YSs9cApuLnZwKEgueShzW3JdKSkKcS5hKz0nIjonCm89cisxCmlmKG8+PXQpcmV0dXJuIEguT0gocyxv
-KQpuLmlVKHNbb10pfXEuYSs9In0iCnJldHVybiEwfX0KUC50aS5wcm90b3R5cGU9ewokMjpmdW5jdGlv
-bihhLGIpe3ZhciB0LHMKaWYodHlwZW9mIGEhPSJzdHJpbmciKXRoaXMuYS5iPSExCnQ9dGhpcy5iCnM9
-dGhpcy5hCkMuTm0uWSh0LHMuYSsrLGEpCkMuTm0uWSh0LHMuYSsrLGIpfSwKJFM6NH0KUC50dS5wcm90
-b3R5cGU9ewpnVks6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmMuYQpyZXR1cm4gdC5jaGFyQ29kZUF0KDAp
-PT0wP3Q6dH19ClAudTUucHJvdG90eXBlPXsKZ1pFOmZ1bmN0aW9uKCl7cmV0dXJuIEMuUWt9fQpQLkUz
-LnByb3RvdHlwZT17CldKOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj1QLmpCKDAsbnVsbCxhLmxlbmd0aCks
-cT1yLTAKaWYocT09PTApcmV0dXJuIG5ldyBVaW50OEFycmF5KDApCnQ9bmV3IFVpbnQ4QXJyYXkocSoz
-KQpzPW5ldyBQLlJ3KHQpCmlmKHMuR3goYSwwLHIpIT09cilzLk82KEouYTYoYSxyLTEpLDApCnJldHVy
-biBuZXcgVWludDhBcnJheSh0LnN1YmFycmF5KDAsSC5yTSgwLHMuYix0Lmxlbmd0aCkpKX19ClAuUncu
-cHJvdG90eXBlPXsKTzY6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRoaXMscj1zLmMscT1zLmIscD1xKzEs
-bz1yLmxlbmd0aAppZigoYiY2NDUxMik9PT01NjMyMCl7dD02NTUzNisoKGEmMTAyMyk8PDEwKXxiJjEw
-MjMKcy5iPXAKaWYocT49bylyZXR1cm4gSC5PSChyLHEpCnJbcV09MjQwfHQ+Pj4xOApxPXMuYj1wKzEK
-aWYocD49bylyZXR1cm4gSC5PSChyLHApCnJbcF09MTI4fHQ+Pj4xMiY2MwpwPXMuYj1xKzEKaWYocT49
-bylyZXR1cm4gSC5PSChyLHEpCnJbcV09MTI4fHQ+Pj42JjYzCnMuYj1wKzEKaWYocD49bylyZXR1cm4g
-SC5PSChyLHApCnJbcF09MTI4fHQmNjMKcmV0dXJuITB9ZWxzZXtzLmI9cAppZihxPj1vKXJldHVybiBI
-Lk9IKHIscSkKcltxXT0yMjR8YT4+PjEyCnE9cy5iPXArMQppZihwPj1vKXJldHVybiBILk9IKHIscCkK
-cltwXT0xMjh8YT4+PjYmNjMKcy5iPXErMQppZihxPj1vKXJldHVybiBILk9IKHIscSkKcltxXT0xMjh8
-YSY2MwpyZXR1cm4hMX19LApHeDpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEscCxvLG4sbT10aGlz
-CmlmKGIhPT1jJiYoQy54Qi5tKGEsYy0xKSY2NDUxMik9PT01NTI5NiktLWMKZm9yKHQ9bS5jLHM9dC5s
-ZW5ndGgscj1iO3I8YzsrK3Ipe3E9Qy54Qi5XKGEscikKaWYocTw9MTI3KXtwPW0uYgppZihwPj1zKWJy
-ZWFrCm0uYj1wKzEKdFtwXT1xfWVsc2UgaWYoKHEmNjQ1MTIpPT09NTUyOTYpe2lmKG0uYiszPj1zKWJy
-ZWFrCm89cisxCmlmKG0uTzYocSxDLnhCLlcoYSxvKSkpcj1vfWVsc2UgaWYocTw9MjA0Nyl7cD1tLmIK
-bj1wKzEKaWYobj49cylicmVhawptLmI9bgppZihwPj1zKXJldHVybiBILk9IKHQscCkKdFtwXT0xOTJ8
-cT4+PjYKbS5iPW4rMQp0W25dPTEyOHxxJjYzfWVsc2V7cD1tLmIKaWYocCsyPj1zKWJyZWFrCm49bS5i
-PXArMQppZihwPj1zKXJldHVybiBILk9IKHQscCkKdFtwXT0yMjR8cT4+PjEyCnA9bS5iPW4rMQppZihu
-Pj1zKXJldHVybiBILk9IKHQsbikKdFtuXT0xMjh8cT4+PjYmNjMKbS5iPXArMQppZihwPj1zKXJldHVy
-biBILk9IKHQscCkKdFtwXT0xMjh8cSY2M319cmV0dXJuIHJ9fQpQLkdZLnByb3RvdHlwZT17CldKOmZ1
-bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbAp1LkwuYihhKQp0PVAua3koITEsYSwwLG51bGwp
-CmlmKHQhPW51bGwpcmV0dXJuIHQKcz1QLmpCKDAsbnVsbCxKLkhtKGEpKQpyPVAuY1AoYSwwLHMpCmlm
-KHI+MCl7cT1QLkhNKGEsMCxyKQppZihyPT09cylyZXR1cm4gcQpwPW5ldyBQLlJuKHEpCm89cgpuPSEx
-fWVsc2V7bz0wCnA9bnVsbApuPSEwfWlmKHA9PW51bGwpcD1uZXcgUC5SbigiIikKbT1uZXcgUC5ieigh
-MSxwKQptLmM9bgptLk1FKGEsbyxzKQppZihtLmU+MCl7SC52aChQLnJyKCJVbmZpbmlzaGVkIFVURi04
-IG9jdGV0IHNlcXVlbmNlIixhLHMpKQpwLmErPUguTHcoNjU1MzMpCm0uZj1tLmU9bS5kPTB9bD1wLmEK
-cmV0dXJuIGwuY2hhckNvZGVBdCgwKT09MD9sOmx9fQpQLmJ6LnByb3RvdHlwZT17Ck1FOmZ1bmN0aW9u
-KGEsYixjKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaD10aGlzLGc9IkJhZCBVVEYtOCBlbmNv
-ZGluZyAweCIKdS5MLmIoYSkKdD1oLmQKcz1oLmUKcj1oLmYKaC5mPWguZT1oLmQ9MAokbGFiZWwwJDA6
-Zm9yKHE9Si5VNihhKSxwPWguYixvPWI7ITA7bz1qKXskbGFiZWwxJDE6aWYocz4wKXtkb3tpZihvPT09
-YylicmVhayAkbGFiZWwwJDAKbj1xLnEoYSxvKQppZih0eXBlb2YgbiE9PSJudW1iZXIiKXJldHVybiBu
-LnpNKCkKaWYoKG4mMTkyKSE9PTEyOCl7bT1QLnJyKGcrQy5qbi5XWihuLDE2KSxhLG8pCnRocm93IEgu
-YihtKX1lbHNle3Q9KHQ8PDZ8biY2Myk+Pj4wOy0tczsrK299fXdoaWxlKHM+MCkKbT1yLTEKaWYobTww
-fHxtPj00KXJldHVybiBILk9IKEMuR2IsbSkKaWYodDw9Qy5HYlttXSl7bT1QLnJyKCJPdmVybG9uZyBl
-bmNvZGluZyBvZiAweCIrQy5qbi5XWih0LDE2KSxhLG8tci0xKQp0aHJvdyBILmIobSl9aWYodD4xMTE0
-MTExKXttPVAucnIoIkNoYXJhY3RlciBvdXRzaWRlIHZhbGlkIFVuaWNvZGUgcmFuZ2U6IDB4IitDLmpu
-LldaKHQsMTYpLGEsby1yLTEpCnRocm93IEguYihtKX1pZighaC5jfHx0IT09NjUyNzkpcC5hKz1ILkx3
-KHQpCmguYz0hMX1mb3IobT1vPGM7bTspe2w9UC5jUChhLG8sYykKaWYobD4wKXtoLmM9ITEKaz1vK2wK
-cC5hKz1QLkhNKGEsbyxrKQppZihrPT09YylicmVha31lbHNlIGs9bwpqPWsrMQpuPXEucShhLGspCmlm
-KHR5cGVvZiBuIT09Im51bWJlciIpcmV0dXJuIG4uSigpCmlmKG48MCl7aT1QLnJyKCJOZWdhdGl2ZSBV
-VEYtOCBjb2RlIHVuaXQ6IC0weCIrQy5qbi5XWigtbiwxNiksYSxqLTEpCnRocm93IEguYihpKX1lbHNl
-e2lmKChuJjIyNCk9PT0xOTIpe3Q9biYzMQpzPTEKcj0xCmNvbnRpbnVlICRsYWJlbDAkMH1pZigobiYy
-NDApPT09MjI0KXt0PW4mMTUKcz0yCnI9Mgpjb250aW51ZSAkbGFiZWwwJDB9aWYoKG4mMjQ4KT09PTI0
-MCYmbjwyNDUpe3Q9biY3CnM9MwpyPTMKY29udGludWUgJGxhYmVsMCQwfWk9UC5ycihnK0Muam4uV1oo
-biwxNiksYSxqLTEpCnRocm93IEguYihpKX19YnJlYWsgJGxhYmVsMCQwfWlmKHM+MCl7aC5kPXQKaC5l
-PXMKaC5mPXJ9fX0KUC5XRi5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3ZhciB0LHMscgp1LmZv
-LmIoYSkKdD10aGlzLmIKcz10aGlzLmEKdC5hKz1zLmEKcj10LmErPUguZChhLmEpCnQuYT1yKyI6ICIK
-dC5hKz1QLnAoYikKcy5hPSIsICJ9LAokUzo0Mn0KUC5hMi5wcm90b3R5cGU9e30KUC5pUC5wcm90b3R5
-cGU9ewpETjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKcmV0dXJuIGIgaW5zdGFuY2Vv
-ZiBQLmlQJiZ0aGlzLmE9PT1iLmEmJiEwfSwKZ2lPOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpyZXR1
-cm4odF5DLmpuLndHKHQsMzApKSYxMDczNzQxODIzfSwKdzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLHM9
-UC5HcShILnRKKHQpKSxyPVAuaDAoSC5OUyh0KSkscT1QLmgwKEguakEodCkpLHA9UC5oMChILklYKHQp
-KSxvPVAuaDAoSC5jaCh0KSksbj1QLmgwKEguSmQodCkpLG09UC5WeChILm8xKHQpKSxsPXMrIi0iK3Ir
-Ii0iK3ErIiAiK3ArIjoiK28rIjoiK24rIi4iK20KcmV0dXJuIGx9fQpQLkNQLnByb3RvdHlwZT17fQpQ
-LlhTLnByb3RvdHlwZT17fQpQLkM2LnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5h
-CmlmKHQhPW51bGwpcmV0dXJuIkFzc2VydGlvbiBmYWlsZWQ6ICIrUC5wKHQpCnJldHVybiJBc3NlcnRp
-b24gZmFpbGVkIn19ClAubi5wcm90b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3JldHVybiJUaHJvdyBvZiBu
-dWxsLiJ9fQpQLnUucHJvdG90eXBlPXsKZ1o6ZnVuY3Rpb24oKXtyZXR1cm4iSW52YWxpZCBhcmd1bWVu
-dCIrKCF0aGlzLmE/IihzKSI6IiIpfSwKZ3U6ZnVuY3Rpb24oKXtyZXR1cm4iIn0sCnc6ZnVuY3Rpb24o
-YSl7dmFyIHQscyxyLHEscD10aGlzLG89cC5jLG49byE9bnVsbD8iICgiK28rIikiOiIiCm89cC5kCnQ9
-bz09bnVsbD8iIjoiOiAiK0guZChvKQpzPXAuZ1ooKStuK3QKaWYoIXAuYSlyZXR1cm4gcwpyPXAuZ3Uo
-KQpxPVAucChwLmIpCnJldHVybiBzK3IrIjogIitxfX0KUC5iSi5wcm90b3R5cGU9ewpnWjpmdW5jdGlv
-bigpe3JldHVybiJSYW5nZUVycm9yIn0sCmd1OmZ1bmN0aW9uKCl7dmFyIHQscyxyPXRoaXMuZQppZihy
-PT1udWxsKXtyPXRoaXMuZgp0PXIhPW51bGw/IjogTm90IGxlc3MgdGhhbiBvciBlcXVhbCB0byAiK0gu
-ZChyKToiIn1lbHNle3M9dGhpcy5mCmlmKHM9PW51bGwpdD0iOiBOb3QgZ3JlYXRlciB0aGFuIG9yIGVx
-dWFsIHRvICIrSC5kKHIpCmVsc2UgaWYocz5yKXQ9IjogTm90IGluIHJhbmdlICIrSC5kKHIpKyIuLiIr
-SC5kKHMpKyIsIGluY2x1c2l2ZSIKZWxzZSB0PXM8cj8iOiBWYWxpZCB2YWx1ZSByYW5nZSBpcyBlbXB0
-eSI6IjogT25seSB2YWxpZCB2YWx1ZSBpcyAiK0guZChyKX1yZXR1cm4gdH19ClAuZVkucHJvdG90eXBl
-PXsKZ1o6ZnVuY3Rpb24oKXtyZXR1cm4iUmFuZ2VFcnJvciJ9LApndTpmdW5jdGlvbigpe3ZhciB0LHM9
-SC5TYyh0aGlzLmIpCmlmKHR5cGVvZiBzIT09Im51bWJlciIpcmV0dXJuIHMuSigpCmlmKHM8MClyZXR1
-cm4iOiBpbmRleCBtdXN0IG5vdCBiZSBuZWdhdGl2ZSIKdD10aGlzLmYKaWYodD09PTApcmV0dXJuIjog
-bm8gaW5kaWNlcyBhcmUgdmFsaWQiCnJldHVybiI6IGluZGV4IHNob3VsZCBiZSBsZXNzIHRoYW4gIitI
-LmQodCl9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5mfX0KUC5tcC5wcm90b3R5cGU9ewp3OmZ1
-bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbD10aGlzLGs9e30saj1uZXcgUC5SbigiIikKay5h
-PSIiCmZvcih0PWwuYyxzPXQubGVuZ3RoLHI9MCxxPSIiLHA9IiI7cjxzOysrcixwPSIsICIpe289dFty
-XQpqLmE9cStwCnE9ai5hKz1QLnAobykKay5hPSIsICJ9bC5kLksoMCxuZXcgUC5XRihrLGopKQpuPVAu
-cChsLmEpCm09ai53KDApCnQ9Ik5vU3VjaE1ldGhvZEVycm9yOiBtZXRob2Qgbm90IGZvdW5kOiAnIitI
-LmQobC5iLmEpKyInXG5SZWNlaXZlcjogIituKyJcbkFyZ3VtZW50czogWyIrbSsiXSIKcmV0dXJuIHR9
-fQpQLnViLnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIlVuc3VwcG9ydGVkIG9wZXJhdGlv
-bjogIit0aGlzLmF9fQpQLmRzLnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJl
-dHVybiB0IT1udWxsPyJVbmltcGxlbWVudGVkRXJyb3I6ICIrdDoiVW5pbXBsZW1lbnRlZEVycm9yIn19
-ClAubGoucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4iQmFkIHN0YXRlOiAiK3RoaXMuYX19
-ClAuVVYucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKaWYodD09bnVsbClyZXR1
-cm4iQ29uY3VycmVudCBtb2RpZmljYXRpb24gZHVyaW5nIGl0ZXJhdGlvbi4iCnJldHVybiJDb25jdXJy
-ZW50IG1vZGlmaWNhdGlvbiBkdXJpbmcgaXRlcmF0aW9uOiAiK1AucCh0KSsiLiJ9fQpQLms1LnByb3Rv
-dHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIk91dCBvZiBNZW1vcnkifSwKJGlYUzoxfQpQLktZLnBy
-b3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIlN0YWNrIE92ZXJmbG93In0sCiRpWFM6MX0KUC5j
-LnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0PT1udWxsPyJSZWFk
-aW5nIHN0YXRpYyB2YXJpYWJsZSBkdXJpbmcgaXRzIGluaXRpYWxpemF0aW9uIjoiUmVhZGluZyBzdGF0
-aWMgdmFyaWFibGUgJyIrdCsiJyBkdXJpbmcgaXRzIGluaXRpYWxpemF0aW9uIn19ClAuQ0QucHJvdG90
-eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4iRXhjZXB0aW9uOiAiK3RoaXMuYX0sCiRpUno6MX0KUC5h
-RS5wcm90b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrLGosaSxoPXRo
-aXMuYSxnPWghPW51bGwmJiIiIT09aD8iRm9ybWF0RXhjZXB0aW9uOiAiK0guZChoKToiRm9ybWF0RXhj
-ZXB0aW9uIixmPXRoaXMuYyxlPXRoaXMuYgppZih0eXBlb2YgZT09InN0cmluZyIpe2lmKGYhPW51bGwp
-aD1mPDB8fGY+ZS5sZW5ndGgKZWxzZSBoPSExCmlmKGgpZj1udWxsCmlmKGY9PW51bGwpe3Q9ZS5sZW5n
-dGg+Nzg/Qy54Qi5OaihlLDAsNzUpKyIuLi4iOmUKcmV0dXJuIGcrIlxuIit0fWZvcihzPTEscj0wLHE9
-ITEscD0wO3A8ZjsrK3Ape289Qy54Qi5XKGUscCkKaWYobz09PTEwKXtpZihyIT09cHx8IXEpKytzCnI9
-cCsxCnE9ITF9ZWxzZSBpZihvPT09MTMpeysrcwpyPXArMQpxPSEwfX1nPXM+MT9nKygiIChhdCBsaW5l
-ICIrcysiLCBjaGFyYWN0ZXIgIisoZi1yKzEpKyIpXG4iKTpnKygiIChhdCBjaGFyYWN0ZXIgIisoZisx
-KSsiKVxuIikKbj1lLmxlbmd0aApmb3IocD1mO3A8bjsrK3Ape289Qy54Qi5tKGUscCkKaWYobz09PTEw
-fHxvPT09MTMpe249cApicmVha319aWYobi1yPjc4KWlmKGYtcjw3NSl7bT1yKzc1Cmw9cgprPSIiCmo9
-Ii4uLiJ9ZWxzZXtpZihuLWY8NzUpe2w9bi03NQptPW4Kaj0iIn1lbHNle2w9Zi0zNgptPWYrMzYKaj0i
-Li4uIn1rPSIuLi4ifWVsc2V7bT1uCmw9cgprPSIiCmo9IiJ9aT1DLnhCLk5qKGUsbCxtKQpyZXR1cm4g
-ZytrK2kraisiXG4iK0MueEIuSXgoIiAiLGYtbCtrLmxlbmd0aCkrIl5cbiJ9ZWxzZSByZXR1cm4gZiE9
-bnVsbD9nKygiIChhdCBvZmZzZXQgIitILmQoZikrIikiKTpnfSwKJGlSejoxfQpQLkVILnByb3RvdHlw
-ZT17fQpQLktOLnByb3RvdHlwZT17fQpQLmNYLnByb3RvdHlwZT17CkUyOmZ1bmN0aW9uKGEsYixjKXt2
-YXIgdD1ILkxoKHRoaXMpCnJldHVybiBILksxKHRoaXMsdC5LcShjKS5DKCIxKGNYLkUpIikuYihiKSx0
-LkMoImNYLkUiKSxjKX0sCmV2OmZ1bmN0aW9uKGEsYil7dmFyIHQ9SC5MaCh0aGlzKQpyZXR1cm4gbmV3
-IEguVTUodGhpcyx0LkMoImEyKGNYLkUpIikuYihiKSx0LkMoIlU1PGNYLkU+IikpfSwKZ0E6ZnVuY3Rp
-b24oYSl7dmFyIHQscz10aGlzLmdreih0aGlzKQpmb3IodD0wO3MuRigpOykrK3QKcmV0dXJuIHR9LApn
-bDA6ZnVuY3Rpb24oYSl7cmV0dXJuIXRoaXMuZ2t6KHRoaXMpLkYoKX0sCmdyODpmdW5jdGlvbihhKXt2
-YXIgdCxzPXRoaXMuZ2t6KHRoaXMpCmlmKCFzLkYoKSl0aHJvdyBILmIoSC5XcCgpKQp0PXMuZ2woKQpp
-ZihzLkYoKSl0aHJvdyBILmIoSC5kVSgpKQpyZXR1cm4gdH0sCkU6ZnVuY3Rpb24oYSxiKXt2YXIgdCxz
-LHIKUC5rMShiLCJpbmRleCIpCmZvcih0PXRoaXMuZ2t6KHRoaXMpLHM9MDt0LkYoKTspe3I9dC5nbCgp
-CmlmKGI9PT1zKXJldHVybiByOysrc310aHJvdyBILmIoUC5DZihiLHRoaXMsImluZGV4IixudWxsLHMp
-KX0sCnc6ZnVuY3Rpb24oYSl7cmV0dXJuIFAuRVAodGhpcywiKCIsIikiKX19ClAuQW4ucHJvdG90eXBl
-PXt9ClAuek0ucHJvdG90eXBlPXskaWJROjEsJGljWDoxfQpQLlowLnByb3RvdHlwZT17fQpQLk4zLnBy
-b3RvdHlwZT17Cnc6ZnVuY3Rpb24oYSl7cmV0dXJuIk1hcEVudHJ5KCIrSC5kKHRoaXMuYSkrIjogIitI
-LmQodGhpcy5iKSsiKSJ9fQpQLmM4LnByb3RvdHlwZT17CmdpTzpmdW5jdGlvbihhKXtyZXR1cm4gUC5r
-LnByb3RvdHlwZS5naU8uY2FsbCh0aGlzLHRoaXMpfSwKdzpmdW5jdGlvbihhKXtyZXR1cm4ibnVsbCJ9
-fQpQLkZLLnByb3RvdHlwZT17fQpQLmsucHJvdG90eXBlPXtjb25zdHJ1Y3RvcjpQLmssJGlrOjEsCkRO
-OmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXM9PT1ifSwKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiBILmVR
-KHRoaXMpfSwKdzpmdW5jdGlvbihhKXtyZXR1cm4iSW5zdGFuY2Ugb2YgJyIrSC5kKEguTSh0aGlzKSkr
-IicifSwKZTc6ZnVuY3Rpb24oYSxiKXt1Lm8uYihiKQp0aHJvdyBILmIoUC5scih0aGlzLGIuZ1dhKCks
-Yi5nbmQoKSxiLmdWbSgpKSl9LAp0b1N0cmluZzpmdW5jdGlvbigpe3JldHVybiB0aGlzLncodGhpcyl9
-fQpQLk9kLnByb3RvdHlwZT17fQpQLmliLnByb3RvdHlwZT17JGlPZDoxfQpQLnh1LnByb3RvdHlwZT17
-fQpQLkd6LnByb3RvdHlwZT17fQpQLnFVLnByb3RvdHlwZT17JGl2WDoxfQpQLlJuLnByb3RvdHlwZT17
-CmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEubGVuZ3RofSwKdzpmdW5jdGlvbihhKXt2YXIgdD10
-aGlzLmEKcmV0dXJuIHQuY2hhckNvZGVBdCgwKT09MD90OnR9LAokaUJMOjF9ClAuR0QucHJvdG90eXBl
-PXt9ClAubjEucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscQp1LmYuYihhKQpI
-LnkoYikKdD1KLnJZKGIpLk9ZKGIsIj0iKQppZih0PT09LTEpe2lmKGIhPT0iIilhLlkoMCxQLmt1KGIs
-MCxiLmxlbmd0aCx0aGlzLmEsITApLCIiKX1lbHNlIGlmKHQhPT0wKXtzPUMueEIuTmooYiwwLHQpCnI9
-Qy54Qi5HKGIsdCsxKQpxPXRoaXMuYQphLlkoMCxQLmt1KHMsMCxzLmxlbmd0aCxxLCEwKSxQLmt1KHIs
-MCxyLmxlbmd0aCxxLCEwKSl9cmV0dXJuIGF9LAokUzoxOX0KUC5jUy5wcm90b3R5cGU9ewokMjpmdW5j
-dGlvbihhLGIpe3Rocm93IEguYihQLnJyKCJJbGxlZ2FsIElQdjQgYWRkcmVzcywgIithLHRoaXMuYSxi
-KSl9LAokUzo0Nn0KUC5WQy5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3Rocm93IEguYihQLnJy
-KCJJbGxlZ2FsIElQdjYgYWRkcmVzcywgIithLHRoaXMuYSxiKSl9LAokMTpmdW5jdGlvbihhKXtyZXR1
-cm4gdGhpcy4kMihhLG51bGwpfSwKJFM6NDd9ClAuSlQucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxi
-KXt2YXIgdAppZihiLWE+NCl0aGlzLmEuJDIoImFuIElQdjYgcGFydCBjYW4gb25seSBjb250YWluIGEg
-bWF4aW11bSBvZiA0IGhleCBkaWdpdHMiLGEpCnQ9UC5RQShDLnhCLk5qKHRoaXMuYixhLGIpLG51bGws
-MTYpCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuSigpCmlmKHQ8MHx8dD42NTUzNSl0aGlz
-LmEuJDIoImVhY2ggcGFydCBtdXN0IGJlIGluIHRoZSByYW5nZSBvZiBgMHgwLi4weEZGRkZgIixhKQpy
-ZXR1cm4gdH0sCiRTOjQ4fQpQLkRuLnByb3RvdHlwZT17CmdrdTpmdW5jdGlvbigpe3JldHVybiB0aGlz
-LmJ9LApnSmY6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5jCmlmKHQ9PW51bGwpcmV0dXJuIiIKaWYoQy54
-Qi5uKHQsIlsiKSlyZXR1cm4gQy54Qi5Oaih0LDEsdC5sZW5ndGgtMSkKcmV0dXJuIHR9LApndHA6ZnVu
-Y3Rpb24oYSl7dmFyIHQ9dGhpcy5kCmlmKHQ9PW51bGwpcmV0dXJuIFAud0sodGhpcy5hKQpyZXR1cm4g
-dH0sCmd0UDpmdW5jdGlvbigpe3ZhciB0PXRoaXMuZgpyZXR1cm4gdD09bnVsbD8iIjp0fSwKZ0thOmZ1
-bmN0aW9uKCl7dmFyIHQ9dGhpcy5yCnJldHVybiB0PT1udWxsPyIiOnR9LApubTpmdW5jdGlvbihhLGIp
-e3ZhciB0LHMscixxLHAsbyxuLG0sbD10aGlzCnUuWC5iKG51bGwpCnUuay5iKGIpCnQ9bC5hCnM9dD09
-PSJmaWxlIgpyPWwuYgpxPWwuZApwPWwuYwppZighKHAhPW51bGwpKXA9ci5sZW5ndGghPT0wfHxxIT1u
-dWxsfHxzPyIiOm51bGwKbz1sLmUKaWYoIXMpbj1wIT1udWxsJiZvLmxlbmd0aCE9PTAKZWxzZSBuPSEw
-CmlmKG4mJiFDLnhCLm4obywiLyIpKW89Ii8iK28KbT1QLmxlKG51bGwsMCwwLGIpCnJldHVybiBuZXcg
-UC5Ebih0LHIscCxxLG8sbSxsLnIpfSwKZ0ZqOmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzLngKaWYocyE9
-bnVsbClyZXR1cm4gcwp0PXRoaXMuZQppZih0Lmxlbmd0aCE9PTAmJkMueEIuVyh0LDApPT09NDcpdD1D
-LnhCLkcodCwxKQpzPXQ9PT0iIj9DLnhEOlAuQUYobmV3IEguQTgoSC5WTSh0LnNwbGl0KCIvIiksdS5z
-KSx1LmRPLmIoUC5QSCgpKSx1LmRvKSx1Lk4pCnRoaXMuc282KHMpCnJldHVybiBzfSwKZ2hZOmZ1bmN0
-aW9uKCl7dmFyIHQscz10aGlzCmlmKHMuUT09bnVsbCl7dD1zLmYKcy5zUkgobmV3IFAuR2ooUC5XWCh0
-PT1udWxsPyIiOnQpLHUuVykpfXJldHVybiBzLlF9LApKaDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixx
-LHAsbwpmb3IodD0wLHM9MDtDLnhCLlFpKGIsIi4uLyIscyk7KXtzKz0zOysrdH1yPUMueEIuY24oYSwi
-LyIpCndoaWxlKCEwKXtpZighKHI+MCYmdD4wKSlicmVhawpxPUMueEIuUGsoYSwiLyIsci0xKQppZihx
-PDApYnJlYWsKcD1yLXEKbz1wIT09MgppZighb3x8cD09PTMpaWYoQy54Qi5tKGEscSsxKT09PTQ2KW89
-IW98fEMueEIubShhLHErMik9PT00NgplbHNlIG89ITEKZWxzZSBvPSExCmlmKG8pYnJlYWs7LS10CnI9
-cX1yZXR1cm4gQy54Qi5pNyhhLHIrMSxudWxsLEMueEIuRyhiLHMtMyp0KSl9LApaSTpmdW5jdGlvbihh
-KXtyZXR1cm4gdGhpcy5tUyhQLmhLKGEpKX0sCm1TOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxu
-LG0sbCxrPXRoaXMsaj1udWxsCmlmKGEuZ0ZpKCkubGVuZ3RoIT09MCl7dD1hLmdGaSgpCmlmKGEuZ2Nq
-KCkpe3M9YS5na3UoKQpyPWEuZ0pmKGEpCnE9YS5neEEoKT9hLmd0cChhKTpqfWVsc2V7cT1qCnI9cQpz
-PSIifXA9UC54ZShhLmdJaShhKSkKbz1hLmdRRCgpP2EuZ3RQKCk6an1lbHNle3Q9ay5hCmlmKGEuZ2Nq
-KCkpe3M9YS5na3UoKQpyPWEuZ0pmKGEpCnE9UC53QihhLmd4QSgpP2EuZ3RwKGEpOmosdCkKcD1QLnhl
-KGEuZ0lpKGEpKQpvPWEuZ1FEKCk/YS5ndFAoKTpqfWVsc2V7cz1rLmIKcj1rLmMKcT1rLmQKaWYoYS5n
-SWkoYSk9PT0iIil7cD1rLmUKbz1hLmdRRCgpP2EuZ3RQKCk6ay5mfWVsc2V7aWYoYS5ndFQoKSlwPVAu
-eGUoYS5nSWkoYSkpCmVsc2V7bj1rLmUKaWYobi5sZW5ndGg9PT0wKWlmKHI9PW51bGwpcD10Lmxlbmd0
-aD09PTA/YS5nSWkoYSk6UC54ZShhLmdJaShhKSkKZWxzZSBwPVAueGUoIi8iK2EuZ0lpKGEpKQplbHNl
-e209ay5KaChuLGEuZ0lpKGEpKQpsPXQubGVuZ3RoPT09MAppZighbHx8ciE9bnVsbHx8Qy54Qi5uKG4s
-Ii8iKSlwPVAueGUobSkKZWxzZSBwPVAud0YobSwhbHx8ciE9bnVsbCl9fW89YS5nUUQoKT9hLmd0UCgp
-Omp9fX1yZXR1cm4gbmV3IFAuRG4odCxzLHIscSxwLG8sYS5nWjgoKT9hLmdLYSgpOmopfSwKZ2NqOmZ1
-bmN0aW9uKCl7cmV0dXJuIHRoaXMuYyE9bnVsbH0sCmd4QTpmdW5jdGlvbigpe3JldHVybiB0aGlzLmQh
-PW51bGx9LApnUUQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5mIT1udWxsfSwKZ1o4OmZ1bmN0aW9uKCl7
-cmV0dXJuIHRoaXMuciE9bnVsbH0sCmd0VDpmdW5jdGlvbigpe3JldHVybiBDLnhCLm4odGhpcy5lLCIv
-Iil9LAp0NDpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzLHE9ci5hCmlmKHEhPT0iIiYmcSE9PSJmaWxl
-Iil0aHJvdyBILmIoUC5MNCgiQ2Fubm90IGV4dHJhY3QgYSBmaWxlIHBhdGggZnJvbSBhICIrSC5kKHEp
-KyIgVVJJIikpCnE9ci5mCmlmKChxPT1udWxsPyIiOnEpIT09IiIpdGhyb3cgSC5iKFAuTDQoIkNhbm5v
-dCBleHRyYWN0IGEgZmlsZSBwYXRoIGZyb20gYSBVUkkgd2l0aCBhIHF1ZXJ5IGNvbXBvbmVudCIpKQpx
-PXIucgppZigocT09bnVsbD8iIjpxKSE9PSIiKXRocm93IEguYihQLkw0KCJDYW5ub3QgZXh0cmFjdCBh
-IGZpbGUgcGF0aCBmcm9tIGEgVVJJIHdpdGggYSBmcmFnbWVudCBjb21wb25lbnQiKSkKdD0kLndRKCkK
-aWYoSC5vVCh0KSlxPVAubW4ocikKZWxzZXtpZihyLmMhPW51bGwmJnIuZ0pmKHIpIT09IiIpSC52aChQ
-Lkw0KCJDYW5ub3QgZXh0cmFjdCBhIG5vbi1XaW5kb3dzIGZpbGUgcGF0aCBmcm9tIGEgZmlsZSBVUkkg
-d2l0aCBhbiBhdXRob3JpdHkiKSkKcz1yLmdGaigpClAua0UocywhMSkKcT1QLnZnKEMueEIubihyLmUs
-Ii8iKT8iLyI6IiIscywiLyIpCnE9cS5jaGFyQ29kZUF0KDApPT0wP3E6cX1yZXR1cm4gcX0sCnc6ZnVu
-Y3Rpb24oYSl7dmFyIHQscyxyLHE9dGhpcyxwPXEueQppZihwPT1udWxsKXtwPXEuYQp0PXAubGVuZ3Ro
-IT09MD9wKyI6IjoiIgpzPXEuYwpyPXM9PW51bGwKaWYoIXJ8fHA9PT0iZmlsZSIpe3A9dCsiLy8iCnQ9
-cS5iCmlmKHQubGVuZ3RoIT09MClwPXArdCsiQCIKaWYoIXIpcCs9cwp0PXEuZAppZih0IT1udWxsKXA9
-cCsiOiIrSC5kKHQpfWVsc2UgcD10CnArPXEuZQp0PXEuZgppZih0IT1udWxsKXA9cCsiPyIrdAp0PXEu
-cgppZih0IT1udWxsKXA9cCsiIyIrdApwPXEueT1wLmNoYXJDb2RlQXQoMCk9PTA/cDpwfXJldHVybiBw
-fSwKRE46ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9dGhpcwppZihiPT1udWxsKXJldHVybiExCmlmKHI9
-PT1iKXJldHVybiEwCmlmKHUudi5jKGIpKWlmKHIuYT09Yi5nRmkoKSlpZihyLmMhPW51bGw9PT1iLmdj
-aigpKWlmKHIuYj09Yi5na3UoKSlpZihyLmdKZihyKT09Yi5nSmYoYikpaWYoci5ndHAocik9PWIuZ3Rw
-KGIpKWlmKHIuZT09PWIuZ0lpKGIpKXt0PXIuZgpzPXQ9PW51bGwKaWYoIXM9PT1iLmdRRCgpKXtpZihz
-KXQ9IiIKaWYodD09PWIuZ3RQKCkpe3Q9ci5yCnM9dD09bnVsbAppZighcz09PWIuZ1o4KCkpe2lmKHMp
-dD0iIgp0PXQ9PT1iLmdLYSgpfWVsc2UgdD0hMX1lbHNlIHQ9ITF9ZWxzZSB0PSExfWVsc2UgdD0hMQpl
-bHNlIHQ9ITEKZWxzZSB0PSExCmVsc2UgdD0hMQplbHNlIHQ9ITEKZWxzZSB0PSExCmVsc2UgdD0hMQpy
-ZXR1cm4gdH0sCmdpTzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLnoKcmV0dXJuIHQ9PW51bGw/dGhpcy56
-PUMueEIuZ2lPKHRoaXMudygwKSk6dH0sCnNvNjpmdW5jdGlvbihhKXt0aGlzLng9dS5hLmIoYSl9LApz
-Ukg6ZnVuY3Rpb24oYSl7dGhpcy5RPXUuZi5iKGEpfSwKJGlpRDoxLApnRmk6ZnVuY3Rpb24oKXtyZXR1
-cm4gdGhpcy5hfSwKZ0lpOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmV9fQpQLmUxLnByb3RvdHlwZT17
-CiQxOmZ1bmN0aW9uKGEpe3Rocm93IEguYihQLnJyKCJJbnZhbGlkIHBvcnQiLHRoaXMuYSx0aGlzLmIr
-MSkpfSwKJFM6MTN9ClAuTlkucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQ9IklsbGVnYWwg
-cGF0aCBjaGFyYWN0ZXIgIgpILnkoYSkKaWYoSi56bChhLCIvIikpaWYodGhpcy5hKXRocm93IEguYihQ
-LnhZKHQrYSkpCmVsc2UgdGhyb3cgSC5iKFAuTDQodCthKSl9LAokUzoxM30KUC5SWi5wcm90b3R5cGU9
-ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gUC5lUChDLlpKLEgueShhKSxDLnhNLCExKX0sCiRTOjV9ClAu
-TUUucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdD10aGlzLmIscz10aGlzLmEKdC5hKz1z
-LmEKcy5hPSImIgpzPXQuYSs9SC5kKFAuZVAoQy5GMyxhLEMueE0sITApKQppZihiIT1udWxsJiZiLmxl
-bmd0aCE9PTApe3QuYT1zKyI9Igp0LmErPUguZChQLmVQKEMuRjMsYixDLnhNLCEwKSl9fSwKJFM6MjJ9
-ClAueTUucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzCkgueShhKQppZihiPT1udWxs
-fHx0eXBlb2YgYj09InN0cmluZyIpdGhpcy5hLiQyKGEsSC55KGIpKQplbHNlIGZvcih0PUouSVQodS5S
-LmIoYikpLHM9dGhpcy5hO3QuRigpOylzLiQyKGEsSC55KHQuZ2woKSkpfSwKJFM6MTJ9ClAuUEUucHJv
-dG90eXBlPXsKZ2xSOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10aGlzLG89bnVsbCxuPXAuYwppZihu
-IT1udWxsKXJldHVybiBuCm49cC5iCmlmKDA+PW4ubGVuZ3RoKXJldHVybiBILk9IKG4sMCkKdD1wLmEK
-bj1uWzBdKzEKcz1DLnhCLlhVKHQsIj8iLG4pCnI9dC5sZW5ndGgKaWYocz49MCl7cT1QLlBJKHQscysx
-LHIsQy5WQywhMSkKcj1zfWVsc2UgcT1vCnJldHVybiBwLmM9bmV3IFAucWUoImRhdGEiLG8sbyxvLFAu
-UEkodCxuLHIsQy5XZCwhMSkscSxvKX0sCnc6ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLmIKaWYoMD49
-cy5sZW5ndGgpcmV0dXJuIEguT0gocywwKQp0PXRoaXMuYQpyZXR1cm4gc1swXT09PS0xPyJkYXRhOiIr
-dDp0fX0KUC5xMy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFVpbnQ4QXJyYXko
-OTYpfSwKJFM6MjN9ClAueUkucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdD10aGlzLmEK
-aWYoYT49dC5sZW5ndGgpcmV0dXJuIEguT0godCxhKQp0PXRbYV0KSi5DTSh0LDAsOTYsYikKcmV0dXJu
-IHR9LAokUzoyNH0KUC5jNi5wcm90b3R5cGU9ewokMzpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEK
-Zm9yKHQ9Yi5sZW5ndGgscz1hLmxlbmd0aCxyPTA7cjx0Oysrcil7cT1DLnhCLlcoYixyKV45NgppZihx
-Pj1zKXJldHVybiBILk9IKGEscSkKYVtxXT1jfX19ClAucWQucHJvdG90eXBlPXsKJDM6ZnVuY3Rpb24o
-YSxiLGMpe3ZhciB0LHMscixxCmZvcih0PUMueEIuVyhiLDApLHM9Qy54Qi5XKGIsMSkscj1hLmxlbmd0
-aDt0PD1zOysrdCl7cT0odF45Nik+Pj4wCmlmKHE+PXIpcmV0dXJuIEguT0goYSxxKQphW3FdPWN9fX0K
-UC5VZi5wcm90b3R5cGU9ewpnY2o6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jPjB9LApneEE6ZnVuY3Rp
-b24oKXt2YXIgdCxzCmlmKHRoaXMuYz4wKXt0PXRoaXMuZAppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJl
-dHVybiB0LmgoKQpzPXRoaXMuZQppZih0eXBlb2YgcyE9PSJudW1iZXIiKXJldHVybiBILnBZKHMpCnM9
-dCsxPHMKdD1zfWVsc2UgdD0hMQpyZXR1cm4gdH0sCmdRRDpmdW5jdGlvbigpe3ZhciB0PXRoaXMuZgpp
-Zih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiB0LkooKQpyZXR1cm4gdDx0aGlzLnJ9LApnWjg6ZnVu
-Y3Rpb24oKXtyZXR1cm4gdGhpcy5yPHRoaXMuYS5sZW5ndGh9LApnTnc6ZnVuY3Rpb24oKXtyZXR1cm4g
-dGhpcy5iPT09NCYmQy54Qi5uKHRoaXMuYSwiZmlsZSIpfSwKZ3ZoOmZ1bmN0aW9uKCl7cmV0dXJuIHRo
-aXMuYj09PTQmJkMueEIubih0aGlzLmEsImh0dHAiKX0sCmdSZTpmdW5jdGlvbigpe3JldHVybiB0aGlz
-LmI9PT01JiZDLnhCLm4odGhpcy5hLCJodHRwcyIpfSwKZ3RUOmZ1bmN0aW9uKCl7cmV0dXJuIEMueEIu
-UWkodGhpcy5hLCIvIix0aGlzLmUpfSwKZ0ZpOmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzLHI9InBhY2th
-Z2UiLHE9cy5iCmlmKHE8PTApcmV0dXJuIiIKdD1zLngKaWYodCE9bnVsbClyZXR1cm4gdAppZihzLmd2
-aCgpKXE9cy54PSJodHRwIgplbHNlIGlmKHMuZ1JlKCkpe3MueD0iaHR0cHMiCnE9Imh0dHBzIn1lbHNl
-IGlmKHMuZ053KCkpe3MueD0iZmlsZSIKcT0iZmlsZSJ9ZWxzZSBpZihxPT09NyYmQy54Qi5uKHMuYSxy
-KSl7cy54PXIKcT1yfWVsc2V7cT1DLnhCLk5qKHMuYSwwLHEpCnMueD1xfXJldHVybiBxfSwKZ2t1OmZ1
-bmN0aW9uKCl7dmFyIHQ9dGhpcy5jLHM9dGhpcy5iKzMKcmV0dXJuIHQ+cz9DLnhCLk5qKHRoaXMuYSxz
-LHQtMSk6IiJ9LApnSmY6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5jCnJldHVybiB0PjA/Qy54Qi5Oaih0
-aGlzLmEsdCx0aGlzLmQpOiIifSwKZ3RwOmZ1bmN0aW9uKGEpe3ZhciB0LHM9dGhpcwppZihzLmd4QSgp
-KXt0PXMuZAppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJldHVybiB0LmgoKQpyZXR1cm4gUC5RQShDLnhC
-Lk5qKHMuYSx0KzEscy5lKSxudWxsLG51bGwpfWlmKHMuZ3ZoKCkpcmV0dXJuIDgwCmlmKHMuZ1JlKCkp
-cmV0dXJuIDQ0MwpyZXR1cm4gMH0sCmdJaTpmdW5jdGlvbihhKXtyZXR1cm4gQy54Qi5Oaih0aGlzLmEs
-dGhpcy5lLHRoaXMuZil9LApndFA6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmYscz10aGlzLnIKaWYodHlw
-ZW9mIHQhPT0ibnVtYmVyIilyZXR1cm4gdC5KKCkKcmV0dXJuIHQ8cz9DLnhCLk5qKHRoaXMuYSx0KzEs
-cyk6IiJ9LApnS2E6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLnIscz10aGlzLmEKcmV0dXJuIHQ8cy5sZW5n
-dGg/Qy54Qi5HKHMsdCsxKToiIn0sCmdGajpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzLmUscT10aGlz
-LmYscD10aGlzLmEKaWYoQy54Qi5RaShwLCIvIixyKSl7aWYodHlwZW9mIHIhPT0ibnVtYmVyIilyZXR1
-cm4gci5oKCk7KytyfWlmKHI9PXEpcmV0dXJuIEMueEQKdD1ILlZNKFtdLHUucykKcz1yCndoaWxlKCEw
-KXtpZih0eXBlb2YgcyE9PSJudW1iZXIiKXJldHVybiBzLkooKQppZih0eXBlb2YgcSE9PSJudW1iZXIi
-KXJldHVybiBILnBZKHEpCmlmKCEoczxxKSlicmVhawppZihDLnhCLm0ocCxzKT09PTQ3KXtDLk5tLmko
-dCxDLnhCLk5qKHAscixzKSkKcj1zKzF9KytzfUMuTm0uaSh0LEMueEIuTmoocCxyLHEpKQpyZXR1cm4g
-UC5BRih0LHUuTil9LApnaFk6ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmYKaWYodHlwZW9mIHQhPT0ibnVt
-YmVyIilyZXR1cm4gdC5KKCkKaWYodD49dGhpcy5yKXJldHVybiBDLldPCnJldHVybiBuZXcgUC5HaihQ
-LldYKHRoaXMuZ3RQKCkpLHUuVyl9LAprWDpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuZAppZih0eXBl
-b2YgcyE9PSJudW1iZXIiKXJldHVybiBzLmgoKQp0PXMrMQpyZXR1cm4gdCthLmxlbmd0aD09PXRoaXMu
-ZSYmQy54Qi5RaSh0aGlzLmEsYSx0KX0sCk45OmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQucixyPXQu
-YQppZihzPj1yLmxlbmd0aClyZXR1cm4gdApyZXR1cm4gbmV3IFAuVWYoQy54Qi5OaihyLDAscyksdC5i
-LHQuYyx0LmQsdC5lLHQuZixzLHQueCl9LApubTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbyxu
-LG0sbCxrLGo9dGhpcyxpPW51bGwKdS5YLmIobnVsbCkKdS5rLmIoYikKdD1qLmdGaSgpCnM9dD09PSJm
-aWxlIgpyPWouYwpxPXI+MD9DLnhCLk5qKGouYSxqLmIrMyxyKToiIgpwPWouZ3hBKCk/ai5ndHAoaik6
-aQpyPWouYwppZihyPjApbz1DLnhCLk5qKGouYSxyLGouZCkKZWxzZSBvPXEubGVuZ3RoIT09MHx8cCE9
-bnVsbHx8cz8iIjppCnI9ai5hCm49Qy54Qi5OaihyLGouZSxqLmYpCmlmKCFzKW09byE9bnVsbCYmbi5s
-ZW5ndGghPT0wCmVsc2UgbT0hMAppZihtJiYhQy54Qi5uKG4sIi8iKSluPSIvIituCmw9UC5sZShpLDAs
-MCxiKQptPWoucgprPW08ci5sZW5ndGg/Qy54Qi5HKHIsbSsxKTppCnJldHVybiBuZXcgUC5Ebih0LHEs
-byxwLG4sbCxrKX0sClpJOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLm1TKFAuaEsoYSkpfSwKbVM6ZnVu
-Y3Rpb24oYSl7aWYoYSBpbnN0YW5jZW9mIFAuVWYpcmV0dXJuIHRoaXMudTEodGhpcyxhKQpyZXR1cm4g
-dGhpcy52cygpLm1TKGEpfSwKdTE6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxq
-LGksaCxnLGYsZT1iLmIKaWYoZT4wKXJldHVybiBiCnQ9Yi5jCmlmKHQ+MCl7cz1hLmIKaWYoczw9MCly
-ZXR1cm4gYgppZihhLmdOdygpKXI9Yi5lIT1iLmYKZWxzZSBpZihhLmd2aCgpKXI9IWIua1goIjgwIikK
-ZWxzZSByPSFhLmdSZSgpfHwhYi5rWCgiNDQzIikKaWYocil7cT1zKzEKcD1DLnhCLk5qKGEuYSwwLHEp
-K0MueEIuRyhiLmEsZSsxKQplPWIuZAppZih0eXBlb2YgZSE9PSJudW1iZXIiKXJldHVybiBlLmgoKQpv
-PWIuZQppZih0eXBlb2YgbyE9PSJudW1iZXIiKXJldHVybiBvLmgoKQpuPWIuZgppZih0eXBlb2YgbiE9
-PSJudW1iZXIiKXJldHVybiBuLmgoKQpyZXR1cm4gbmV3IFAuVWYocCxzLHQrcSxlK3EsbytxLG4rcSxi
-LnIrcSxhLngpfWVsc2UgcmV0dXJuIHRoaXMudnMoKS5tUyhiKX1tPWIuZQplPWIuZgppZihtPT1lKXt0
-PWIucgppZih0eXBlb2YgZSE9PSJudW1iZXIiKXJldHVybiBlLkooKQppZihlPHQpe3M9YS5mCmlmKHR5
-cGVvZiBzIT09Im51bWJlciIpcmV0dXJuIHMuSE4oKQpxPXMtZQpyZXR1cm4gbmV3IFAuVWYoQy54Qi5O
-aihhLmEsMCxzKStDLnhCLkcoYi5hLGUpLGEuYixhLmMsYS5kLGEuZSxlK3EsdCtxLGEueCl9ZT1iLmEK
-aWYodDxlLmxlbmd0aCl7cz1hLnIKcmV0dXJuIG5ldyBQLlVmKEMueEIuTmooYS5hLDAscykrQy54Qi5H
-KGUsdCksYS5iLGEuYyxhLmQsYS5lLGEuZix0KyhzLXQpLGEueCl9cmV0dXJuIGEuTjkoKX10PWIuYQpp
-ZihDLnhCLlFpKHQsIi8iLG0pKXtzPWEuZQppZih0eXBlb2YgcyE9PSJudW1iZXIiKXJldHVybiBzLkhO
-KCkKaWYodHlwZW9mIG0hPT0ibnVtYmVyIilyZXR1cm4gSC5wWShtKQpxPXMtbQpwPUMueEIuTmooYS5h
-LDAscykrQy54Qi5HKHQsbSkKaWYodHlwZW9mIGUhPT0ibnVtYmVyIilyZXR1cm4gZS5oKCkKcmV0dXJu
-IG5ldyBQLlVmKHAsYS5iLGEuYyxhLmQscyxlK3EsYi5yK3EsYS54KX1sPWEuZQprPWEuZgppZihsPT1r
-JiZhLmM+MCl7Zm9yKDtDLnhCLlFpKHQsIi4uLyIsbSk7KXtpZih0eXBlb2YgbSE9PSJudW1iZXIiKXJl
-dHVybiBtLmgoKQptKz0zfWlmKHR5cGVvZiBsIT09Im51bWJlciIpcmV0dXJuIGwuSE4oKQppZih0eXBl
-b2YgbSE9PSJudW1iZXIiKXJldHVybiBILnBZKG0pCnE9bC1tKzEKcD1DLnhCLk5qKGEuYSwwLGwpKyIv
-IitDLnhCLkcodCxtKQppZih0eXBlb2YgZSE9PSJudW1iZXIiKXJldHVybiBlLmgoKQpyZXR1cm4gbmV3
-IFAuVWYocCxhLmIsYS5jLGEuZCxsLGUrcSxiLnIrcSxhLngpfWo9YS5hCmZvcihpPWw7Qy54Qi5RaShq
-LCIuLi8iLGkpOyl7aWYodHlwZW9mIGkhPT0ibnVtYmVyIilyZXR1cm4gaS5oKCkKaSs9M31oPTAKd2hp
-bGUoITApe2lmKHR5cGVvZiBtIT09Im51bWJlciIpcmV0dXJuIG0uaCgpCmc9bSszCmlmKHR5cGVvZiBl
-IT09Im51bWJlciIpcmV0dXJuIEgucFkoZSkKaWYoIShnPD1lJiZDLnhCLlFpKHQsIi4uLyIsbSkpKWJy
-ZWFrOysraAptPWd9Zj0iIgp3aGlsZSghMCl7aWYodHlwZW9mIGshPT0ibnVtYmVyIilyZXR1cm4gay5v
-cygpCmlmKHR5cGVvZiBpIT09Im51bWJlciIpcmV0dXJuIEgucFkoaSkKaWYoIShrPmkpKWJyZWFrOy0t
-awppZihDLnhCLm0oaixrKT09PTQ3KXtpZihoPT09MCl7Zj0iLyIKYnJlYWt9LS1oCmY9Ii8ifX1pZihr
-PT09aSYmYS5iPD0wJiYhQy54Qi5RaShqLCIvIixsKSl7bS09aCozCmY9IiJ9cT1rLW0rZi5sZW5ndGgK
-cmV0dXJuIG5ldyBQLlVmKEMueEIuTmooaiwwLGspK2YrQy54Qi5HKHQsbSksYS5iLGEuYyxhLmQsbCxl
-K3EsYi5yK3EsYS54KX0sCnQ0OmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10aGlzCmlmKHAuYj49MCYm
-IXAuZ053KCkpdGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBleHRyYWN0IGEgZmlsZSBwYXRoIGZyb20gYSAi
-K0guZChwLmdGaSgpKSsiIFVSSSIpKQp0PXAuZgpzPXAuYQppZih0eXBlb2YgdCE9PSJudW1iZXIiKXJl
-dHVybiB0LkooKQppZih0PHMubGVuZ3RoKXtpZih0PHAucil0aHJvdyBILmIoUC5MNCgiQ2Fubm90IGV4
-dHJhY3QgYSBmaWxlIHBhdGggZnJvbSBhIFVSSSB3aXRoIGEgcXVlcnkgY29tcG9uZW50IikpCnRocm93
-IEguYihQLkw0KCJDYW5ub3QgZXh0cmFjdCBhIGZpbGUgcGF0aCBmcm9tIGEgVVJJIHdpdGggYSBmcmFn
-bWVudCBjb21wb25lbnQiKSl9cj0kLndRKCkKaWYoSC5vVChyKSl0PVAubW4ocCkKZWxzZXtxPXAuZApp
-Zih0eXBlb2YgcSE9PSJudW1iZXIiKXJldHVybiBILnBZKHEpCmlmKHAuYzxxKUgudmgoUC5MNCgiQ2Fu
-bm90IGV4dHJhY3QgYSBub24tV2luZG93cyBmaWxlIHBhdGggZnJvbSBhIGZpbGUgVVJJIHdpdGggYW4g
-YXV0aG9yaXR5IikpCnQ9Qy54Qi5OaihzLHAuZSx0KX1yZXR1cm4gdH0sCmdpTzpmdW5jdGlvbihhKXt2
-YXIgdD10aGlzLnkKcmV0dXJuIHQ9PW51bGw/dGhpcy55PUMueEIuZ2lPKHRoaXMuYSk6dH0sCkROOmZ1
-bmN0aW9uKGEsYil7aWYoYj09bnVsbClyZXR1cm4hMQppZih0aGlzPT09YilyZXR1cm4hMApyZXR1cm4g
-dS52LmMoYikmJnRoaXMuYT09PWIudygwKX0sCnZzOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPW51bGws
-cj10LmdGaSgpLHE9dC5na3UoKSxwPXQuYz4wP3QuZ0pmKHQpOnMsbz10Lmd4QSgpP3QuZ3RwKHQpOnMs
-bj10LmEsbT10LmYsbD1DLnhCLk5qKG4sdC5lLG0pLGs9dC5yCmlmKHR5cGVvZiBtIT09Im51bWJlciIp
-cmV0dXJuIG0uSigpCm09bTxrP3QuZ3RQKCk6cwpyZXR1cm4gbmV3IFAuRG4ocixxLHAsbyxsLG0sazxu
-Lmxlbmd0aD90LmdLYSgpOnMpfSwKdzpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hfSwKJGlpRDoxfQpQ
-LnFlLnByb3RvdHlwZT17fQpXLnFFLnByb3RvdHlwZT17fQpXLkdoLnByb3RvdHlwZT17Cnc6ZnVuY3Rp
-b24oYSl7cmV0dXJuIFN0cmluZyhhKX0sCiRpR2g6MX0KVy5mWS5wcm90b3R5cGU9ewp3OmZ1bmN0aW9u
-KGEpe3JldHVybiBTdHJpbmcoYSl9fQpXLm5CLnByb3RvdHlwZT17JGluQjoxfQpXLkF6LnByb3RvdHlw
-ZT17JGlBejoxfQpXLlFQLnByb3RvdHlwZT17JGlRUDoxfQpXLm54LnByb3RvdHlwZT17CmdBOmZ1bmN0
-aW9uKGEpe3JldHVybiBhLmxlbmd0aH19Clcub0oucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7cmV0
-dXJuIGEubGVuZ3RofX0KVy5pZC5wcm90b3R5cGU9e30KVy5RRi5wcm90b3R5cGU9e30KVy5OaC5wcm90
-b3R5cGU9ewp3OmZ1bmN0aW9uKGEpe3JldHVybiBTdHJpbmcoYSl9fQpXLklCLnByb3RvdHlwZT17Cnc6
-ZnVuY3Rpb24oYSl7cmV0dXJuIlJlY3RhbmdsZSAoIitILmQoYS5sZWZ0KSsiLCAiK0guZChhLnRvcCkr
-IikgIitILmQoYS53aWR0aCkrIiB4ICIrSC5kKGEuaGVpZ2h0KX0sCkROOmZ1bmN0aW9uKGEsYil7aWYo
-Yj09bnVsbClyZXR1cm4hMQpyZXR1cm4gdS5xLmMoYikmJmEubGVmdD09PWIubGVmdCYmYS50b3A9PT1i
-LnRvcCYmYS53aWR0aD09PWIud2lkdGgmJmEuaGVpZ2h0PT09Yi5oZWlnaHR9LApnaU86ZnVuY3Rpb24o
-YSl7cmV0dXJuIFcuckUoQy5DRC5naU8oYS5sZWZ0KSxDLkNELmdpTyhhLnRvcCksQy5DRC5naU8oYS53
-aWR0aCksQy5DRC5naU8oYS5oZWlnaHQpKX0sCiRpdG46MX0KVy5uNy5wcm90b3R5cGU9ewpnQTpmdW5j
-dGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9fQpXLnd6LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3Jl
-dHVybiB0aGlzLmEubGVuZ3RofSwKcTpmdW5jdGlvbihhLGIpe3ZhciB0CkguU2MoYikKdD10aGlzLmEK
-aWYoYjwwfHxiPj10Lmxlbmd0aClyZXR1cm4gSC5PSCh0LGIpCnJldHVybiB0aGlzLiR0aS5kLmIodFti
-XSl9LApZOmZ1bmN0aW9uKGEsYixjKXt0aGlzLiR0aS5kLmIoYykKdGhyb3cgSC5iKFAuTDQoIkNhbm5v
-dCBtb2RpZnkgbGlzdCIpKX19ClcuY3YucHJvdG90eXBlPXsKZ1FnOmZ1bmN0aW9uKGEpe3JldHVybiBu
-ZXcgVy5pNyhhKX0sCmdQOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgVy5JNChhKX0sCnNQOmZ1bmN0aW9u
-KGEsYil7dmFyIHQKdS5YLmIoYikKdD10aGlzLmdQKGEpCnQuVjEoMCkKdC5GVigwLGIpfSwKdzpmdW5j
-dGlvbihhKXtyZXR1cm4gYS5sb2NhbE5hbWV9LApGRjpmdW5jdGlvbihhKXt2YXIgdD0hIWEuc2Nyb2xs
-SW50b1ZpZXdJZk5lZWRlZAppZih0KWEuc2Nyb2xsSW50b1ZpZXdJZk5lZWRlZCgpCmVsc2UgYS5zY3Jv
-bGxJbnRvVmlldygpfSwKbno6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgdCxzPXRoaXMucjYoYSxjLGQs
-ZSkKc3dpdGNoKGIudG9Mb3dlckNhc2UoKSl7Y2FzZSJiZWZvcmViZWdpbiI6YS5wYXJlbnROb2RlLmlu
-c2VydEJlZm9yZShzLGEpCmJyZWFrCmNhc2UiYWZ0ZXJiZWdpbiI6dD1hLmNoaWxkTm9kZXMKYS5pbnNl
-cnRCZWZvcmUocyx0Lmxlbmd0aD4wP3RbMF06bnVsbCkKYnJlYWsKY2FzZSJiZWZvcmVlbmQiOmEuYXBw
-ZW5kQ2hpbGQocykKYnJlYWsKY2FzZSJhZnRlcmVuZCI6YS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShz
-LGEubmV4dFNpYmxpbmcpCmJyZWFrCmRlZmF1bHQ6SC52aChQLnhZKCJJbnZhbGlkIHBvc2l0aW9uICIr
-YikpfX0sCnI2OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMscixxCmlmKGM9PW51bGwpe2lmKGQ9PW51
-bGwpe3Q9JC5sdAppZih0PT1udWxsKXt0PUguVk0oW10sdS5pKQpzPW5ldyBXLnZEKHQpCkMuTm0uaSh0
-LFcuVHcobnVsbCkpCkMuTm0uaSh0LFcuQmwoKSkKJC5sdD1zCmQ9c31lbHNlIGQ9dH10PSQuRVUKaWYo
-dD09bnVsbCl7dD1uZXcgVy5LbyhkKQokLkVVPXQKYz10fWVsc2V7dC5hPWQKYz10fX1lbHNlIGlmKGQh
-PW51bGwpdGhyb3cgSC5iKFAueFkoInZhbGlkYXRvciBjYW4gb25seSBiZSBwYXNzZWQgaWYgdHJlZVNh
-bml0aXplciBpcyBudWxsIikpCmlmKCQueG89PW51bGwpe3Q9ZG9jdW1lbnQKcz10LmltcGxlbWVudGF0
-aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgiIikKJC54bz1zCiQuQk89cy5jcmVhdGVSYW5nZSgpCnM9JC54
-by5jcmVhdGVFbGVtZW50KCJiYXNlIikKdS5jUi5iKHMpCnMuaHJlZj10LmJhc2VVUkkKJC54by5oZWFk
-LmFwcGVuZENoaWxkKHMpfXQ9JC54bwppZih0LmJvZHk9PW51bGwpe3M9dC5jcmVhdGVFbGVtZW50KCJi
-b2R5IikKdC5ib2R5PXUuWS5iKHMpfXQ9JC54bwppZih1LlkuYyhhKSlyPXQuYm9keQplbHNle3I9dC5j
-cmVhdGVFbGVtZW50KGEudGFnTmFtZSkKJC54by5ib2R5LmFwcGVuZENoaWxkKHIpfWlmKCJjcmVhdGVD
-b250ZXh0dWFsRnJhZ21lbnQiIGluIHdpbmRvdy5SYW5nZS5wcm90b3R5cGUmJiFDLk5tLnRnKEMuU3Es
-YS50YWdOYW1lKSl7JC5CTy5zZWxlY3ROb2RlQ29udGVudHMocikKcT0kLkJPLmNyZWF0ZUNvbnRleHR1
-YWxGcmFnbWVudChiKX1lbHNle3IuaW5uZXJIVE1MPWIKcT0kLnhvLmNyZWF0ZURvY3VtZW50RnJhZ21l
-bnQoKQpmb3IoO3Q9ci5maXJzdENoaWxkLHQhPW51bGw7KXEuYXBwZW5kQ2hpbGQodCl9dD0kLnhvLmJv
-ZHkKaWYocj09bnVsbD90IT1udWxsOnIhPT10KUouTHQocikKYy5QbihxKQpkb2N1bWVudC5hZG9wdE5v
-ZGUocSkKcmV0dXJuIHF9LApBSDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIHRoaXMucjYoYSxiLGMsbnVs
-bCl9LApzaGY6ZnVuY3Rpb24oYSxiKXt0aGlzLllDKGEsYil9LApwazpmdW5jdGlvbihhLGIsYyl7YS50
-ZXh0Q29udGVudD1udWxsCmEuYXBwZW5kQ2hpbGQodGhpcy5yNihhLGIsbnVsbCxjKSl9LApZQzpmdW5j
-dGlvbihhLGIpe3JldHVybiB0aGlzLnBrKGEsYixudWxsKX0sCmdWbDpmdW5jdGlvbihhKXtyZXR1cm4g
-bmV3IFcuZXUoYSwiY2xpY2siLCExLHUuUSl9LAokaWN2OjEsCmduczpmdW5jdGlvbihhKXtyZXR1cm4g
-YS50YWdOYW1lfX0KVy5Ddi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdS5oLmModS5B
-LmIoYSkpfSwKJFM6MjV9ClcuZWEucHJvdG90eXBlPXskaWVhOjF9ClcuRDAucHJvdG90eXBlPXsKT246
-ZnVuY3Rpb24oYSxiLGMsZCl7dS5VLmIoYykKaWYoYyE9bnVsbCl0aGlzLnYoYSxiLGMsZCl9LApCOmZ1
-bmN0aW9uKGEsYixjKXtyZXR1cm4gdGhpcy5PbihhLGIsYyxudWxsKX0sCnY6ZnVuY3Rpb24oYSxiLGMs
-ZCl7cmV0dXJuIGEuYWRkRXZlbnRMaXN0ZW5lcihiLEgudFIodS5VLmIoYyksMSksZCl9LAokaUQwOjF9
-ClcuaEgucHJvdG90eXBlPXskaWhIOjF9ClcuaDQucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7cmV0
-dXJuIGEubGVuZ3RofX0KVy5ici5wcm90b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5n
-dGh9fQpXLlZiLnByb3RvdHlwZT17fQpXLk83LnByb3RvdHlwZT17CmVvOmZ1bmN0aW9uKGEsYixjLGQp
-e3JldHVybiBhLm9wZW4oYixjLCEwKX0sCiRpTzc6MX0KVy53YS5wcm90b3R5cGU9e30KVy5TZy5wcm90
-b3R5cGU9eyRpU2c6MX0KVy51OC5wcm90b3R5cGU9ewpnRHI6ZnVuY3Rpb24oYSl7aWYoIm9yaWdpbiIg
-aW4gYSlyZXR1cm4gYS5vcmlnaW4KcmV0dXJuIEguZChhLnByb3RvY29sKSsiLy8iK0guZChhLmhvc3Qp
-fSwKdzpmdW5jdGlvbihhKXtyZXR1cm4gU3RyaW5nKGEpfSwKJGl1ODoxfQpXLkFqLnByb3RvdHlwZT17
-JGlBajoxfQpXLmU3LnByb3RvdHlwZT17CmdyODpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEscz10LmNo
-aWxkTm9kZXMubGVuZ3RoCmlmKHM9PT0wKXRocm93IEguYihQLlBWKCJObyBlbGVtZW50cyIpKQppZihz
-PjEpdGhyb3cgSC5iKFAuUFYoIk1vcmUgdGhhbiBvbmUgZWxlbWVudCIpKQpyZXR1cm4gdC5maXJzdENo
-aWxkfSwKRlY6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscQp1LmVoLmIoYikKdD1iLmEKcz10aGlzLmEK
-aWYodCE9PXMpZm9yKHI9dC5jaGlsZE5vZGVzLmxlbmd0aCxxPTA7cTxyOysrcSlzLmFwcGVuZENoaWxk
-KHQuZmlyc3RDaGlsZCkKcmV0dXJufSwKWTpmdW5jdGlvbihhLGIsYyl7dmFyIHQscwp1LkEuYihjKQp0
-PXRoaXMuYQpzPXQuY2hpbGROb2RlcwppZihiPDB8fGI+PXMubGVuZ3RoKXJldHVybiBILk9IKHMsYikK
-dC5yZXBsYWNlQ2hpbGQoYyxzW2JdKX0sCmdrejpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEuY2hpbGRO
-b2RlcwpyZXR1cm4gbmV3IFcuVzkodCx0Lmxlbmd0aCxILnpLKHQpLkMoIlc5PEdtLkU+IikpfSwKZ0E6
-ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5jaGlsZE5vZGVzLmxlbmd0aH0sCnE6ZnVuY3Rpb24oYSxi
-KXt2YXIgdApILlNjKGIpCnQ9dGhpcy5hLmNoaWxkTm9kZXMKaWYoYjwwfHxiPj10Lmxlbmd0aClyZXR1
-cm4gSC5PSCh0LGIpCnJldHVybiB0W2JdfX0KVy51SC5wcm90b3R5cGU9ewp3ZzpmdW5jdGlvbihhKXt2
-YXIgdD1hLnBhcmVudE5vZGUKaWYodCE9bnVsbCl0LnJlbW92ZUNoaWxkKGEpfSwKRDQ6ZnVuY3Rpb24o
-YSl7dmFyIHQKZm9yKDt0PWEuZmlyc3RDaGlsZCx0IT1udWxsOylhLnJlbW92ZUNoaWxkKHQpfSwKdzpm
-dW5jdGlvbihhKXt2YXIgdD1hLm5vZGVWYWx1ZQpyZXR1cm4gdD09bnVsbD90aGlzLlUoYSk6dH0sCiRp
-dUg6MX0KVy5CSC5wcm90b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApxOmZ1
-bmN0aW9uKGEsYil7SC5TYyhiKQppZihiPj4+MCE9PWJ8fGI+PWEubGVuZ3RoKXRocm93IEguYihQLkNm
-KGIsYSxudWxsLG51bGwsbnVsbCkpCnJldHVybiBhW2JdfSwKWTpmdW5jdGlvbihhLGIsYyl7dS5BLmIo
+bykKcj1ILnRzKG8pCnE9dS5uLmEobC5hLmEuYykKcD1xLmEKbj1zCm09bC5iCmlmKHA9PW51bGw/bj09
+bnVsbDpwPT09biltLmI9cQplbHNlIG0uYj1QLlRsKHMscikKbS5hPSEwfX0sCiRTOjJ9ClAuT00ucHJv
+dG90eXBlPXt9ClAucWgucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPXRoaXMscT17
+fSxwPW5ldyBQLnZzKCQuWDMsdS5mSikKcS5hPTAKdD1ILkxoKHIpCnM9dC5DKCJ+KDEpIikuYShuZXcg
+UC5CNShxLHIpKQp1Lk0uYShuZXcgUC51TyhxLHApKQpXLkpFKHIuYSxyLmIscywhMSx0LmMpCnJldHVy
+biBwfX0KUC5CNS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtILkxoKHRoaXMuYikuYy5hKGEpOysr
+dGhpcy5hLmF9LAokUzpmdW5jdGlvbigpe3JldHVybiBILkxoKHRoaXMuYikuQygiYzgoMSkiKX19ClAu
+dU8ucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXt0aGlzLmIuSEgodGhpcy5hLmEpfSwKJFM6MH0KUC5N
+Ty5wcm90b3R5cGU9e30KUC5rVC5wcm90b3R5cGU9e30KUC54SS5wcm90b3R5cGU9e30KUC5PSC5wcm90
+b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiBILmQodGhpcy5hKX0sCiRpWFM6MSwKZ0lJOmZ1bmN0
+aW9uKCl7cmV0dXJuIHRoaXMuYn19ClAubTAucHJvdG90eXBlPXskaUpCOjF9ClAucEsucHJvdG90eXBl
+PXsKJDA6ZnVuY3Rpb24oKXt2YXIgdCxzPXRoaXMuYSxyPXMuYgppZihyPT1udWxsKXRocm93IEguYihz
+LmEpCnQ9SC5iKHMuYSkKdC5zdGFjaz1yLlooMCkKdGhyb3cgdH0sCiRTOjB9ClAuSmkucHJvdG90eXBl
+PXsKYkg6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9bnVsbAp1Lk0uYShhKQp0cnl7aWYoQy5OVT09PSQu
+WDMpe2EuJDAoKQpyZXR1cm59UC5UOChxLHEsdGhpcyxhLHUuSCl9Y2F0Y2gocil7dD1ILlJ1KHIpCnM9
+SC50cyhyKQpQLkwyKHEscSx0aGlzLHQsdS5sLmEocykpfX0sCkRsOmZ1bmN0aW9uKGEsYixjKXt2YXIg
+dCxzLHIscT1udWxsCmMuQygifigwKSIpLmEoYSkKYy5hKGIpCnRyeXtpZihDLk5VPT09JC5YMyl7YS4k
+MShiKQpyZXR1cm59UC55dihxLHEsdGhpcyxhLGIsdS5ILGMpfWNhdGNoKHIpe3Q9SC5SdShyKQpzPUgu
+dHMocikKUC5MMihxLHEsdGhpcyx0LHUubC5hKHMpKX19LApSVDpmdW5jdGlvbihhLGIpe3JldHVybiBu
+ZXcgUC5oaih0aGlzLGIuQygiMCgpIikuYShhKSxiKX0sCkdZOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcg
+UC5WcCh0aGlzLHUuTS5hKGEpKX0sClB5OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG5ldyBQLk9SKHRoaXMs
+Yi5DKCJ+KDApIikuYShhKSxiKX0sCnE6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbnVsbH0sCnp6OmZ1bmN0
+aW9uKGEsYil7Yi5DKCIwKCkiKS5hKGEpCmlmKCQuWDM9PT1DLk5VKXJldHVybiBhLiQwKCkKcmV0dXJu
+IFAuVDgobnVsbCxudWxsLHRoaXMsYSxiKX0sCmJ2OmZ1bmN0aW9uKGEsYixjLGQpe2MuQygiQDwwPiIp
+LktxKGQpLkMoIjEoMikiKS5hKGEpCmQuYShiKQppZigkLlgzPT09Qy5OVSlyZXR1cm4gYS4kMShiKQpy
+ZXR1cm4gUC55dihudWxsLG51bGwsdGhpcyxhLGIsYyxkKX0sCnJwOmZ1bmN0aW9uKGEsYixjLGQsZSxm
+KXtkLkMoIkA8MD4iKS5LcShlKS5LcShmKS5DKCIxKDIsMykiKS5hKGEpCmUuYShiKQpmLmEoYykKaWYo
+JC5YMz09PUMuTlUpcmV0dXJuIGEuJDIoYixjKQpyZXR1cm4gUC5ReChudWxsLG51bGwsdGhpcyxhLGIs
+YyxkLGUsZil9LApMajpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gYi5DKCJAPDA+IikuS3EoYykuS3Eo
+ZCkuQygiMSgyLDMpIikuYShhKX19ClAuaGoucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtyZXR1cm4g
+dGhpcy5hLnp6KHRoaXMuYix0aGlzLmMpfSwKJFM6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5jLkMoIjAo
+KSIpfX0KUC5WcC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmEuYkgodGhpcy5i
+KX0sCiRTOjJ9ClAuT1IucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5jCnJldHVy
+biB0aGlzLmEuRGwodGhpcy5iLHQuYShhKSx0KX0sCiRTOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYy5D
+KCJ+KDApIil9fQpQLmI2LnByb3RvdHlwZT17CmdrejpmdW5jdGlvbihhKXt2YXIgdD10aGlzLHM9bmV3
+IFAubG0odCx0LnIsSC5MaCh0KS5DKCJsbTwxPiIpKQpzLmM9dC5lCnJldHVybiBzfSwKZ0E6ZnVuY3Rp
+b24oYSl7cmV0dXJuIHRoaXMuYX0sCnRnOmZ1bmN0aW9uKGEsYil7dmFyIHQscwppZih0eXBlb2YgYj09
+InN0cmluZyImJmIhPT0iX19wcm90b19fIil7dD10aGlzLmIKaWYodD09bnVsbClyZXR1cm4hMQpyZXR1
+cm4gdS5ELmEodFtiXSkhPW51bGx9ZWxzZXtzPXRoaXMuUFIoYikKcmV0dXJuIHN9fSwKUFI6ZnVuY3Rp
+b24oYSl7dmFyIHQ9dGhpcy5kCmlmKHQ9PW51bGwpcmV0dXJuITEKcmV0dXJuIHRoaXMuREYodFt0aGlz
+Lk4oYSldLGEpPj0wfSwKaTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj10aGlzCkguTGgocikuYy5hKGIp
+CmlmKHR5cGVvZiBiPT0ic3RyaW5nIiYmYiE9PSJfX3Byb3RvX18iKXt0PXIuYgpyZXR1cm4gci5iUSh0
+PT1udWxsP3IuYj1QLlQyKCk6dCxiKX1lbHNlIGlmKHR5cGVvZiBiPT0ibnVtYmVyIiYmKGImMTA3Mzc0
+MTgyMyk9PT1iKXtzPXIuYwpyZXR1cm4gci5iUShzPT1udWxsP3IuYz1QLlQyKCk6cyxiKX1lbHNlIHJl
+dHVybiByLkI3KGIpfSwKQjc6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9dGhpcwpILkxoKHEpLmMuYShh
+KQp0PXEuZAppZih0PT1udWxsKXQ9cS5kPVAuVDIoKQpzPXEuTihhKQpyPXRbc10KaWYocj09bnVsbCl0
+W3NdPVtxLnlvKGEpXQplbHNle2lmKHEuREYocixhKT49MClyZXR1cm4hMQpyLnB1c2gocS55byhhKSl9
+cmV0dXJuITB9LApSOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcwppZih0eXBlb2YgYj09InN0cmluZyIm
+JmIhPT0iX19wcm90b19fIilyZXR1cm4gdC5INCh0LmIsYikKZWxzZSBpZih0eXBlb2YgYj09Im51bWJl
+ciImJihiJjEwNzM3NDE4MjMpPT09YilyZXR1cm4gdC5INCh0LmMsYikKZWxzZSByZXR1cm4gdC5xZyhi
+KX0sCnFnOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9dGhpcyxvPXAuZAppZihvPT1udWxsKXJldHVy
+biExCnQ9cC5OKGEpCnM9b1t0XQpyPXAuREYocyxhKQppZihyPDApcmV0dXJuITEKcT1zLnNwbGljZShy
+LDEpWzBdCmlmKDA9PT1zLmxlbmd0aClkZWxldGUgb1t0XQpwLkdTKHEpCnJldHVybiEwfSwKYlE6ZnVu
+Y3Rpb24oYSxiKXtILkxoKHRoaXMpLmMuYShiKQppZih1LkQuYShhW2JdKSE9bnVsbClyZXR1cm4hMQph
+W2JdPXRoaXMueW8oYikKcmV0dXJuITB9LApINDpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGE9PW51bGwp
+cmV0dXJuITEKdD11LkQuYShhW2JdKQppZih0PT1udWxsKXJldHVybiExCnRoaXMuR1ModCkKZGVsZXRl
+IGFbYl0KcmV0dXJuITB9LApTOmZ1bmN0aW9uKCl7dGhpcy5yPTEwNzM3NDE4MjMmdGhpcy5yKzF9LAp5
+bzpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMscj1uZXcgUC5ibihILkxoKHMpLmMuYShhKSkKaWYocy5l
+PT1udWxsKXMuZT1zLmY9cgplbHNle3Q9cy5mCnIuYz10CnMuZj10LmI9cn0rK3MuYQpzLlMoKQpyZXR1
+cm4gcn0sCkdTOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMscz1hLmMscj1hLmIKaWYocz09bnVsbCl0LmU9
+cgplbHNlIHMuYj1yCmlmKHI9PW51bGwpdC5mPXMKZWxzZSByLmM9czstLXQuYQp0LlMoKX0sCk46ZnVu
+Y3Rpb24oYSl7cmV0dXJuIEouaGYoYSkmMTA3Mzc0MTgyM30sCkRGOmZ1bmN0aW9uKGEsYil7dmFyIHQs
+cwppZihhPT1udWxsKXJldHVybi0xCnQ9YS5sZW5ndGgKZm9yKHM9MDtzPHQ7KytzKWlmKEouUk0oYVtz
+XS5hLGIpKXJldHVybiBzCnJldHVybi0xfX0KUC5ibi5wcm90b3R5cGU9e30KUC5sbS5wcm90b3R5cGU9
+ewpnbDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmR9LApGOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcyxzPXQu
+YQppZih0LmIhPT1zLnIpdGhyb3cgSC5iKFAuYTQocykpCmVsc2V7cz10LmMKaWYocz09bnVsbCl7dC5z
+aihudWxsKQpyZXR1cm4hMX1lbHNle3Quc2oodC4kdGkuYy5hKHMuYSkpCnQuYz10LmMuYgpyZXR1cm4h
+MH19fSwKc2o6ZnVuY3Rpb24oYSl7dGhpcy5kPXRoaXMuJHRpLmMuYShhKX0sCiRpQW46MX0KUC5tVy5w
+cm90b3R5cGU9e30KUC51eS5wcm90b3R5cGU9eyRpYlE6MSwkaWNYOjEsJGl6TToxfQpQLmxELnByb3Rv
+dHlwZT17CmdrejpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IEguYTcoYSx0aGlzLmdBKGEpLEgucShhKS5D
+KCJhNzxsRC5FPiIpKX0sCkU6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5xKGEsYil9LApLOmZ1bmN0
+aW9uKGEsYil7dmFyIHQscwpILnEoYSkuQygifihsRC5FKSIpLmEoYikKdD10aGlzLmdBKGEpCmZvcihz
+PTA7czx0Oysrcyl7Yi4kMSh0aGlzLnEoYSxzKSkKaWYodCE9PXRoaXMuZ0EoYSkpdGhyb3cgSC5iKFAu
+YTQoYSkpfX0sCmdvcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nQShhKSE9PTB9LApFMjpmdW5jdGlv
+bihhLGIsYyl7dmFyIHQ9SC5xKGEpCnJldHVybiBuZXcgSC5sSihhLHQuS3EoYykuQygiMShsRC5FKSIp
+LmEoYiksdC5DKCJAPGxELkU+IikuS3EoYykuQygibEo8MSwyPiIpKX0sCmR1OmZ1bmN0aW9uKGEsYixj
+LGQpe3ZhciB0CkgucShhKS5DKCJsRC5FIikuYShkKQpQLmpCKGIsYyx0aGlzLmdBKGEpKQpmb3IodD1i
+O3Q8YzsrK3QpdGhpcy5ZKGEsdCxkKX0sClo6ZnVuY3Rpb24oYSl7cmV0dXJuIFAuV0UoYSwiWyIsIl0i
+KX19ClAuaWwucHJvdG90eXBlPXt9ClAucmEucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIg
+dCxzPXRoaXMuYQppZighcy5hKXRoaXMuYi5hKz0iLCAiCnMuYT0hMQpzPXRoaXMuYgp0PXMuYSs9SC5k
+KGEpCnMuYT10KyI6ICIKcy5hKz1ILmQoYil9LAokUzo0fQpQLllrLnByb3RvdHlwZT17Cks6ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzCkguTGgodGhpcykuQygifihZay5LLFlrLlYpIikuYShiKQpmb3IodD1KLklU
+KHRoaXMuZ1YoKSk7dC5GKCk7KXtzPXQuZ2woKQpiLiQyKHMsdGhpcy5xKDAscykpfX0sCmdQdTpmdW5j
+dGlvbihhKXtyZXR1cm4gSi5NMSh0aGlzLmdWKCksbmV3IFAueVEodGhpcyksSC5MaCh0aGlzKS5DKCJO
+MzxZay5LLFlrLlY+IikpfSwKeDQ6ZnVuY3Rpb24oYSl7cmV0dXJuIEouemwodGhpcy5nVigpLGEpfSwK
+Z0E6ZnVuY3Rpb24oYSl7cmV0dXJuIEouSCh0aGlzLmdWKCkpfSwKZ2wwOmZ1bmN0aW9uKGEpe3JldHVy
+biBKLkNpKHRoaXMuZ1YoKSl9LApaOmZ1bmN0aW9uKGEpe3JldHVybiBQLm5PKHRoaXMpfSwKJGlaMDox
+fQpQLnlRLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYSxzPUguTGgodCkKcy5D
+KCJZay5LIikuYShhKQpyZXR1cm4gbmV3IFAuTjMoYSx0LnEoMCxhKSxzLkMoIkA8WWsuSz4iKS5LcShz
+LkMoIllrLlYiKSkuQygiTjM8MSwyPiIpKX0sCiRTOmZ1bmN0aW9uKCl7cmV0dXJuIEguTGgodGhpcy5h
+KS5DKCJOMzxZay5LLFlrLlY+KFlrLkspIil9fQpQLktQLnByb3RvdHlwZT17Clk6ZnVuY3Rpb24oYSxi
+LGMpe3ZhciB0PUguTGgodGhpcykKdC5jLmEoYikKdC5RWzFdLmEoYykKdGhyb3cgSC5iKFAuTDQoIkNh
+bm5vdCBtb2RpZnkgdW5tb2RpZmlhYmxlIG1hcCIpKX19ClAuUG4ucHJvdG90eXBlPXsKcTpmdW5jdGlv
+bihhLGIpe3JldHVybiB0aGlzLmEucSgwLGIpfSwKWTpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9SC5MaCh0
+aGlzKQp0aGlzLmEuWSgwLHQuYy5hKGIpLHQuUVsxXS5hKGMpKX0sCng0OmZ1bmN0aW9uKGEpe3JldHVy
+biB0aGlzLmEueDQoYSl9LApLOmZ1bmN0aW9uKGEsYil7dGhpcy5hLksoMCxILkxoKHRoaXMpLkMoIn4o
+MSwyKSIpLmEoYikpfSwKZ2wwOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpyZXR1cm4gdC5nbDAodCl9
+LApnQTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKcmV0dXJuIHQuZ0EodCl9LApaOmZ1bmN0aW9uKGEp
+e3JldHVybiBKLkFjKHRoaXMuYSl9LApnUHU6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hCnJldHVybiB0
+LmdQdSh0KX0sCiRpWjA6MX0KUC5Hai5wcm90b3R5cGU9e30KUC5NYS5wcm90b3R5cGU9ewpaOmZ1bmN0
+aW9uKGEpe3JldHVybiBQLldFKHRoaXMsInsiLCJ9Iil9fQpQLlZqLnByb3RvdHlwZT17JGliUToxLCRp
+Y1g6MSwkaXh1OjF9ClAuWHYucHJvdG90eXBlPXsKRlY6ZnVuY3Rpb24oYSxiKXt2YXIgdApmb3IodD1K
+LklUKEguTGgodGhpcykuQygiY1g8MT4iKS5hKGIpKTt0LkYoKTspdGhpcy5pKDAsdC5nbCgpKX0sClo6
+ZnVuY3Rpb24oYSl7cmV0dXJuIFAuV0UodGhpcywieyIsIn0iKX0sCkg6ZnVuY3Rpb24oYSxiKXt2YXIg
+dCxzPVAucmoodGhpcyx0aGlzLnIsSC5MaCh0aGlzKS5jKQppZighcy5GKCkpcmV0dXJuIiIKaWYoYj09
+PSIiKXt0PSIiCmRvIHQrPUguZChzLmQpCndoaWxlKHMuRigpKX1lbHNle3Q9SC5kKHMuZCkKZm9yKDtz
+LkYoKTspdD10K2IrSC5kKHMuZCl9cmV0dXJuIHQuY2hhckNvZGVBdCgwKT09MD90OnR9LAokaWJROjEs
+CiRpY1g6MSwKJGl4dToxfQpQLm5ZLnByb3RvdHlwZT17fQpQLlRDLnByb3RvdHlwZT17fQpQLlJVLnBy
+b3RvdHlwZT17fQpQLnV3LnByb3RvdHlwZT17CnE6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRoaXMuYgpp
+ZihzPT1udWxsKXJldHVybiB0aGlzLmMucSgwLGIpCmVsc2UgaWYodHlwZW9mIGIhPSJzdHJpbmciKXJl
+dHVybiBudWxsCmVsc2V7dD1zW2JdCnJldHVybiB0eXBlb2YgdD09InVuZGVmaW5lZCI/dGhpcy5mYihi
+KTp0fX0sCmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmI9PW51bGw/dGhpcy5jLmE6dGhpcy5DZigp
+Lmxlbmd0aH0sCmdsMDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nQSh0aGlzKT09PTB9LApnVjpmdW5j
+dGlvbigpe2lmKHRoaXMuYj09bnVsbCl7dmFyIHQ9dGhpcy5jCnJldHVybiBuZXcgSC5pNSh0LEguTGgo
+dCkuQygiaTU8MT4iKSl9cmV0dXJuIG5ldyBQLmk4KHRoaXMpfSwKWTpmdW5jdGlvbihhLGIsYyl7dmFy
+IHQscyxyPXRoaXMKaWYoci5iPT1udWxsKXIuYy5ZKDAsYixjKQplbHNlIGlmKHIueDQoYikpe3Q9ci5i
+CnRbYl09YwpzPXIuYQppZihzPT1udWxsP3QhPW51bGw6cyE9PXQpc1tiXT1udWxsfWVsc2Ugci5YSygp
+LlkoMCxiLGMpfSwKeDQ6ZnVuY3Rpb24oYSl7aWYodGhpcy5iPT1udWxsKXJldHVybiB0aGlzLmMueDQo
+YSkKcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLmEsYSl9LApL
+OmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscD10aGlzCnUuY0EuYShiKQppZihwLmI9PW51bGwpcmV0
+dXJuIHAuYy5LKDAsYikKdD1wLkNmKCkKZm9yKHM9MDtzPHQubGVuZ3RoOysrcyl7cj10W3NdCnE9cC5i
+W3JdCmlmKHR5cGVvZiBxPT0idW5kZWZpbmVkIil7cT1QLlFlKHAuYVtyXSkKcC5iW3JdPXF9Yi4kMihy
+LHEpCmlmKHQhPT1wLmMpdGhyb3cgSC5iKFAuYTQocCkpfX0sCkNmOmZ1bmN0aW9uKCl7dmFyIHQ9dS5q
+LmEodGhpcy5jKQppZih0PT1udWxsKXQ9dGhpcy5jPUguVk0oT2JqZWN0LmtleXModGhpcy5hKSx1LnMp
+CnJldHVybiB0fSwKWEs6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwLG89dGhpcwppZihvLmI9PW51bGwp
+cmV0dXJuIG8uYwp0PVAuRmwodS5OLHUueikKcz1vLkNmKCkKZm9yKHI9MDtxPXMubGVuZ3RoLHI8cTsr
+K3Ipe3A9c1tyXQp0LlkoMCxwLG8ucSgwLHApKX1pZihxPT09MClDLk5tLmkocyxudWxsKQplbHNlIEMu
+Tm0uc0EocywwKQpvLmE9by5iPW51bGwKcmV0dXJuIG8uYz10fSwKZmI6ZnVuY3Rpb24oYSl7dmFyIHQK
+aWYoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLmEsYSkpcmV0dXJuIG51
+bGwKdD1QLlFlKHRoaXMuYVthXSkKcmV0dXJuIHRoaXMuYlthXT10fX0KUC5pOC5wcm90b3R5cGU9ewpn
+QTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKcmV0dXJuIHQuZ0EodCl9LApFOmZ1bmN0aW9uKGEsYil7
+dmFyIHQ9dGhpcy5hCmlmKHQuYj09bnVsbCl0PXQuZ1YoKS5FKDAsYikKZWxzZXt0PXQuQ2YoKQppZihi
+PDB8fGI+PXQubGVuZ3RoKXJldHVybiBILmsodCxiKQp0PXRbYl19cmV0dXJuIHR9LApna3o6ZnVuY3Rp
+b24oYSl7dmFyIHQ9dGhpcy5hCmlmKHQuYj09bnVsbCl7dD10LmdWKCkKdD10Lmdreih0KX1lbHNle3Q9
+dC5DZigpCnQ9bmV3IEoubTEodCx0Lmxlbmd0aCxILnQ2KHQpLkMoIm0xPDE+IikpfXJldHVybiB0fSwK
+dGc6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5hLng0KGIpfX0KUC5DVi5wcm90b3R5cGU9ewp5cjpm
+dW5jdGlvbihhLGEwLGExKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqLGksaCxnLGYsZSxkLGMsYj0i
+SW52YWxpZCBiYXNlNjQgZW5jb2RpbmcgbGVuZ3RoICIKYTE9UC5qQihhMCxhMSxhLmxlbmd0aCkKdD0k
+LlY3KCkKZm9yKHM9YTAscj1zLHE9bnVsbCxwPS0xLG89LTEsbj0wO3M8YTE7cz1tKXttPXMrMQpsPUMu
+eEIuVyhhLHMpCmlmKGw9PT0zNyl7az1tKzIKaWYoazw9YTEpe2o9SC5vbyhDLnhCLlcoYSxtKSkKaT1I
+Lm9vKEMueEIuVyhhLG0rMSkpCmg9aioxNitpLShpJjI1NikKaWYoaD09PTM3KWg9LTEKbT1rfWVsc2Ug
+aD0tMX1lbHNlIGg9bAppZigwPD1oJiZoPD0xMjcpe2lmKGg8MHx8aD49dC5sZW5ndGgpcmV0dXJuIEgu
+ayh0LGgpCmc9dFtoXQppZihnPj0wKXtoPUMueEIubSgiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVph
+YmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLyIsZykKaWYoaD09PWwpY29udGludWUK
+bD1ofWVsc2V7aWYoZz09PS0xKXtpZihwPDApe2Y9cT09bnVsbD9udWxsOnEuYS5sZW5ndGgKaWYoZj09
+bnVsbClmPTAKcD1mKyhzLXIpCm89c30rK24KaWYobD09PTYxKWNvbnRpbnVlfWw9aH1pZihnIT09LTIp
+e2lmKHE9PW51bGwpcT1uZXcgUC5SbigiIikKcS5hKz1DLnhCLk5qKGEscixzKQpxLmErPUguTHcobCkK
+cj1tCmNvbnRpbnVlfX10aHJvdyBILmIoUC5ycigiSW52YWxpZCBiYXNlNjQgZGF0YSIsYSxzKSl9aWYo
+cSE9bnVsbCl7Zj1xLmErPUMueEIuTmooYSxyLGExKQplPWYubGVuZ3RoCmlmKHA+PTApUC54TShhLG8s
+YTEscCxuLGUpCmVsc2V7ZD1DLmpuLnpZKGUtMSw0KSsxCmlmKGQ9PT0xKXRocm93IEguYihQLnJyKGIs
+YSxhMSkpCmZvcig7ZDw0Oyl7Zis9Ij0iCnEuYT1mOysrZH19Zj1xLmEKcmV0dXJuIEMueEIuaTcoYSxh
+MCxhMSxmLmNoYXJDb2RlQXQoMCk9PTA/ZjpmKX1jPWExLWEwCmlmKHA+PTApUC54TShhLG8sYTEscCxu
+LGMpCmVsc2V7ZD1DLmpuLnpZKGMsNCkKaWYoZD09PTEpdGhyb3cgSC5iKFAucnIoYixhLGExKSkKaWYo
+ZD4xKWE9Qy54Qi5pNyhhLGExLGExLGQ9PT0yPyI9PSI6Ij0iKX1yZXR1cm4gYX19ClAuVTgucHJvdG90
+eXBlPXt9ClAuVWsucHJvdG90eXBlPXt9ClAud0kucHJvdG90eXBlPXt9ClAuWmkucHJvdG90eXBlPXt9
+ClAuVWQucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXt2YXIgdD1QLmgodGhpcy5hKQpyZXR1cm4odGhp
+cy5iIT1udWxsPyJDb252ZXJ0aW5nIG9iamVjdCB0byBhbiBlbmNvZGFibGUgb2JqZWN0IGZhaWxlZDoi
+OiJDb252ZXJ0aW5nIG9iamVjdCBkaWQgbm90IHJldHVybiBhbiBlbmNvZGFibGUgb2JqZWN0OiIpKyIg
+Iit0fX0KUC5LOC5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiJDeWNsaWMgZXJyb3IgaW4g
+SlNPTiBzdHJpbmdpZnkifX0KUC5ieS5wcm90b3R5cGU9ewpwVzpmdW5jdGlvbihhLGIsYyl7dmFyIHQK
+dS5lcC5hKGMpCnQ9UC5CUyhiLHRoaXMuZ0hlKCkuYSkKcmV0dXJuIHR9LApPQjpmdW5jdGlvbihhLGIp
+e3ZhciB0CnUuYmMuYShiKQp0PVAudVgoYSx0aGlzLmdaRSgpLmIsbnVsbCkKcmV0dXJuIHR9LApnWkU6
+ZnVuY3Rpb24oKXtyZXR1cm4gQy5uWH0sCmdIZTpmdW5jdGlvbigpe3JldHVybiBDLkEzfX0KUC5vai5w
+cm90b3R5cGU9e30KUC5NeC5wcm90b3R5cGU9e30KUC5TaC5wcm90b3R5cGU9ewp2cDpmdW5jdGlvbihh
+KXt2YXIgdCxzLHIscSxwLG8sbj1hLmxlbmd0aApmb3IodD1KLnJZKGEpLHM9dGhpcy5jLHI9MCxxPTA7
+cTxuOysrcSl7cD10LlcoYSxxKQppZihwPjkyKWNvbnRpbnVlCmlmKHA8MzIpe2lmKHE+cilzLmErPUMu
+eEIuTmooYSxyLHEpCnI9cSsxCnMuYSs9SC5Mdyg5MikKc3dpdGNoKHApe2Nhc2UgODpzLmErPUguTHco
+OTgpCmJyZWFrCmNhc2UgOTpzLmErPUguTHcoMTE2KQpicmVhawpjYXNlIDEwOnMuYSs9SC5MdygxMTAp
+CmJyZWFrCmNhc2UgMTI6cy5hKz1ILkx3KDEwMikKYnJlYWsKY2FzZSAxMzpzLmErPUguTHcoMTE0KQpi
+cmVhawpkZWZhdWx0OnMuYSs9SC5MdygxMTcpCnMuYSs9SC5Mdyg0OCkKcy5hKz1ILkx3KDQ4KQpvPXA+
+Pj40JjE1CnMuYSs9SC5MdyhvPDEwPzQ4K286ODcrbykKbz1wJjE1CnMuYSs9SC5MdyhvPDEwPzQ4K286
+ODcrbykKYnJlYWt9fWVsc2UgaWYocD09PTM0fHxwPT09OTIpe2lmKHE+cilzLmErPUMueEIuTmooYSxy
+LHEpCnI9cSsxCnMuYSs9SC5Mdyg5MikKcy5hKz1ILkx3KHApfX1pZihyPT09MClzLmErPUguZChhKQpl
+bHNlIGlmKHI8bilzLmErPXQuTmooYSxyLG4pfSwKSm46ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEKZm9y
+KHQ9dGhpcy5hLHM9dC5sZW5ndGgscj0wO3I8czsrK3Ipe3E9dFtyXQppZihhPT1udWxsP3E9PW51bGw6
+YT09PXEpdGhyb3cgSC5iKG5ldyBQLks4KGEsbnVsbCkpfUMuTm0uaSh0LGEpfSwKaVU6ZnVuY3Rpb24o
+YSl7dmFyIHQscyxyLHEscD10aGlzCmlmKHAudE0oYSkpcmV0dXJuCnAuSm4oYSkKdHJ5e3Q9cC5iLiQx
+KGEpCmlmKCFwLnRNKHQpKXtyPVAuR3koYSxudWxsLHAuZ1ZLKCkpCnRocm93IEguYihyKX1yPXAuYQpp
+ZigwPj1yLmxlbmd0aClyZXR1cm4gSC5rKHIsLTEpCnIucG9wKCl9Y2F0Y2gocSl7cz1ILlJ1KHEpCnI9
+UC5HeShhLHMscC5nVksoKSkKdGhyb3cgSC5iKHIpfX0sCnRNOmZ1bmN0aW9uKGEpe3ZhciB0LHMscj10
+aGlzCmlmKHR5cGVvZiBhPT0ibnVtYmVyIil7aWYoIWlzRmluaXRlKGEpKXJldHVybiExCnIuYy5hKz1D
+LkNELlooYSkKcmV0dXJuITB9ZWxzZSBpZihhPT09ITApe3IuYy5hKz0idHJ1ZSIKcmV0dXJuITB9ZWxz
+ZSBpZihhPT09ITEpe3IuYy5hKz0iZmFsc2UiCnJldHVybiEwfWVsc2UgaWYoYT09bnVsbCl7ci5jLmEr
+PSJudWxsIgpyZXR1cm4hMH1lbHNlIGlmKHR5cGVvZiBhPT0ic3RyaW5nIil7dD1yLmMKdC5hKz0nIicK
+ci52cChhKQp0LmErPSciJwpyZXR1cm4hMH1lbHNlIGlmKHUuai5iKGEpKXtyLkpuKGEpCnIubEsoYSkK
+dD1yLmEKaWYoMD49dC5sZW5ndGgpcmV0dXJuIEguayh0LC0xKQp0LnBvcCgpCnJldHVybiEwfWVsc2Ug
+aWYodS5HLmIoYSkpe3IuSm4oYSkKcz1yLmp3KGEpCnQ9ci5hCmlmKDA+PXQubGVuZ3RoKXJldHVybiBI
+LmsodCwtMSkKdC5wb3AoKQpyZXR1cm4gc31lbHNlIHJldHVybiExfSwKbEs6ZnVuY3Rpb24oYSl7dmFy
+IHQscyxyPXRoaXMuYwpyLmErPSJbIgp0PUouVTYoYSkKaWYodC5nb3IoYSkpe3RoaXMuaVUodC5xKGEs
+MCkpCmZvcihzPTE7czx0LmdBKGEpOysrcyl7ci5hKz0iLCIKdGhpcy5pVSh0LnEoYSxzKSl9fXIuYSs9
+Il0ifSwKanc6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscCxvLG49dGhpcyxtPXt9CmlmKGEuZ2wwKGEp
+KXtuLmMuYSs9Int9IgpyZXR1cm4hMH10PWEuZ0EoYSkqMgpzPW5ldyBBcnJheSh0KQpzLmZpeGVkJGxl
+bmd0aD1BcnJheQpyPW0uYT0wCm0uYj0hMAphLksoMCxuZXcgUC50aShtLHMpKQppZighbS5iKXJldHVy
+biExCnE9bi5jCnEuYSs9InsiCmZvcihwPSciJztyPHQ7cis9MixwPScsIicpe3EuYSs9cApuLnZwKEgu
+YyhzW3JdKSkKcS5hKz0nIjonCm89cisxCmlmKG8+PXQpcmV0dXJuIEguayhzLG8pCm4uaVUoc1tvXSl9
+cS5hKz0ifSIKcmV0dXJuITB9fQpQLnRpLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7dmFyIHQs
+cwppZih0eXBlb2YgYSE9InN0cmluZyIpdGhpcy5hLmI9ITEKdD10aGlzLmIKcz10aGlzLmEKQy5ObS5Z
+KHQscy5hKyssYSkKQy5ObS5ZKHQscy5hKyssYil9LAokUzo0fQpQLnR1LnByb3RvdHlwZT17CmdWSzpm
+dW5jdGlvbigpe3ZhciB0PXRoaXMuYy5hCnJldHVybiB0LmNoYXJDb2RlQXQoMCk9PTA/dDp0fX0KUC51
+NS5wcm90b3R5cGU9ewpnWkU6ZnVuY3Rpb24oKXtyZXR1cm4gQy5Ra319ClAuRTMucHJvdG90eXBlPXsK
+V0o6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPVAuakIoMCxudWxsLGEubGVuZ3RoKSxxPXItMAppZihxPT09
+MClyZXR1cm4gbmV3IFVpbnQ4QXJyYXkoMCkKdD1uZXcgVWludDhBcnJheShxKjMpCnM9bmV3IFAuUnco
+dCkKaWYocy5HeChhLDAscikhPT1yKXMuTzYoSi5hNihhLHItMSksMCkKcmV0dXJuIG5ldyBVaW50OEFy
+cmF5KHQuc3ViYXJyYXkoMCxILnJNKDAscy5iLHQubGVuZ3RoKSkpfX0KUC5Sdy5wcm90b3R5cGU9ewpP
+NjpmdW5jdGlvbihhLGIpe3ZhciB0LHM9dGhpcyxyPXMuYyxxPXMuYixwPXErMSxvPXIubGVuZ3RoCmlm
+KChiJjY0NTEyKT09PTU2MzIwKXt0PTY1NTM2KygoYSYxMDIzKTw8MTApfGImMTAyMwpzLmI9cAppZihx
+Pj1vKXJldHVybiBILmsocixxKQpyW3FdPTI0MHx0Pj4+MTgKcT1zLmI9cCsxCmlmKHA+PW8pcmV0dXJu
+IEguayhyLHApCnJbcF09MTI4fHQ+Pj4xMiY2MwpwPXMuYj1xKzEKaWYocT49bylyZXR1cm4gSC5rKHIs
+cSkKcltxXT0xMjh8dD4+PjYmNjMKcy5iPXArMQppZihwPj1vKXJldHVybiBILmsocixwKQpyW3BdPTEy
+OHx0JjYzCnJldHVybiEwfWVsc2V7cy5iPXAKaWYocT49bylyZXR1cm4gSC5rKHIscSkKcltxXT0yMjR8
+YT4+PjEyCnE9cy5iPXArMQppZihwPj1vKXJldHVybiBILmsocixwKQpyW3BdPTEyOHxhPj4+NiY2Mwpz
+LmI9cSsxCmlmKHE+PW8pcmV0dXJuIEguayhyLHEpCnJbcV09MTI4fGEmNjMKcmV0dXJuITF9fSwKR3g6
+ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxuLG09dGhpcwppZihiIT09YyYmKEMueEIubShh
+LGMtMSkmNjQ1MTIpPT09NTUyOTYpLS1jCmZvcih0PW0uYyxzPXQubGVuZ3RoLHI9YjtyPGM7KytyKXtx
+PUMueEIuVyhhLHIpCmlmKHE8PTEyNyl7cD1tLmIKaWYocD49cylicmVhawptLmI9cCsxCnRbcF09cX1l
+bHNlIGlmKChxJjY0NTEyKT09PTU1Mjk2KXtpZihtLmIrMz49cylicmVhawpvPXIrMQppZihtLk82KHEs
+Qy54Qi5XKGEsbykpKXI9b31lbHNlIGlmKHE8PTIwNDcpe3A9bS5iCm49cCsxCmlmKG4+PXMpYnJlYWsK
+bS5iPW4KaWYocD49cylyZXR1cm4gSC5rKHQscCkKdFtwXT0xOTJ8cT4+PjYKbS5iPW4rMQp0W25dPTEy
+OHxxJjYzfWVsc2V7cD1tLmIKaWYocCsyPj1zKWJyZWFrCm49bS5iPXArMQppZihwPj1zKXJldHVybiBI
+LmsodCxwKQp0W3BdPTIyNHxxPj4+MTIKcD1tLmI9bisxCmlmKG4+PXMpcmV0dXJuIEguayh0LG4pCnRb
+bl09MTI4fHE+Pj42JjYzCm0uYj1wKzEKaWYocD49cylyZXR1cm4gSC5rKHQscCkKdFtwXT0xMjh8cSY2
+M319cmV0dXJuIHJ9fQpQLkdZLnByb3RvdHlwZT17CldKOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAs
+byxuLG0sbAp1LkwuYShhKQp0PVAua3koITEsYSwwLG51bGwpCmlmKHQhPW51bGwpcmV0dXJuIHQKcz1Q
+LmpCKDAsbnVsbCxKLkgoYSkpCnI9UC5jUChhLDAscykKaWYocj4wKXtxPVAuSE0oYSwwLHIpCmlmKHI9
+PT1zKXJldHVybiBxCnA9bmV3IFAuUm4ocSkKbz1yCm49ITF9ZWxzZXtvPTAKcD1udWxsCm49ITB9aWYo
+cD09bnVsbClwPW5ldyBQLlJuKCIiKQptPW5ldyBQLmJ6KCExLHApCm0uYz1uCm0uTUUoYSxvLHMpCmlm
+KG0uZT4wKXtILnZoKFAucnIoIlVuZmluaXNoZWQgVVRGLTggb2N0ZXQgc2VxdWVuY2UiLGEscykpCnAu
+YSs9SC5Mdyg2NTUzMykKbS5mPW0uZT1tLmQ9MH1sPXAuYQpyZXR1cm4gbC5jaGFyQ29kZUF0KDApPT0w
+P2w6bH19ClAuYnoucHJvdG90eXBlPXsKTUU6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMscixxLHAsbyxu
+LG0sbCxrLGosaSxoPXRoaXMsZz0iQmFkIFVURi04IGVuY29kaW5nIDB4Igp1LkwuYShhKQp0PWguZApz
+PWguZQpyPWguZgpoLmY9aC5lPWguZD0wCiRsYWJlbDAkMDpmb3IocT1KLlU2KGEpLHA9aC5iLG89Yjsh
+MDtvPWopeyRsYWJlbDEkMTppZihzPjApe2Rve2lmKG89PT1jKWJyZWFrICRsYWJlbDAkMApuPXEucShh
+LG8pCmlmKHR5cGVvZiBuIT09Im51bWJlciIpcmV0dXJuIG4uek0oKQppZigobiYxOTIpIT09MTI4KXtt
+PVAucnIoZytDLmpuLldaKG4sMTYpLGEsbykKdGhyb3cgSC5iKG0pfWVsc2V7dD0odDw8NnxuJjYzKT4+
+PjA7LS1zOysrb319d2hpbGUocz4wKQptPXItMQppZihtPDB8fG0+PTQpcmV0dXJuIEguayhDLkdiLG0p
+CmlmKHQ8PUMuR2JbbV0pe209UC5ycigiT3ZlcmxvbmcgZW5jb2Rpbmcgb2YgMHgiK0Muam4uV1oodCwx
+NiksYSxvLXItMSkKdGhyb3cgSC5iKG0pfWlmKHQ+MTExNDExMSl7bT1QLnJyKCJDaGFyYWN0ZXIgb3V0
+c2lkZSB2YWxpZCBVbmljb2RlIHJhbmdlOiAweCIrQy5qbi5XWih0LDE2KSxhLG8tci0xKQp0aHJvdyBI
+LmIobSl9aWYoIWguY3x8dCE9PTY1Mjc5KXAuYSs9SC5Mdyh0KQpoLmM9ITF9Zm9yKG09bzxjO207KXts
+PVAuY1AoYSxvLGMpCmlmKGw+MCl7aC5jPSExCms9bytsCnAuYSs9UC5ITShhLG8saykKaWYoaz09PWMp
+YnJlYWt9ZWxzZSBrPW8Kaj1rKzEKbj1xLnEoYSxrKQppZih0eXBlb2YgbiE9PSJudW1iZXIiKXJldHVy
+biBuLkooKQppZihuPDApe2k9UC5ycigiTmVnYXRpdmUgVVRGLTggY29kZSB1bml0OiAtMHgiK0Muam4u
+V1ooLW4sMTYpLGEsai0xKQp0aHJvdyBILmIoaSl9ZWxzZXtpZigobiYyMjQpPT09MTkyKXt0PW4mMzEK
+cz0xCnI9MQpjb250aW51ZSAkbGFiZWwwJDB9aWYoKG4mMjQwKT09PTIyNCl7dD1uJjE1CnM9MgpyPTIK
+Y29udGludWUgJGxhYmVsMCQwfWlmKChuJjI0OCk9PT0yNDAmJm48MjQ1KXt0PW4mNwpzPTMKcj0zCmNv
+bnRpbnVlICRsYWJlbDAkMH1pPVAucnIoZytDLmpuLldaKG4sMTYpLGEsai0xKQp0aHJvdyBILmIoaSl9
+fWJyZWFrICRsYWJlbDAkMH1pZihzPjApe2guZD10CmguZT1zCmguZj1yfX19ClAuV0YucHJvdG90eXBl
+PXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKdS5mby5hKGEpCnQ9dGhpcy5iCnM9dGhpcy5hCnQu
+YSs9cy5hCnI9dC5hKz1ILmQoYS5hKQp0LmE9cisiOiAiCnQuYSs9UC5oKGIpCnMuYT0iLCAifSwKJFM6
+NDJ9ClAuYTIucHJvdG90eXBlPXt9ClAuaVAucHJvdG90eXBlPXsKRE46ZnVuY3Rpb24oYSxiKXtpZihi
+PT1udWxsKXJldHVybiExCnJldHVybiBiIGluc3RhbmNlb2YgUC5pUCYmdGhpcy5hPT09Yi5hJiYhMH0s
+CmdpTzpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKcmV0dXJuKHReQy5qbi53Ryh0LDMwKSkmMTA3Mzc0
+MTgyM30sClo6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPVAuR3EoSC50Sih0KSkscj1QLmgwKEguTlMo
+dCkpLHE9UC5oMChILmpBKHQpKSxwPVAuaDAoSC5JWCh0KSksbz1QLmgwKEguY2godCkpLG49UC5oMChI
+LkpkKHQpKSxtPVAuVngoSC5WYSh0KSksbD1zKyItIityKyItIitxKyIgIitwKyI6IitvKyI6IituKyIu
+IittCnJldHVybiBsfX0KUC5DUC5wcm90b3R5cGU9e30KUC5YUy5wcm90b3R5cGU9ewpnSUk6ZnVuY3Rp
+b24oKXtyZXR1cm4gSC50cyh0aGlzLiR0aHJvd25Kc0Vycm9yKX19ClAuQzYucHJvdG90eXBlPXsKWjpm
+dW5jdGlvbihhKXt2YXIgdD10aGlzLmEKaWYodCE9bnVsbClyZXR1cm4iQXNzZXJ0aW9uIGZhaWxlZDog
+IitQLmgodCkKcmV0dXJuIkFzc2VydGlvbiBmYWlsZWQifX0KUC5MSy5wcm90b3R5cGU9ewpaOmZ1bmN0
+aW9uKGEpe3JldHVybiJUaHJvdyBvZiBudWxsLiJ9fQpQLkFULnByb3RvdHlwZT17CmdMOmZ1bmN0aW9u
+KCl7cmV0dXJuIkludmFsaWQgYXJndW1lbnQiKyghdGhpcy5hPyIocykiOiIiKX0sCmd1OmZ1bmN0aW9u
+KCl7cmV0dXJuIiJ9LApaOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHA9dGhpcyxvPXAuYyxuPW8hPW51
+bGw/IiAoIitvKyIpIjoiIgpvPXAuZAp0PW89PW51bGw/IiI6IjogIitILmQobykKcz1wLmdMKCkrbit0
+CmlmKCFwLmEpcmV0dXJuIHMKcj1wLmd1KCkKcT1QLmgocC5iKQpyZXR1cm4gcytyKyI6ICIrcX19ClAu
+YkoucHJvdG90eXBlPXsKZ0w6ZnVuY3Rpb24oKXtyZXR1cm4iUmFuZ2VFcnJvciJ9LApndTpmdW5jdGlv
+bigpe3ZhciB0LHMscj10aGlzLmUKaWYocj09bnVsbCl7cj10aGlzLmYKdD1yIT1udWxsPyI6IE5vdCBs
+ZXNzIHRoYW4gb3IgZXF1YWwgdG8gIitILmQocik6IiJ9ZWxzZXtzPXRoaXMuZgppZihzPT1udWxsKXQ9
+IjogTm90IGdyZWF0ZXIgdGhhbiBvciBlcXVhbCB0byAiK0guZChyKQplbHNlIGlmKHM+cil0PSI6IE5v
+dCBpbiByYW5nZSAiK0guZChyKSsiLi4iK0guZChzKSsiLCBpbmNsdXNpdmUiCmVsc2UgdD1zPHI/Ijog
+VmFsaWQgdmFsdWUgcmFuZ2UgaXMgZW1wdHkiOiI6IE9ubHkgdmFsaWQgdmFsdWUgaXMgIitILmQocil9
+cmV0dXJuIHR9fQpQLmVZLnByb3RvdHlwZT17CmdMOmZ1bmN0aW9uKCl7cmV0dXJuIlJhbmdlRXJyb3Ii
+fSwKZ3U6ZnVuY3Rpb24oKXt2YXIgdCxzPUguV1kodGhpcy5iKQppZih0eXBlb2YgcyE9PSJudW1iZXIi
+KXJldHVybiBzLkooKQppZihzPDApcmV0dXJuIjogaW5kZXggbXVzdCBub3QgYmUgbmVnYXRpdmUiCnQ9
+dGhpcy5mCmlmKHQ9PT0wKXJldHVybiI6IG5vIGluZGljZXMgYXJlIHZhbGlkIgpyZXR1cm4iOiBpbmRl
+eCBzaG91bGQgYmUgbGVzcyB0aGFuICIrSC5kKHQpfSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMu
+Zn19ClAubXAucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixtLGw9dGhp
+cyxrPXt9LGo9bmV3IFAuUm4oIiIpCmsuYT0iIgpmb3IodD1sLmMscz10Lmxlbmd0aCxyPTAscT0iIixw
+PSIiO3I8czsrK3IscD0iLCAiKXtvPXRbcl0Kai5hPXErcApxPWouYSs9UC5oKG8pCmsuYT0iLCAifWwu
+ZC5LKDAsbmV3IFAuV0YoayxqKSkKbj1QLmgobC5hKQptPWouWigwKQp0PSJOb1N1Y2hNZXRob2RFcnJv
+cjogbWV0aG9kIG5vdCBmb3VuZDogJyIrSC5kKGwuYi5hKSsiJ1xuUmVjZWl2ZXI6ICIrbisiXG5Bcmd1
+bWVudHM6IFsiK20rIl0iCnJldHVybiB0fX0KUC51Yi5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3Jl
+dHVybiJVbnN1cHBvcnRlZCBvcGVyYXRpb246ICIrdGhpcy5hfX0KUC5kcy5wcm90b3R5cGU9ewpaOmZ1
+bmN0aW9uKGEpe3ZhciB0PXRoaXMuYQpyZXR1cm4gdCE9bnVsbD8iVW5pbXBsZW1lbnRlZEVycm9yOiAi
+K3Q6IlVuaW1wbGVtZW50ZWRFcnJvciJ9fQpQLmxqLnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7cmV0
+dXJuIkJhZCBzdGF0ZTogIit0aGlzLmF9fQpQLlVWLnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7dmFy
+IHQ9dGhpcy5hCmlmKHQ9PW51bGwpcmV0dXJuIkNvbmN1cnJlbnQgbW9kaWZpY2F0aW9uIGR1cmluZyBp
+dGVyYXRpb24uIgpyZXR1cm4iQ29uY3VycmVudCBtb2RpZmljYXRpb24gZHVyaW5nIGl0ZXJhdGlvbjog
+IitQLmgodCkrIi4ifX0KUC5rNS5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiJPdXQgb2Yg
+TWVtb3J5In0sCmdJSTpmdW5jdGlvbigpe3JldHVybiBudWxsfSwKJGlYUzoxfQpQLktZLnByb3RvdHlw
+ZT17Clo6ZnVuY3Rpb24oYSl7cmV0dXJuIlN0YWNrIE92ZXJmbG93In0sCmdJSTpmdW5jdGlvbigpe3Jl
+dHVybiBudWxsfSwKJGlYUzoxfQpQLnQ3LnByb3RvdHlwZT17Clo6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhp
+cy5hCnJldHVybiB0PT1udWxsPyJSZWFkaW5nIHN0YXRpYyB2YXJpYWJsZSBkdXJpbmcgaXRzIGluaXRp
+YWxpemF0aW9uIjoiUmVhZGluZyBzdGF0aWMgdmFyaWFibGUgJyIrdCsiJyBkdXJpbmcgaXRzIGluaXRp
+YWxpemF0aW9uIn19ClAuQ0QucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4iRXhjZXB0aW9u
+OiAiK3RoaXMuYX0sCiRpUno6MX0KUC5hRS5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3ZhciB0LHMs
+cixxLHAsbyxuLG0sbCxrLGosaSxoPXRoaXMuYSxnPWghPW51bGwmJiIiIT09aD8iRm9ybWF0RXhjZXB0
+aW9uOiAiK0guZChoKToiRm9ybWF0RXhjZXB0aW9uIixmPXRoaXMuYyxlPXRoaXMuYgppZih0eXBlb2Yg
+ZT09InN0cmluZyIpe2lmKGYhPW51bGwpaD1mPDB8fGY+ZS5sZW5ndGgKZWxzZSBoPSExCmlmKGgpZj1u
+dWxsCmlmKGY9PW51bGwpe3Q9ZS5sZW5ndGg+Nzg/Qy54Qi5OaihlLDAsNzUpKyIuLi4iOmUKcmV0dXJu
+IGcrIlxuIit0fWZvcihzPTEscj0wLHE9ITEscD0wO3A8ZjsrK3Ape289Qy54Qi5XKGUscCkKaWYobz09
+PTEwKXtpZihyIT09cHx8IXEpKytzCnI9cCsxCnE9ITF9ZWxzZSBpZihvPT09MTMpeysrcwpyPXArMQpx
+PSEwfX1nPXM+MT9nKygiIChhdCBsaW5lICIrcysiLCBjaGFyYWN0ZXIgIisoZi1yKzEpKyIpXG4iKTpn
+KygiIChhdCBjaGFyYWN0ZXIgIisoZisxKSsiKVxuIikKbj1lLmxlbmd0aApmb3IocD1mO3A8bjsrK3Ap
+e289Qy54Qi5tKGUscCkKaWYobz09PTEwfHxvPT09MTMpe249cApicmVha319aWYobi1yPjc4KWlmKGYt
+cjw3NSl7bT1yKzc1Cmw9cgprPSIiCmo9Ii4uLiJ9ZWxzZXtpZihuLWY8NzUpe2w9bi03NQptPW4Kaj0i
+In1lbHNle2w9Zi0zNgptPWYrMzYKaj0iLi4uIn1rPSIuLi4ifWVsc2V7bT1uCmw9cgprPSIiCmo9IiJ9
+aT1DLnhCLk5qKGUsbCxtKQpyZXR1cm4gZytrK2kraisiXG4iK0MueEIuSXgoIiAiLGYtbCtrLmxlbmd0
+aCkrIl5cbiJ9ZWxzZSByZXR1cm4gZiE9bnVsbD9nKygiIChhdCBvZmZzZXQgIitILmQoZikrIikiKTpn
+fSwKJGlSejoxfQpQLkVILnByb3RvdHlwZT17fQpQLklmLnByb3RvdHlwZT17fQpQLmNYLnByb3RvdHlw
+ZT17CkUyOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD1ILkxoKHRoaXMpCnJldHVybiBILksxKHRoaXMsdC5L
+cShjKS5DKCIxKGNYLkUpIikuYShiKSx0LkMoImNYLkUiKSxjKX0sCmV2OmZ1bmN0aW9uKGEsYil7dmFy
+IHQ9SC5MaCh0aGlzKQpyZXR1cm4gbmV3IEguVTUodGhpcyx0LkMoImEyKGNYLkUpIikuYShiKSx0LkMo
+IlU1PGNYLkU+IikpfSwKZ0E6ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLmdreih0aGlzKQpmb3IodD0w
+O3MuRigpOykrK3QKcmV0dXJuIHR9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIXRoaXMuZ2t6KHRoaXMp
+LkYoKX0sCmdyODpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuZ2t6KHRoaXMpCmlmKCFzLkYoKSl0aHJv
+dyBILmIoSC5XcCgpKQp0PXMuZ2woKQppZihzLkYoKSl0aHJvdyBILmIoSC5kVSgpKQpyZXR1cm4gdH0s
+CkU6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscT0iaW5kZXgiClAuVUkoYixxLHUucCkKUC5rMShiLHEp
+CmZvcih0PXRoaXMuZ2t6KHRoaXMpLHM9MDt0LkYoKTspe3I9dC5nbCgpCmlmKGI9PT1zKXJldHVybiBy
+Oysrc310aHJvdyBILmIoUC50KGIsdGhpcyxxLG51bGwscykpfSwKWjpmdW5jdGlvbihhKXtyZXR1cm4g
+UC5FUCh0aGlzLCIoIiwiKSIpfX0KUC5Bbi5wcm90b3R5cGU9e30KUC56TS5wcm90b3R5cGU9eyRpYlE6
+MSwkaWNYOjF9ClAuWjAucHJvdG90eXBlPXt9ClAuTjMucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXty
+ZXR1cm4iTWFwRW50cnkoIitILmQodGhpcy5hKSsiOiAiK0guZCh0aGlzLmIpKyIpIn19ClAuYzgucHJv
+dG90eXBlPXsKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiBQLk1oLnByb3RvdHlwZS5naU8uY2FsbCh0aGlz
+LHRoaXMpfSwKWjpmdW5jdGlvbihhKXtyZXR1cm4ibnVsbCJ9fQpQLmxmLnByb3RvdHlwZT17fQpQLk1o
+LnByb3RvdHlwZT17Y29uc3RydWN0b3I6UC5NaCwkaU1oOjEsCkROOmZ1bmN0aW9uKGEsYil7cmV0dXJu
+IHRoaXM9PT1ifSwKZ2lPOmZ1bmN0aW9uKGEpe3JldHVybiBILmVRKHRoaXMpfSwKWjpmdW5jdGlvbihh
+KXtyZXR1cm4iSW5zdGFuY2Ugb2YgJyIrSC5kKEgubGgodGhpcykpKyInIn0sCmU3OmZ1bmN0aW9uKGEs
+Yil7dS5vLmEoYikKdGhyb3cgSC5iKFAubHIodGhpcyxiLmdXYSgpLGIuZ25kKCksYi5nVm0oKSkpfSwK
+dG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5aKHRoaXMpfX0KUC5PZC5wcm90b3R5cGU9e30K
+UC5pYi5wcm90b3R5cGU9eyRpT2Q6MX0KUC54dS5wcm90b3R5cGU9e30KUC5Hei5wcm90b3R5cGU9e30K
+UC5aZC5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiIifSwKJGlHejoxfQpQLnFVLnByb3Rv
+dHlwZT17JGl2WDoxfQpQLlJuLnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEu
+bGVuZ3RofSwKWjpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEKcmV0dXJuIHQuY2hhckNvZGVBdCgwKT09
+MD90OnR9LAokaUJMOjF9ClAuR0QucHJvdG90eXBlPXt9ClAubjEucHJvdG90eXBlPXsKJDI6ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzLHIscQp1LmYuYShhKQpILmMoYikKdD1KLnJZKGIpLk9ZKGIsIj0iKQppZih0
+PT09LTEpe2lmKGIhPT0iIilhLlkoMCxQLmt1KGIsMCxiLmxlbmd0aCx0aGlzLmEsITApLCIiKX1lbHNl
+IGlmKHQhPT0wKXtzPUMueEIuTmooYiwwLHQpCnI9Qy54Qi5HKGIsdCsxKQpxPXRoaXMuYQphLlkoMCxQ
+Lmt1KHMsMCxzLmxlbmd0aCxxLCEwKSxQLmt1KHIsMCxyLmxlbmd0aCxxLCEwKSl9cmV0dXJuIGF9LAok
+UzoxOX0KUC5jUy5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe3Rocm93IEguYihQLnJyKCJJbGxl
+Z2FsIElQdjQgYWRkcmVzcywgIithLHRoaXMuYSxiKSl9LAokUzo0Nn0KUC5WQy5wcm90b3R5cGU9ewok
+MjpmdW5jdGlvbihhLGIpe3Rocm93IEguYihQLnJyKCJJbGxlZ2FsIElQdjYgYWRkcmVzcywgIithLHRo
+aXMuYSxiKSl9LAokMTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy4kMihhLG51bGwpfSwKJFM6NDd9ClAu
+SlQucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt2YXIgdAppZihiLWE+NCl0aGlzLmEuJDIoImFu
+IElQdjYgcGFydCBjYW4gb25seSBjb250YWluIGEgbWF4aW11bSBvZiA0IGhleCBkaWdpdHMiLGEpCnQ9
+UC5RQShDLnhCLk5qKHRoaXMuYixhLGIpLG51bGwsMTYpCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0
+dXJuIHQuSigpCmlmKHQ8MHx8dD42NTUzNSl0aGlzLmEuJDIoImVhY2ggcGFydCBtdXN0IGJlIGluIHRo
+ZSByYW5nZSBvZiBgMHgwLi4weEZGRkZgIixhKQpyZXR1cm4gdH0sCiRTOjQ4fQpQLkRuLnByb3RvdHlw
+ZT17CmdrdTpmdW5jdGlvbigpe3JldHVybiB0aGlzLmJ9LApnSmY6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhp
+cy5jCmlmKHQ9PW51bGwpcmV0dXJuIiIKaWYoQy54Qi5uKHQsIlsiKSlyZXR1cm4gQy54Qi5Oaih0LDEs
+dC5sZW5ndGgtMSkKcmV0dXJuIHR9LApndHA6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5kCmlmKHQ9PW51
+bGwpcmV0dXJuIFAud0sodGhpcy5hKQpyZXR1cm4gdH0sCmd0UDpmdW5jdGlvbigpe3ZhciB0PXRoaXMu
+ZgpyZXR1cm4gdD09bnVsbD8iIjp0fSwKZ0thOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5yCnJldHVybiB0
+PT1udWxsPyIiOnR9LApubTpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbyxuLG0sbD10aGlzCnUu
+WC5hKG51bGwpCnUuay5hKGIpCnQ9bC5hCnM9dD09PSJmaWxlIgpyPWwuYgpxPWwuZApwPWwuYwppZigh
+KHAhPW51bGwpKXA9ci5sZW5ndGghPT0wfHxxIT1udWxsfHxzPyIiOm51bGwKbz1sLmUKaWYoIXMpbj1w
+IT1udWxsJiZvLmxlbmd0aCE9PTAKZWxzZSBuPSEwCmlmKG4mJiFDLnhCLm4obywiLyIpKW89Ii8iK28K
+bT1QLmxlKG51bGwsMCwwLGIpCnJldHVybiBuZXcgUC5Ebih0LHIscCxxLG8sbSxsLnIpfSwKZ0ZqOmZ1
+bmN0aW9uKCl7dmFyIHQscz10aGlzLngKaWYocyE9bnVsbClyZXR1cm4gcwp0PXRoaXMuZQppZih0Lmxl
+bmd0aCE9PTAmJkMueEIuVyh0LDApPT09NDcpdD1DLnhCLkcodCwxKQpzPXQ9PT0iIj9DLnhEOlAuQUYo
+bmV3IEgubEooSC5WTSh0LnNwbGl0KCIvIiksdS5zKSx1LmRPLmEoUC5QSCgpKSx1LmRvKSx1Lk4pCnRo
+aXMuc282KHMpCnJldHVybiBzfSwKZ2hZOmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzCmlmKHMuUT09bnVs
+bCl7dD1zLmYKcy5zUkgobmV3IFAuR2ooUC5XWCh0PT1udWxsPyIiOnQpLHUudikpfXJldHVybiBzLlF9
+LApKaDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscixxLHAsbwpmb3IodD0wLHM9MDtDLnhCLlFpKGIsIi4u
+LyIscyk7KXtzKz0zOysrdH1yPUMueEIuY24oYSwiLyIpCndoaWxlKCEwKXtpZighKHI+MCYmdD4wKSli
+cmVhawpxPUMueEIuUGsoYSwiLyIsci0xKQppZihxPDApYnJlYWsKcD1yLXEKbz1wIT09MgppZighb3x8
+cD09PTMpaWYoQy54Qi5tKGEscSsxKT09PTQ2KW89IW98fEMueEIubShhLHErMik9PT00NgplbHNlIG89
+ITEKZWxzZSBvPSExCmlmKG8pYnJlYWs7LS10CnI9cX1yZXR1cm4gQy54Qi5pNyhhLHIrMSxudWxsLEMu
+eEIuRyhiLHMtMyp0KSl9LApaSTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5tUyhQLmhLKGEpKX0sCm1T
+OmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrPXRoaXMsaj1udWxsCmlmKGEuZ0ZpKCku
+bGVuZ3RoIT09MCl7dD1hLmdGaSgpCmlmKGEuZ2NqKCkpe3M9YS5na3UoKQpyPWEuZ0pmKGEpCnE9YS5n
+eEEoKT9hLmd0cChhKTpqfWVsc2V7cT1qCnI9cQpzPSIifXA9UC54ZShhLmdJaShhKSkKbz1hLmdRRCgp
+P2EuZ3RQKCk6an1lbHNle3Q9ay5hCmlmKGEuZ2NqKCkpe3M9YS5na3UoKQpyPWEuZ0pmKGEpCnE9UC53
+QihhLmd4QSgpP2EuZ3RwKGEpOmosdCkKcD1QLnhlKGEuZ0lpKGEpKQpvPWEuZ1FEKCk/YS5ndFAoKTpq
+fWVsc2V7cz1rLmIKcj1rLmMKcT1rLmQKaWYoYS5nSWkoYSk9PT0iIil7cD1rLmUKbz1hLmdRRCgpP2Eu
+Z3RQKCk6ay5mfWVsc2V7aWYoYS5ndFQoKSlwPVAueGUoYS5nSWkoYSkpCmVsc2V7bj1rLmUKaWYobi5s
+ZW5ndGg9PT0wKWlmKHI9PW51bGwpcD10Lmxlbmd0aD09PTA/YS5nSWkoYSk6UC54ZShhLmdJaShhKSkK
+ZWxzZSBwPVAueGUoIi8iK2EuZ0lpKGEpKQplbHNle209ay5KaChuLGEuZ0lpKGEpKQpsPXQubGVuZ3Ro
+PT09MAppZighbHx8ciE9bnVsbHx8Qy54Qi5uKG4sIi8iKSlwPVAueGUobSkKZWxzZSBwPVAud0YobSwh
+bHx8ciE9bnVsbCl9fW89YS5nUUQoKT9hLmd0UCgpOmp9fX1yZXR1cm4gbmV3IFAuRG4odCxzLHIscSxw
+LG8sYS5nWjgoKT9hLmdLYSgpOmopfSwKZ2NqOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYyE9bnVsbH0s
+Cmd4QTpmdW5jdGlvbigpe3JldHVybiB0aGlzLmQhPW51bGx9LApnUUQ6ZnVuY3Rpb24oKXtyZXR1cm4g
+dGhpcy5mIT1udWxsfSwKZ1o4OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuciE9bnVsbH0sCmd0VDpmdW5j
+dGlvbigpe3JldHVybiBDLnhCLm4odGhpcy5lLCIvIil9LAp0NDpmdW5jdGlvbigpe3ZhciB0LHMscj10
+aGlzLHE9ci5hCmlmKHEhPT0iIiYmcSE9PSJmaWxlIil0aHJvdyBILmIoUC5MNCgiQ2Fubm90IGV4dHJh
+Y3QgYSBmaWxlIHBhdGggZnJvbSBhICIrSC5kKHEpKyIgVVJJIikpCnE9ci5mCmlmKChxPT1udWxsPyIi
+OnEpIT09IiIpdGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBleHRyYWN0IGEgZmlsZSBwYXRoIGZyb20gYSBV
+Ukkgd2l0aCBhIHF1ZXJ5IGNvbXBvbmVudCIpKQpxPXIucgppZigocT09bnVsbD8iIjpxKSE9PSIiKXRo
+cm93IEguYihQLkw0KCJDYW5ub3QgZXh0cmFjdCBhIGZpbGUgcGF0aCBmcm9tIGEgVVJJIHdpdGggYSBm
+cmFnbWVudCBjb21wb25lbnQiKSkKdD0kLk94KCkKaWYoSC5vVCh0KSlxPVAubW4ocikKZWxzZXtpZihy
+LmMhPW51bGwmJnIuZ0pmKHIpIT09IiIpSC52aChQLkw0KCJDYW5ub3QgZXh0cmFjdCBhIG5vbi1XaW5k
+b3dzIGZpbGUgcGF0aCBmcm9tIGEgZmlsZSBVUkkgd2l0aCBhbiBhdXRob3JpdHkiKSkKcz1yLmdGaigp
+ClAua0UocywhMSkKcT1QLnZnKEMueEIubihyLmUsIi8iKT8iLyI6IiIscywiLyIpCnE9cS5jaGFyQ29k
+ZUF0KDApPT0wP3E6cX1yZXR1cm4gcX0sClo6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9dGhpcyxwPXEu
+eQppZihwPT1udWxsKXtwPXEuYQp0PXAubGVuZ3RoIT09MD9wKyI6IjoiIgpzPXEuYwpyPXM9PW51bGwK
+aWYoIXJ8fHA9PT0iZmlsZSIpe3A9dCsiLy8iCnQ9cS5iCmlmKHQubGVuZ3RoIT09MClwPXArdCsiQCIK
+aWYoIXIpcCs9cwp0PXEuZAppZih0IT1udWxsKXA9cCsiOiIrSC5kKHQpfWVsc2UgcD10CnArPXEuZQp0
+PXEuZgppZih0IT1udWxsKXA9cCsiPyIrdAp0PXEucgppZih0IT1udWxsKXA9cCsiIyIrdApwPXEueT1w
+LmNoYXJDb2RlQXQoMCk9PTA/cDpwfXJldHVybiBwfSwKRE46ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHI9
+dGhpcwppZihiPT1udWxsKXJldHVybiExCmlmKHI9PT1iKXJldHVybiEwCmlmKHUudy5iKGIpKWlmKHIu
+YT09Yi5nRmkoKSlpZihyLmMhPW51bGw9PT1iLmdjaigpKWlmKHIuYj09Yi5na3UoKSlpZihyLmdKZihy
+KT09Yi5nSmYoYikpaWYoci5ndHAocik9PWIuZ3RwKGIpKWlmKHIuZT09PWIuZ0lpKGIpKXt0PXIuZgpz
+PXQ9PW51bGwKaWYoIXM9PT1iLmdRRCgpKXtpZihzKXQ9IiIKaWYodD09PWIuZ3RQKCkpe3Q9ci5yCnM9
+dD09bnVsbAppZighcz09PWIuZ1o4KCkpe2lmKHMpdD0iIgp0PXQ9PT1iLmdLYSgpfWVsc2UgdD0hMX1l
+bHNlIHQ9ITF9ZWxzZSB0PSExfWVsc2UgdD0hMQplbHNlIHQ9ITEKZWxzZSB0PSExCmVsc2UgdD0hMQpl
+bHNlIHQ9ITEKZWxzZSB0PSExCmVsc2UgdD0hMQpyZXR1cm4gdH0sCmdpTzpmdW5jdGlvbihhKXt2YXIg
+dD10aGlzLnoKcmV0dXJuIHQ9PW51bGw/dGhpcy56PUMueEIuZ2lPKHRoaXMuWigwKSk6dH0sCnNvNjpm
+dW5jdGlvbihhKXt0aGlzLng9dS5hLmEoYSl9LApzUkg6ZnVuY3Rpb24oYSl7dGhpcy5RPXUuZi5hKGEp
+fSwKJGlpRDoxLApnRmk6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5hfSwKZ0lpOmZ1bmN0aW9uKGEpe3Jl
+dHVybiB0aGlzLmV9fQpQLmUxLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3Rocm93IEguYihQLnJy
+KCJJbnZhbGlkIHBvcnQiLHRoaXMuYSx0aGlzLmIrMSkpfSwKJFM6MTN9ClAuTlkucHJvdG90eXBlPXsK
+JDE6ZnVuY3Rpb24oYSl7dmFyIHQ9IklsbGVnYWwgcGF0aCBjaGFyYWN0ZXIgIgpILmMoYSkKaWYoSi56
+bChhLCIvIikpaWYodGhpcy5hKXRocm93IEguYihQLnhZKHQrYSkpCmVsc2UgdGhyb3cgSC5iKFAuTDQo
+dCthKSl9LAokUzoxM30KUC5SWi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gUC5lUChD
+LlpKLEguYyhhKSxDLnhNLCExKX0sCiRTOjV9ClAuTUUucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxi
+KXt2YXIgdD10aGlzLmIscz10aGlzLmEKdC5hKz1zLmEKcy5hPSImIgpzPXQuYSs9SC5kKFAuZVAoQy5G
+MyxhLEMueE0sITApKQppZihiIT1udWxsJiZiLmxlbmd0aCE9PTApe3QuYT1zKyI9Igp0LmErPUguZChQ
+LmVQKEMuRjMsYixDLnhNLCEwKSl9fSwKJFM6MjJ9ClAueTUucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24o
+YSxiKXt2YXIgdCxzCkguYyhhKQppZihiPT1udWxsfHx0eXBlb2YgYj09InN0cmluZyIpdGhpcy5hLiQy
+KGEsSC5jKGIpKQplbHNlIGZvcih0PUouSVQodS5SLmEoYikpLHM9dGhpcy5hO3QuRigpOylzLiQyKGEs
+SC5jKHQuZ2woKSkpfSwKJFM6MTJ9ClAuUEUucHJvdG90eXBlPXsKZ2xSOmZ1bmN0aW9uKCl7dmFyIHQs
+cyxyLHEscD10aGlzLG89bnVsbCxuPXAuYwppZihuIT1udWxsKXJldHVybiBuCm49cC5iCmlmKDA+PW4u
+bGVuZ3RoKXJldHVybiBILmsobiwwKQp0PXAuYQpuPW5bMF0rMQpzPUMueEIuWFUodCwiPyIsbikKcj10
+Lmxlbmd0aAppZihzPj0wKXtxPVAuUEkodCxzKzEscixDLlZDLCExKQpyPXN9ZWxzZSBxPW8KcmV0dXJu
+IHAuYz1uZXcgUC5xZSgiZGF0YSIsbyxvLG8sUC5QSSh0LG4scixDLldkLCExKSxxLG8pfSwKWjpmdW5j
+dGlvbihhKXt2YXIgdCxzPXRoaXMuYgppZigwPj1zLmxlbmd0aClyZXR1cm4gSC5rKHMsMCkKdD10aGlz
+LmEKcmV0dXJuIHNbMF09PT0tMT8iZGF0YToiK3Q6dH19ClAucTMucHJvdG90eXBlPXsKJDE6ZnVuY3Rp
+b24oYSl7cmV0dXJuIG5ldyBVaW50OEFycmF5KDk2KX0sCiRTOjIzfQpQLnlJLnByb3RvdHlwZT17CiQy
+OmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcy5hCmlmKGE+PXQubGVuZ3RoKXJldHVybiBILmsodCxhKQp0
+PXRbYV0KSi5DTSh0LDAsOTYsYikKcmV0dXJuIHR9LAokUzoyNH0KUC5jNi5wcm90b3R5cGU9ewokMzpm
+dW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEKZm9yKHQ9Yi5sZW5ndGgscz1hLmxlbmd0aCxyPTA7cjx0
+Oysrcil7cT1DLnhCLlcoYixyKV45NgppZihxPj1zKXJldHVybiBILmsoYSxxKQphW3FdPWN9fX0KUC5x
+ZC5wcm90b3R5cGU9ewokMzpmdW5jdGlvbihhLGIsYyl7dmFyIHQscyxyLHEKZm9yKHQ9Qy54Qi5XKGIs
+MCkscz1DLnhCLlcoYiwxKSxyPWEubGVuZ3RoO3Q8PXM7Kyt0KXtxPSh0Xjk2KT4+PjAKaWYocT49cily
+ZXR1cm4gSC5rKGEscSkKYVtxXT1jfX19ClAuVWYucHJvdG90eXBlPXsKZ2NqOmZ1bmN0aW9uKCl7cmV0
+dXJuIHRoaXMuYz4wfSwKZ3hBOmZ1bmN0aW9uKCl7dmFyIHQscwppZih0aGlzLmM+MCl7dD10aGlzLmQK
+aWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1cm4gdC5oKCkKcz10aGlzLmUKaWYodHlwZW9mIHMhPT0i
+bnVtYmVyIilyZXR1cm4gSC5wWShzKQpzPXQrMTxzCnQ9c31lbHNlIHQ9ITEKcmV0dXJuIHR9LApnUUQ6
+ZnVuY3Rpb24oKXt2YXIgdD10aGlzLmYKaWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1cm4gdC5KKCkK
+cmV0dXJuIHQ8dGhpcy5yfSwKZ1o4OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucjx0aGlzLmEubGVuZ3Ro
+fSwKZ053OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuYj09PTQmJkMueEIubih0aGlzLmEsImZpbGUiKX0s
+Cmd2aDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmI9PT00JiZDLnhCLm4odGhpcy5hLCJodHRwIil9LApn
+UmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5iPT09NSYmQy54Qi5uKHRoaXMuYSwiaHR0cHMiKX0sCmd0
+VDpmdW5jdGlvbigpe3JldHVybiBDLnhCLlFpKHRoaXMuYSwiLyIsdGhpcy5lKX0sCmdGaTpmdW5jdGlv
+bigpe3ZhciB0LHM9dGhpcyxyPSJwYWNrYWdlIixxPXMuYgppZihxPD0wKXJldHVybiIiCnQ9cy54Cmlm
+KHQhPW51bGwpcmV0dXJuIHQKaWYocy5ndmgoKSlxPXMueD0iaHR0cCIKZWxzZSBpZihzLmdSZSgpKXtz
+Lng9Imh0dHBzIgpxPSJodHRwcyJ9ZWxzZSBpZihzLmdOdygpKXtzLng9ImZpbGUiCnE9ImZpbGUifWVs
+c2UgaWYocT09PTcmJkMueEIubihzLmEscikpe3MueD1yCnE9cn1lbHNle3E9Qy54Qi5OaihzLmEsMCxx
+KQpzLng9cX1yZXR1cm4gcX0sCmdrdTpmdW5jdGlvbigpe3ZhciB0PXRoaXMuYyxzPXRoaXMuYiszCnJl
+dHVybiB0PnM/Qy54Qi5Oaih0aGlzLmEscyx0LTEpOiIifSwKZ0pmOmZ1bmN0aW9uKGEpe3ZhciB0PXRo
+aXMuYwpyZXR1cm4gdD4wP0MueEIuTmoodGhpcy5hLHQsdGhpcy5kKToiIn0sCmd0cDpmdW5jdGlvbihh
+KXt2YXIgdCxzPXRoaXMKaWYocy5neEEoKSl7dD1zLmQKaWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1
+cm4gdC5oKCkKcmV0dXJuIFAuUUEoQy54Qi5OaihzLmEsdCsxLHMuZSksbnVsbCxudWxsKX1pZihzLmd2
+aCgpKXJldHVybiA4MAppZihzLmdSZSgpKXJldHVybiA0NDMKcmV0dXJuIDB9LApnSWk6ZnVuY3Rpb24o
+YSl7cmV0dXJuIEMueEIuTmoodGhpcy5hLHRoaXMuZSx0aGlzLmYpfSwKZ3RQOmZ1bmN0aW9uKCl7dmFy
+IHQ9dGhpcy5mLHM9dGhpcy5yCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuSigpCnJldHVy
+biB0PHM/Qy54Qi5Oaih0aGlzLmEsdCsxLHMpOiIifSwKZ0thOmZ1bmN0aW9uKCl7dmFyIHQ9dGhpcy5y
+LHM9dGhpcy5hCnJldHVybiB0PHMubGVuZ3RoP0MueEIuRyhzLHQrMSk6IiJ9LApnRmo6ZnVuY3Rpb24o
+KXt2YXIgdCxzLHI9dGhpcy5lLHE9dGhpcy5mLHA9dGhpcy5hCmlmKEMueEIuUWkocCwiLyIscikpe2lm
+KHR5cGVvZiByIT09Im51bWJlciIpcmV0dXJuIHIuaCgpOysrcn1pZihyPT1xKXJldHVybiBDLnhECnQ9
+SC5WTShbXSx1LnMpCnM9cgp3aGlsZSghMCl7aWYodHlwZW9mIHMhPT0ibnVtYmVyIilyZXR1cm4gcy5K
+KCkKaWYodHlwZW9mIHEhPT0ibnVtYmVyIilyZXR1cm4gSC5wWShxKQppZighKHM8cSkpYnJlYWsKaWYo
+Qy54Qi5tKHAscyk9PT00Nyl7Qy5ObS5pKHQsQy54Qi5OaihwLHIscykpCnI9cysxfSsrc31DLk5tLmko
+dCxDLnhCLk5qKHAscixxKSkKcmV0dXJuIFAuQUYodCx1Lk4pfSwKZ2hZOmZ1bmN0aW9uKCl7dmFyIHQ9
+dGhpcy5mCmlmKHR5cGVvZiB0IT09Im51bWJlciIpcmV0dXJuIHQuSigpCmlmKHQ+PXRoaXMucilyZXR1
+cm4gQy5XTwpyZXR1cm4gbmV3IFAuR2ooUC5XWCh0aGlzLmd0UCgpKSx1LnYpfSwKa1g6ZnVuY3Rpb24o
+YSl7dmFyIHQscz10aGlzLmQKaWYodHlwZW9mIHMhPT0ibnVtYmVyIilyZXR1cm4gcy5oKCkKdD1zKzEK
+cmV0dXJuIHQrYS5sZW5ndGg9PT10aGlzLmUmJkMueEIuUWkodGhpcy5hLGEsdCl9LApOOTpmdW5jdGlv
+bigpe3ZhciB0PXRoaXMscz10LnIscj10LmEKaWYocz49ci5sZW5ndGgpcmV0dXJuIHQKcmV0dXJuIG5l
+dyBQLlVmKEMueEIuTmoociwwLHMpLHQuYix0LmMsdC5kLHQuZSx0LmYscyx0LngpfSwKbm06ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtLGwsayxqPXRoaXMsaT1udWxsCnUuWC5hKG51bGwpCnUu
+ay5hKGIpCnQ9ai5nRmkoKQpzPXQ9PT0iZmlsZSIKcj1qLmMKcT1yPjA/Qy54Qi5OaihqLmEsai5iKzMs
+cik6IiIKcD1qLmd4QSgpP2ouZ3RwKGopOmkKcj1qLmMKaWYocj4wKW89Qy54Qi5OaihqLmEscixqLmQp
+CmVsc2Ugbz1xLmxlbmd0aCE9PTB8fHAhPW51bGx8fHM/IiI6aQpyPWouYQpuPUMueEIuTmoocixqLmUs
+ai5mKQppZighcyltPW8hPW51bGwmJm4ubGVuZ3RoIT09MAplbHNlIG09ITAKaWYobSYmIUMueEIubihu
+LCIvIikpbj0iLyIrbgpsPVAubGUoaSwwLDAsYikKbT1qLnIKaz1tPHIubGVuZ3RoP0MueEIuRyhyLG0r
+MSk6aQpyZXR1cm4gbmV3IFAuRG4odCxxLG8scCxuLGwsayl9LApaSTpmdW5jdGlvbihhKXtyZXR1cm4g
+dGhpcy5tUyhQLmhLKGEpKX0sCm1TOmZ1bmN0aW9uKGEpe2lmKGEgaW5zdGFuY2VvZiBQLlVmKXJldHVy
+biB0aGlzLnUxKHRoaXMsYSkKcmV0dXJuIHRoaXMudnMoKS5tUyhhKX0sCnUxOmZ1bmN0aW9uKGEsYil7
+dmFyIHQscyxyLHEscCxvLG4sbSxsLGssaixpLGgsZyxmLGU9Yi5iCmlmKGU+MClyZXR1cm4gYgp0PWIu
+YwppZih0PjApe3M9YS5iCmlmKHM8PTApcmV0dXJuIGIKaWYoYS5nTncoKSlyPWIuZSE9Yi5mCmVsc2Ug
+aWYoYS5ndmgoKSlyPSFiLmtYKCI4MCIpCmVsc2Ugcj0hYS5nUmUoKXx8IWIua1goIjQ0MyIpCmlmKHIp
+e3E9cysxCnA9Qy54Qi5OaihhLmEsMCxxKStDLnhCLkcoYi5hLGUrMSkKZT1iLmQKaWYodHlwZW9mIGUh
+PT0ibnVtYmVyIilyZXR1cm4gZS5oKCkKbz1iLmUKaWYodHlwZW9mIG8hPT0ibnVtYmVyIilyZXR1cm4g
+by5oKCkKbj1iLmYKaWYodHlwZW9mIG4hPT0ibnVtYmVyIilyZXR1cm4gbi5oKCkKcmV0dXJuIG5ldyBQ
+LlVmKHAscyx0K3EsZStxLG8rcSxuK3EsYi5yK3EsYS54KX1lbHNlIHJldHVybiB0aGlzLnZzKCkubVMo
+Yil9bT1iLmUKZT1iLmYKaWYobT09ZSl7dD1iLnIKaWYodHlwZW9mIGUhPT0ibnVtYmVyIilyZXR1cm4g
+ZS5KKCkKaWYoZTx0KXtzPWEuZgppZih0eXBlb2YgcyE9PSJudW1iZXIiKXJldHVybiBzLkhOKCkKcT1z
+LWUKcmV0dXJuIG5ldyBQLlVmKEMueEIuTmooYS5hLDAscykrQy54Qi5HKGIuYSxlKSxhLmIsYS5jLGEu
+ZCxhLmUsZStxLHQrcSxhLngpfWU9Yi5hCmlmKHQ8ZS5sZW5ndGgpe3M9YS5yCnJldHVybiBuZXcgUC5V
+ZihDLnhCLk5qKGEuYSwwLHMpK0MueEIuRyhlLHQpLGEuYixhLmMsYS5kLGEuZSxhLmYsdCsocy10KSxh
+LngpfXJldHVybiBhLk45KCl9dD1iLmEKaWYoQy54Qi5RaSh0LCIvIixtKSl7cz1hLmUKaWYodHlwZW9m
+IHMhPT0ibnVtYmVyIilyZXR1cm4gcy5ITigpCmlmKHR5cGVvZiBtIT09Im51bWJlciIpcmV0dXJuIEgu
+cFkobSkKcT1zLW0KcD1DLnhCLk5qKGEuYSwwLHMpK0MueEIuRyh0LG0pCmlmKHR5cGVvZiBlIT09Im51
+bWJlciIpcmV0dXJuIGUuaCgpCnJldHVybiBuZXcgUC5VZihwLGEuYixhLmMsYS5kLHMsZStxLGIucitx
+LGEueCl9bD1hLmUKaz1hLmYKaWYobD09ayYmYS5jPjApe2Zvcig7Qy54Qi5RaSh0LCIuLi8iLG0pOyl7
+aWYodHlwZW9mIG0hPT0ibnVtYmVyIilyZXR1cm4gbS5oKCkKbSs9M31pZih0eXBlb2YgbCE9PSJudW1i
+ZXIiKXJldHVybiBsLkhOKCkKaWYodHlwZW9mIG0hPT0ibnVtYmVyIilyZXR1cm4gSC5wWShtKQpxPWwt
+bSsxCnA9Qy54Qi5OaihhLmEsMCxsKSsiLyIrQy54Qi5HKHQsbSkKaWYodHlwZW9mIGUhPT0ibnVtYmVy
+IilyZXR1cm4gZS5oKCkKcmV0dXJuIG5ldyBQLlVmKHAsYS5iLGEuYyxhLmQsbCxlK3EsYi5yK3EsYS54
+KX1qPWEuYQpmb3IoaT1sO0MueEIuUWkoaiwiLi4vIixpKTspe2lmKHR5cGVvZiBpIT09Im51bWJlciIp
+cmV0dXJuIGkuaCgpCmkrPTN9aD0wCndoaWxlKCEwKXtpZih0eXBlb2YgbSE9PSJudW1iZXIiKXJldHVy
+biBtLmgoKQpnPW0rMwppZih0eXBlb2YgZSE9PSJudW1iZXIiKXJldHVybiBILnBZKGUpCmlmKCEoZzw9
+ZSYmQy54Qi5RaSh0LCIuLi8iLG0pKSlicmVhazsrK2gKbT1nfWY9IiIKd2hpbGUoITApe2lmKHR5cGVv
+ZiBrIT09Im51bWJlciIpcmV0dXJuIGsub3MoKQppZih0eXBlb2YgaSE9PSJudW1iZXIiKXJldHVybiBI
+LnBZKGkpCmlmKCEoaz5pKSlicmVhazstLWsKaWYoQy54Qi5tKGosayk9PT00Nyl7aWYoaD09PTApe2Y9
+Ii8iCmJyZWFrfS0taApmPSIvIn19aWYoaz09PWkmJmEuYjw9MCYmIUMueEIuUWkoaiwiLyIsbCkpe20t
+PWgqMwpmPSIifXE9ay1tK2YubGVuZ3RoCnJldHVybiBuZXcgUC5VZihDLnhCLk5qKGosMCxrKStmK0Mu
+eEIuRyh0LG0pLGEuYixhLmMsYS5kLGwsZStxLGIucitxLGEueCl9LAp0NDpmdW5jdGlvbigpe3ZhciB0
+LHMscixxLHA9dGhpcwppZihwLmI+PTAmJiFwLmdOdygpKXRocm93IEguYihQLkw0KCJDYW5ub3QgZXh0
+cmFjdCBhIGZpbGUgcGF0aCBmcm9tIGEgIitILmQocC5nRmkoKSkrIiBVUkkiKSkKdD1wLmYKcz1wLmEK
+aWYodHlwZW9mIHQhPT0ibnVtYmVyIilyZXR1cm4gdC5KKCkKaWYodDxzLmxlbmd0aCl7aWYodDxwLnIp
+dGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBleHRyYWN0IGEgZmlsZSBwYXRoIGZyb20gYSBVUkkgd2l0aCBh
+IHF1ZXJ5IGNvbXBvbmVudCIpKQp0aHJvdyBILmIoUC5MNCgiQ2Fubm90IGV4dHJhY3QgYSBmaWxlIHBh
+dGggZnJvbSBhIFVSSSB3aXRoIGEgZnJhZ21lbnQgY29tcG9uZW50IikpfXI9JC5PeCgpCmlmKEgub1Qo
+cikpdD1QLm1uKHApCmVsc2V7cT1wLmQKaWYodHlwZW9mIHEhPT0ibnVtYmVyIilyZXR1cm4gSC5wWShx
+KQppZihwLmM8cSlILnZoKFAuTDQoIkNhbm5vdCBleHRyYWN0IGEgbm9uLVdpbmRvd3MgZmlsZSBwYXRo
+IGZyb20gYSBmaWxlIFVSSSB3aXRoIGFuIGF1dGhvcml0eSIpKQp0PUMueEIuTmoocyxwLmUsdCl9cmV0
+dXJuIHR9LApnaU86ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy55CnJldHVybiB0PT1udWxsP3RoaXMueT1D
+LnhCLmdpTyh0aGlzLmEpOnR9LApETjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKaWYo
+dGhpcz09PWIpcmV0dXJuITAKcmV0dXJuIHUudy5iKGIpJiZ0aGlzLmE9PT1iLlooMCl9LAp2czpmdW5j
+dGlvbigpe3ZhciB0PXRoaXMscz1udWxsLHI9dC5nRmkoKSxxPXQuZ2t1KCkscD10LmM+MD90LmdKZih0
+KTpzLG89dC5neEEoKT90Lmd0cCh0KTpzLG49dC5hLG09dC5mLGw9Qy54Qi5OaihuLHQuZSxtKSxrPXQu
+cgppZih0eXBlb2YgbSE9PSJudW1iZXIiKXJldHVybiBtLkooKQptPW08az90Lmd0UCgpOnMKcmV0dXJu
+IG5ldyBQLkRuKHIscSxwLG8sbCxtLGs8bi5sZW5ndGg/dC5nS2EoKTpzKX0sClo6ZnVuY3Rpb24oYSl7
+cmV0dXJuIHRoaXMuYX0sCiRpaUQ6MX0KUC5xZS5wcm90b3R5cGU9e30KVy5xRS5wcm90b3R5cGU9e30K
+Vy5HaC5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiBTdHJpbmcoYSl9LAokaUdoOjF9Clcu
+ZlkucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4gU3RyaW5nKGEpfX0KVy5uQi5wcm90b3R5
+cGU9eyRpbkI6MX0KVy5Bei5wcm90b3R5cGU9eyRpQXo6MX0KVy5RUC5wcm90b3R5cGU9eyRpUVA6MX0K
+Vy5ueC5wcm90b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9fQpXLm9KLnByb3Rv
+dHlwZT17CmdBOmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH19ClcuaWQucHJvdG90eXBlPXt9Clcu
+UUYucHJvdG90eXBlPXt9ClcuTmgucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4gU3RyaW5n
+KGEpfX0KVy5JQi5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiJSZWN0YW5nbGUgKCIrSC5k
+KGEubGVmdCkrIiwgIitILmQoYS50b3ApKyIpICIrSC5kKGEud2lkdGgpKyIgeCAiK0guZChhLmhlaWdo
+dCl9LApETjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKcmV0dXJuIHUucS5iKGIpJiZh
+LmxlZnQ9PWIubGVmdCYmYS50b3A9PWIudG9wJiZhLndpZHRoPT1iLndpZHRoJiZhLmhlaWdodD09Yi5o
+ZWlnaHR9LApnaU86ZnVuY3Rpb24oYSl7cmV0dXJuIFcuckUoSi5oZihhLmxlZnQpLEouaGYoYS50b3Ap
+LEouaGYoYS53aWR0aCksSi5oZihhLmhlaWdodCkpfSwKJGl0bjoxfQpXLm43LnByb3RvdHlwZT17CmdB
+OmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH19Clcud3oucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24o
+YSl7cmV0dXJuIHRoaXMuYS5sZW5ndGh9LApxOmZ1bmN0aW9uKGEsYil7dmFyIHQKSC5XWShiKQp0PXRo
+aXMuYQppZihiPDB8fGI+PXQubGVuZ3RoKXJldHVybiBILmsodCxiKQpyZXR1cm4gdGhpcy4kdGkuYy5h
+KHRbYl0pfSwKWTpmdW5jdGlvbihhLGIsYyl7dGhpcy4kdGkuYy5hKGMpCnRocm93IEguYihQLkw0KCJD
+YW5ub3QgbW9kaWZ5IGxpc3QiKSl9fQpXLmN2LnByb3RvdHlwZT17CmdRZzpmdW5jdGlvbihhKXtyZXR1
+cm4gbmV3IFcuaTcoYSl9LApnUDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFcuSTQoYSl9LApzUDpmdW5j
+dGlvbihhLGIpe3ZhciB0CnUuWC5hKGIpCnQ9dGhpcy5nUChhKQp0LlYxKDApCnQuRlYoMCxiKX0sClo6
+ZnVuY3Rpb24oYSl7cmV0dXJuIGEubG9jYWxOYW1lfSwKRkY6ZnVuY3Rpb24oYSl7dmFyIHQ9ISFhLnNj
+cm9sbEludG9WaWV3SWZOZWVkZWQKaWYodClhLnNjcm9sbEludG9WaWV3SWZOZWVkZWQoKQplbHNlIGEu
+c2Nyb2xsSW50b1ZpZXcoKX0sCm56OmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIHQscz10aGlzLnI2KGEs
+YyxkLGUpCnN3aXRjaChiLnRvTG93ZXJDYXNlKCkpe2Nhc2UiYmVmb3JlYmVnaW4iOmEucGFyZW50Tm9k
+ZS5pbnNlcnRCZWZvcmUocyxhKQpicmVhawpjYXNlImFmdGVyYmVnaW4iOnQ9YS5jaGlsZE5vZGVzCmEu
+aW5zZXJ0QmVmb3JlKHMsdC5sZW5ndGg+MD90WzBdOm51bGwpCmJyZWFrCmNhc2UiYmVmb3JlZW5kIjph
+LmFwcGVuZENoaWxkKHMpCmJyZWFrCmNhc2UiYWZ0ZXJlbmQiOmEucGFyZW50Tm9kZS5pbnNlcnRCZWZv
+cmUocyxhLm5leHRTaWJsaW5nKQpicmVhawpkZWZhdWx0OkgudmgoUC54WSgiSW52YWxpZCBwb3NpdGlv
+biAiK2IpKX19LApyNjpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscQppZihjPT1udWxsKXtpZihk
+PT1udWxsKXt0PSQubHQKaWYodD09bnVsbCl7dD1ILlZNKFtdLHUuaSkKcz1uZXcgVy52RCh0KQpDLk5t
+LmkodCxXLlR3KG51bGwpKQpDLk5tLmkodCxXLkJsKCkpCiQubHQ9cwpkPXN9ZWxzZSBkPXR9dD0kLkVV
+CmlmKHQ9PW51bGwpe3Q9bmV3IFcuS28oZCkKJC5FVT10CmM9dH1lbHNle3QuYT1kCmM9dH19ZWxzZSBp
+ZihkIT1udWxsKXRocm93IEguYihQLnhZKCJ2YWxpZGF0b3IgY2FuIG9ubHkgYmUgcGFzc2VkIGlmIHRy
+ZWVTYW5pdGl6ZXIgaXMgbnVsbCIpKQppZigkLnhvPT1udWxsKXt0PWRvY3VtZW50CnM9dC5pbXBsZW1l
+bnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoIiIpCiQueG89cwokLkJPPXMuY3JlYXRlUmFuZ2UoKQpz
+PSQueG8uY3JlYXRlRWxlbWVudCgiYmFzZSIpCnUuY1IuYShzKQpzLmhyZWY9dC5iYXNlVVJJCiQueG8u
+aGVhZC5hcHBlbmRDaGlsZChzKX10PSQueG8KaWYodC5ib2R5PT1udWxsKXtzPXQuY3JlYXRlRWxlbWVu
+dCgiYm9keSIpCnQuYm9keT11LlkuYShzKX10PSQueG8KaWYodS5ZLmIoYSkpcj10LmJvZHkKZWxzZXty
+PXQuY3JlYXRlRWxlbWVudChhLnRhZ05hbWUpCiQueG8uYm9keS5hcHBlbmRDaGlsZChyKX1pZigiY3Jl
+YXRlQ29udGV4dHVhbEZyYWdtZW50IiBpbiB3aW5kb3cuUmFuZ2UucHJvdG90eXBlJiYhQy5ObS50ZyhD
+LlNxLGEudGFnTmFtZSkpeyQuQk8uc2VsZWN0Tm9kZUNvbnRlbnRzKHIpCnE9JC5CTy5jcmVhdGVDb250
+ZXh0dWFsRnJhZ21lbnQoYil9ZWxzZXtyLmlubmVySFRNTD1iCnE9JC54by5jcmVhdGVEb2N1bWVudEZy
+YWdtZW50KCkKZm9yKDt0PXIuZmlyc3RDaGlsZCx0IT1udWxsOylxLmFwcGVuZENoaWxkKHQpfXQ9JC54
+by5ib2R5CmlmKHI9PW51bGw/dCE9bnVsbDpyIT09dClKLkx0KHIpCmMuUG4ocSkKZG9jdW1lbnQuYWRv
+cHROb2RlKHEpCnJldHVybiBxfSwKQUg6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiB0aGlzLnI2KGEsYixj
+LG51bGwpfSwKc2hmOmZ1bmN0aW9uKGEsYil7dGhpcy5ZQyhhLGIpfSwKcGs6ZnVuY3Rpb24oYSxiLGMp
+e2EudGV4dENvbnRlbnQ9bnVsbAphLmFwcGVuZENoaWxkKHRoaXMucjYoYSxiLG51bGwsYykpfSwKWUM6
+ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5wayhhLGIsbnVsbCl9LApnbnM6ZnVuY3Rpb24oYSl7cmV0
+dXJuIGEudGFnTmFtZX0sCmdWbDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFcuZXUoYSwiY2xpY2siLCEx
+LHUuUSl9LAokaWN2OjF9ClcuQ3YucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHUuaC5i
+KHUuQS5hKGEpKX0sCiRTOjI1fQpXLmVhLnByb3RvdHlwZT17JGllYToxfQpXLkQwLnByb3RvdHlwZT17
+Ck9uOmZ1bmN0aW9uKGEsYixjLGQpe3UuVS5hKGMpCmlmKGMhPW51bGwpdGhpcy52KGEsYixjLGQpfSwK
+QjpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIHRoaXMuT24oYSxiLGMsbnVsbCl9LAp2OmZ1bmN0aW9uKGEs
+YixjLGQpe3JldHVybiBhLmFkZEV2ZW50TGlzdGVuZXIoYixILnRSKHUuVS5hKGMpLDEpLGQpfSwKJGlE
+MDoxfQpXLmhILnByb3RvdHlwZT17JGloSDoxfQpXLmg0LnByb3RvdHlwZT17CmdBOmZ1bmN0aW9uKGEp
+e3JldHVybiBhLmxlbmd0aH19ClcuYnIucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIGEu
+bGVuZ3RofX0KVy5WYi5wcm90b3R5cGU9e30KVy5mSi5wcm90b3R5cGU9ewplbzpmdW5jdGlvbihhLGIs
+YyxkKXtyZXR1cm4gYS5vcGVuKGIsYywhMCl9LAokaWZKOjF9Clcud2EucHJvdG90eXBlPXt9ClcuU2cu
+cHJvdG90eXBlPXskaVNnOjF9ClcudTgucHJvdG90eXBlPXsKZ0RyOmZ1bmN0aW9uKGEpe2lmKCJvcmln
+aW4iIGluIGEpcmV0dXJuIGEub3JpZ2luCnJldHVybiBILmQoYS5wcm90b2NvbCkrIi8vIitILmQoYS5o
+b3N0KX0sClo6ZnVuY3Rpb24oYSl7cmV0dXJuIFN0cmluZyhhKX0sCiRpdTg6MX0KVy5PSy5wcm90b3R5
+cGU9eyRpT0s6MX0KVy5lNy5wcm90b3R5cGU9ewpncjg6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hLHM9
+dC5jaGlsZE5vZGVzLmxlbmd0aAppZihzPT09MCl0aHJvdyBILmIoUC5QVigiTm8gZWxlbWVudHMiKSkK
+aWYocz4xKXRocm93IEguYihQLlBWKCJNb3JlIHRoYW4gb25lIGVsZW1lbnQiKSkKcmV0dXJuIHQuZmly
+c3RDaGlsZH0sCkZWOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEKdS5laC5hKGIpCnQ9Yi5hCnM9dGhp
+cy5hCmlmKHQhPT1zKWZvcihyPXQuY2hpbGROb2Rlcy5sZW5ndGgscT0wO3E8cjsrK3Epcy5hcHBlbmRD
+aGlsZCh0LmZpcnN0Q2hpbGQpCnJldHVybn0sClk6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKdS5BLmEo
+YykKdD10aGlzLmEKcz10LmNoaWxkTm9kZXMKaWYoYjwwfHxiPj1zLmxlbmd0aClyZXR1cm4gSC5rKHMs
+YikKdC5yZXBsYWNlQ2hpbGQoYyxzW2JdKX0sCmdrejpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmEuY2hp
+bGROb2RlcwpyZXR1cm4gbmV3IFcuVzkodCx0Lmxlbmd0aCxILnEodCkuQygiVzk8R20uRT4iKSl9LApn
+QTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLmNoaWxkTm9kZXMubGVuZ3RofSwKcTpmdW5jdGlvbihh
+LGIpe3ZhciB0CkguV1koYikKdD10aGlzLmEuY2hpbGROb2RlcwppZihiPDB8fGI+PXQubGVuZ3RoKXJl
+dHVybiBILmsodCxiKQpyZXR1cm4gdFtiXX19ClcudUgucHJvdG90eXBlPXsKd2c6ZnVuY3Rpb24oYSl7
+dmFyIHQ9YS5wYXJlbnROb2RlCmlmKHQhPW51bGwpdC5yZW1vdmVDaGlsZChhKX0sCkQ0OmZ1bmN0aW9u
+KGEpe3ZhciB0CmZvcig7dD1hLmZpcnN0Q2hpbGQsdCE9bnVsbDspYS5yZW1vdmVDaGlsZCh0KX0sClo6
+ZnVuY3Rpb24oYSl7dmFyIHQ9YS5ub2RlVmFsdWUKcmV0dXJuIHQ9PW51bGw/dGhpcy5VKGEpOnR9LAok
+aXVIOjF9ClcuQkgucHJvdG90eXBlPXsKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofSwKcTpm
+dW5jdGlvbihhLGIpe0guV1koYikKaWYoYj4+PjAhPT1ifHxiPj1hLmxlbmd0aCl0aHJvdyBILmIoUC50
+KGIsYSxudWxsLG51bGwsbnVsbCkpCnJldHVybiBhW2JdfSwKWTpmdW5jdGlvbihhLGIsYyl7dS5BLmEo
YykKdGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBhc3NpZ24gZWxlbWVudCBvZiBpbW11dGFibGUgTGlzdC4i
KSl9LApndEg6ZnVuY3Rpb24oYSl7aWYoYS5sZW5ndGg+MClyZXR1cm4gYVswXQp0aHJvdyBILmIoUC5Q
VigiTm8gZWxlbWVudHMiKSl9LApFOmZ1bmN0aW9uKGEsYil7aWYoYjwwfHxiPj1hLmxlbmd0aClyZXR1
-cm4gSC5PSChhLGIpCnJldHVybiBhW2JdfSwKJGliUToxLAokaVhqOjEsCiRpY1g6MSwKJGl6TToxfQpX
-LlNOLnByb3RvdHlwZT17fQpXLmV3LnByb3RvdHlwZT17JGlldzoxfQpXLmxwLnByb3RvdHlwZT17CmdB
-OmZ1bmN0aW9uKGEpe3JldHVybiBhLmxlbmd0aH19ClcuVGIucHJvdG90eXBlPXsKcjY6ZnVuY3Rpb24o
-YSxiLGMsZCl7dmFyIHQscwppZigiY3JlYXRlQ29udGV4dHVhbEZyYWdtZW50IiBpbiB3aW5kb3cuUmFu
-Z2UucHJvdG90eXBlKXJldHVybiB0aGlzLkRXKGEsYixjLGQpCnQ9Vy5VOSgiPHRhYmxlPiIrSC5kKGIp
-KyI8L3RhYmxlPiIsYyxkKQpzPWRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKQpzLnRvU3Ry
-aW5nCnQudG9TdHJpbmcKbmV3IFcuZTcocykuRlYoMCxuZXcgVy5lNyh0KSkKcmV0dXJuIHN9fQpXLkl2
-LnByb3RvdHlwZT17CnI2OmZ1bmN0aW9uKGEsYixjLGQpe3ZhciB0LHMscixxCmlmKCJjcmVhdGVDb250
-ZXh0dWFsRnJhZ21lbnQiIGluIHdpbmRvdy5SYW5nZS5wcm90b3R5cGUpcmV0dXJuIHRoaXMuRFcoYSxi
-LGMsZCkKdD1kb2N1bWVudApzPXQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpCnQ9Qy5JZS5yNih0LmNy
-ZWF0ZUVsZW1lbnQoInRhYmxlIiksYixjLGQpCnQudG9TdHJpbmcKdD1uZXcgVy5lNyh0KQpyPXQuZ3I4
-KHQpCnIudG9TdHJpbmcKdD1uZXcgVy5lNyhyKQpxPXQuZ3I4KHQpCnMudG9TdHJpbmcKcS50b1N0cmlu
-ZwpuZXcgVy5lNyhzKS5GVigwLG5ldyBXLmU3KHEpKQpyZXR1cm4gc319ClcuV1AucHJvdG90eXBlPXsK
-cjY6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyCmlmKCJjcmVhdGVDb250ZXh0dWFsRnJhZ21lbnQi
-IGluIHdpbmRvdy5SYW5nZS5wcm90b3R5cGUpcmV0dXJuIHRoaXMuRFcoYSxiLGMsZCkKdD1kb2N1bWVu
-dApzPXQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpCnQ9Qy5JZS5yNih0LmNyZWF0ZUVsZW1lbnQoInRh
-YmxlIiksYixjLGQpCnQudG9TdHJpbmcKdD1uZXcgVy5lNyh0KQpyPXQuZ3I4KHQpCnMudG9TdHJpbmcK
-ci50b1N0cmluZwpuZXcgVy5lNyhzKS5GVigwLG5ldyBXLmU3KHIpKQpyZXR1cm4gc319ClcueVkucHJv
-dG90eXBlPXsKcGs6ZnVuY3Rpb24oYSxiLGMpe3ZhciB0LHMKYS50ZXh0Q29udGVudD1udWxsCnQ9YS5j
-b250ZW50CnQudG9TdHJpbmcKSi5iVCh0KQpzPXRoaXMucjYoYSxiLG51bGwsYykKYS5jb250ZW50LmFw
-cGVuZENoaWxkKHMpfSwKWUM6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5wayhhLGIsbnVsbCl9LAok
-aXlZOjF9ClcudzYucHJvdG90eXBlPXt9ClcuSzUucHJvdG90eXBlPXsKUG86ZnVuY3Rpb24oYSxiLGMp
-e3ZhciB0PVcuUDEoYS5vcGVuKGIsYykpCnJldHVybiB0fSwKZ21XOmZ1bmN0aW9uKGEpe3JldHVybiBh
-LmxvY2F0aW9ufSwKJGlLNToxLAokaXY2OjF9ClcuQ20ucHJvdG90eXBlPXskaUNtOjF9ClcuQ1EucHJv
-dG90eXBlPXskaUNROjF9ClcudzQucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4iUmVjdGFu
-Z2xlICgiK0guZChhLmxlZnQpKyIsICIrSC5kKGEudG9wKSsiKSAiK0guZChhLndpZHRoKSsiIHggIitI
-LmQoYS5oZWlnaHQpfSwKRE46ZnVuY3Rpb24oYSxiKXtpZihiPT1udWxsKXJldHVybiExCnJldHVybiB1
-LnEuYyhiKSYmYS5sZWZ0PT09Yi5sZWZ0JiZhLnRvcD09PWIudG9wJiZhLndpZHRoPT09Yi53aWR0aCYm
-YS5oZWlnaHQ9PT1iLmhlaWdodH0sCmdpTzpmdW5jdGlvbihhKXtyZXR1cm4gVy5yRShDLkNELmdpTyhh
-LmxlZnQpLEMuQ0QuZ2lPKGEudG9wKSxDLkNELmdpTyhhLndpZHRoKSxDLkNELmdpTyhhLmhlaWdodCkp
-fX0KVy5yaC5wcm90b3R5cGU9ewpnQTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApxOmZ1bmN0
-aW9uKGEsYil7SC5TYyhiKQppZihiPj4+MCE9PWJ8fGI+PWEubGVuZ3RoKXRocm93IEguYihQLkNmKGIs
-YSxudWxsLG51bGwsbnVsbCkpCnJldHVybiBhW2JdfSwKWTpmdW5jdGlvbihhLGIsYyl7dS5BLmIoYykK
-dGhyb3cgSC5iKFAuTDQoIkNhbm5vdCBhc3NpZ24gZWxlbWVudCBvZiBpbW11dGFibGUgTGlzdC4iKSl9
-LApFOmZ1bmN0aW9uKGEsYil7aWYoYjwwfHxiPj1hLmxlbmd0aClyZXR1cm4gSC5PSChhLGIpCnJldHVy
-biBhW2JdfSwKJGliUToxLAokaVhqOjEsCiRpY1g6MSwKJGl6TToxfQpXLmNmLnByb3RvdHlwZT17Cks6
-ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwCnUuRi5iKGIpCmZvcih0PXRoaXMuZ1YoKSxzPXQubGVu
-Z3RoLHI9dGhpcy5hLHE9MDtxPHQubGVuZ3RoO3QubGVuZ3RoPT09c3x8KDAsSC5saykodCksKytxKXtw
-PXRbcV0KYi4kMihwLHIuZ2V0QXR0cmlidXRlKHApKX19LApnVjpmdW5jdGlvbigpe3ZhciB0LHMscixx
-LHA9dGhpcy5hLmF0dHJpYnV0ZXMsbz1ILlZNKFtdLHUucykKZm9yKHQ9cC5sZW5ndGgscz11Lmg5LHI9
-MDtyPHQ7KytyKXtpZihyPj1wLmxlbmd0aClyZXR1cm4gSC5PSChwLHIpCnE9cy5iKHBbcl0pCmlmKHEu
-bmFtZXNwYWNlVVJJPT1udWxsKUMuTm0uaShvLHEubmFtZSl9cmV0dXJuIG99LApnbDA6ZnVuY3Rpb24o
-YSl7cmV0dXJuIHRoaXMuZ1YoKS5sZW5ndGg9PT0wfX0KVy5pNy5wcm90b3R5cGU9ewp4NDpmdW5jdGlv
-bihhKXtyZXR1cm4gdGhpcy5hLmhhc0F0dHJpYnV0ZShhKX0sCnE6ZnVuY3Rpb24oYSxiKXtyZXR1cm4g
-dGhpcy5hLmdldEF0dHJpYnV0ZShILnkoYikpfSwKWTpmdW5jdGlvbihhLGIsYyl7dGhpcy5hLnNldEF0
-dHJpYnV0ZShiLGMpfSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZ1YoKS5sZW5ndGh9fQpXLlN5
-LnByb3RvdHlwZT17Cng0OmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEuYS5oYXNBdHRyaWJ1dGUoImRh
-dGEtIit0aGlzLk8oYSkpfSwKcTpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLmEuYS5nZXRBdHRyaWJ1
-dGUoImRhdGEtIit0aGlzLk8oSC55KGIpKSl9LApZOmZ1bmN0aW9uKGEsYixjKXt0aGlzLmEuYS5zZXRB
-dHRyaWJ1dGUoImRhdGEtIit0aGlzLk8oYiksYyl9LApLOmZ1bmN0aW9uKGEsYil7dGhpcy5hLksoMCxu
-ZXcgVy5LUyh0aGlzLHUuRi5iKGIpKSl9LApnVjpmdW5jdGlvbigpe3ZhciB0PUguVk0oW10sdS5zKQp0
-aGlzLmEuSygwLG5ldyBXLkEzKHRoaXMsdCkpCnJldHVybiB0fSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJu
-IHRoaXMuZ1YoKS5sZW5ndGh9LApnbDA6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZ1YoKS5sZW5ndGg9
-PT0wfSwKazpmdW5jdGlvbihhKXt2YXIgdCxzLHI9SC5WTShhLnNwbGl0KCItIiksdS5zKQpmb3IodD0x
-O3Q8ci5sZW5ndGg7Kyt0KXtzPXJbdF0KaWYocy5sZW5ndGg+MClDLk5tLlkocix0LHNbMF0udG9VcHBl
-ckNhc2UoKStKLktWKHMsMSkpfXJldHVybiBDLk5tLkgociwiIil9LApPOmZ1bmN0aW9uKGEpe3ZhciB0
-LHMscixxLHAKZm9yKHQ9YS5sZW5ndGgscz0wLHI9IiI7czx0Oysrcyl7cT1hW3NdCnA9cS50b0xvd2Vy
-Q2FzZSgpCnI9KHEhPT1wJiZzPjA/cisiLSI6cikrcH1yZXR1cm4gci5jaGFyQ29kZUF0KDApPT0wP3I6
-cn19ClcuS1MucHJvdG90eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXtpZihKLnJZKGEpLm4oYSwiZGF0YS0i
-KSl0aGlzLmIuJDIodGhpcy5hLmsoQy54Qi5HKGEsNSkpLGIpfSwKJFM6MTR9ClcuQTMucHJvdG90eXBl
-PXsKJDI6ZnVuY3Rpb24oYSxiKXtpZihKLnJZKGEpLm4oYSwiZGF0YS0iKSlDLk5tLmkodGhpcy5iLHRo
-aXMuYS5rKEMueEIuRyhhLDUpKSl9LAokUzoxNH0KVy5JNC5wcm90b3R5cGU9ewpERzpmdW5jdGlvbigp
-e3ZhciB0LHMscixxLHA9UC5Mcyh1Lk4pCmZvcih0PXRoaXMuYS5jbGFzc05hbWUuc3BsaXQoIiAiKSxz
-PXQubGVuZ3RoLHI9MDtyPHM7KytyKXtxPUouVDAodFtyXSkKaWYocS5sZW5ndGghPT0wKXAuaSgwLHEp
-fXJldHVybiBwfSwKWDpmdW5jdGlvbihhKXt0aGlzLmEuY2xhc3NOYW1lPXUuQy5iKGEpLkgoMCwiICIp
-fSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5jbGFzc0xpc3QubGVuZ3RofSwKVjE6ZnVuY3Rp
-b24oYSl7dGhpcy5hLmNsYXNzTmFtZT0iIn0sCnRnOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcy5hLmNs
-YXNzTGlzdC5jb250YWlucyhiKQpyZXR1cm4gdH0sCmk6ZnVuY3Rpb24oYSxiKXt2YXIgdD10aGlzLmEu
-Y2xhc3NMaXN0LHM9dC5jb250YWlucyhiKQp0LmFkZChiKQpyZXR1cm4hc30sClI6ZnVuY3Rpb24oYSxi
-KXt2YXIgdD10aGlzLmEuY2xhc3NMaXN0LHM9dC5jb250YWlucyhiKQp0LnJlbW92ZShiKQpyZXR1cm4g
-c30sCkZWOmZ1bmN0aW9uKGEsYil7Vy5UTih0aGlzLmEsdS5YLmIoYikpfX0KVy5Gay5wcm90b3R5cGU9
-e30KVy5STy5wcm90b3R5cGU9e30KVy5ldS5wcm90b3R5cGU9e30KVy54Qy5wcm90b3R5cGU9e30KVy52
-Ti5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5hLiQxKHUuQi5iKGEpKX0sCiRT
-OjI3fQpXLkpRLnByb3RvdHlwZT17CkNZOmZ1bmN0aW9uKGEpe3ZhciB0CmlmKCQub3IuYT09PTApe2Zv
-cih0PTA7dDwyNjI7Kyt0KSQub3IuWSgwLEMuY21bdF0sVy5wUygpKQpmb3IodD0wO3Q8MTI7Kyt0KSQu
-b3IuWSgwLEMuQklbdF0sVy5WNCgpKX19LAppMDpmdW5jdGlvbihhKXtyZXR1cm4gJC5BTigpLnRnKDAs
-Vy5yUyhhKSl9LApFYjpmdW5jdGlvbihhLGIsYyl7dmFyIHQ9JC5vci5xKDAsSC5kKFcuclMoYSkpKyI6
-OiIrYikKaWYodD09bnVsbCl0PSQub3IucSgwLCIqOjoiK2IpCmlmKHQ9PW51bGwpcmV0dXJuITEKcmV0
-dXJuIEgueGQodC4kNChhLGIsYyx0aGlzKSl9LAokaWtGOjF9ClcuR20ucHJvdG90eXBlPXsKZ2t6OmZ1
-bmN0aW9uKGEpe3JldHVybiBuZXcgVy5XOShhLHRoaXMuZ0EoYSksSC56SyhhKS5DKCJXOTxHbS5FPiIp
-KX19ClcudkQucHJvdG90eXBlPXsKaTA6ZnVuY3Rpb24oYSl7cmV0dXJuIEMuTm0uVnIodGhpcy5hLG5l
-dyBXLlV2KGEpKX0sCkViOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gQy5ObS5Wcih0aGlzLmEsbmV3IFcu
-RWcoYSxiLGMpKX0sCiRpa0Y6MX0KVy5Vdi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4g
-dS5lLmIoYSkuaTAodGhpcy5hKX0sCiRTOjE1fQpXLkVnLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEp
-e3JldHVybiB1LmUuYihhKS5FYih0aGlzLmEsdGhpcy5iLHRoaXMuYyl9LAokUzoxNX0KVy5tNi5wcm90
-b3R5cGU9ewpDWTpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIKdGhpcy5hLkZWKDAsYykKdD1iLmV2
-KDAsbmV3IFcuRW8oKSkKcz1iLmV2KDAsbmV3IFcuV2soKSkKdGhpcy5iLkZWKDAsdCkKcj10aGlzLmMK
-ci5GVigwLEMueEQpCnIuRlYoMCxzKX0sCmkwOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEudGcoMCxX
-LnJTKGEpKX0sCkViOmZ1bmN0aW9uKGEsYixjKXt2YXIgdD10aGlzLHM9Vy5yUyhhKSxyPXQuYwppZihy
-LnRnKDAsSC5kKHMpKyI6OiIrYikpcmV0dXJuIHQuZC5EdChjKQplbHNlIGlmKHIudGcoMCwiKjo6Iiti
-KSlyZXR1cm4gdC5kLkR0KGMpCmVsc2V7cj10LmIKaWYoci50ZygwLEguZChzKSsiOjoiK2IpKXJldHVy
-biEwCmVsc2UgaWYoci50ZygwLCIqOjoiK2IpKXJldHVybiEwCmVsc2UgaWYoci50ZygwLEguZChzKSsi
-OjoqIikpcmV0dXJuITAKZWxzZSBpZihyLnRnKDAsIio6OioiKSlyZXR1cm4hMH1yZXR1cm4hMX0sCiRp
-a0Y6MX0KVy5Fby5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4hQy5ObS50ZyhDLkJJLEgu
-eShhKSl9LAokUzo3fQpXLldrLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiBDLk5tLnRn
-KEMuQkksSC55KGEpKX0sCiRTOjd9ClcuY3QucHJvdG90eXBlPXsKRWI6ZnVuY3Rpb24oYSxiLGMpe2lm
-KHRoaXMuakYoYSxiLGMpKXJldHVybiEwCmlmKGI9PT0idGVtcGxhdGUiJiZjPT09IiIpcmV0dXJuITAK
-aWYoYS5nZXRBdHRyaWJ1dGUoInRlbXBsYXRlIik9PT0iIilyZXR1cm4gdGhpcy5lLnRnKDAsYikKcmV0
-dXJuITF9fQpXLklBLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiJURU1QTEFURTo6IitI
-LmQoSC55KGEpKX0sCiRTOjV9ClcuT3cucHJvdG90eXBlPXsKaTA6ZnVuY3Rpb24oYSl7dmFyIHQKaWYo
-dS5hTy5jKGEpKXJldHVybiExCnQ9dS5nNy5jKGEpCmlmKHQmJlcuclMoYSk9PT0iZm9yZWlnbk9iamVj
-dCIpcmV0dXJuITEKaWYodClyZXR1cm4hMApyZXR1cm4hMX0sCkViOmZ1bmN0aW9uKGEsYixjKXtpZihi
-PT09ImlzInx8Qy54Qi5uKGIsIm9uIikpcmV0dXJuITEKcmV0dXJuIHRoaXMuaTAoYSl9LAokaWtGOjF9
-ClcuVzkucHJvdG90eXBlPXsKRjpmdW5jdGlvbigpe3ZhciB0PXRoaXMscz10LmMrMSxyPXQuYgppZihz
-PHIpe3Quc3AoSi53Mih0LmEscykpCnQuYz1zCnJldHVybiEwfXQuc3AobnVsbCkKdC5jPXIKcmV0dXJu
-ITF9LApnbDpmdW5jdGlvbigpe3JldHVybiB0aGlzLmR9LApzcDpmdW5jdGlvbihhKXt0aGlzLmQ9dGhp
-cy4kdGkuZC5iKGEpfSwKJGlBbjoxfQpXLmRXLnByb3RvdHlwZT17CmdtVzpmdW5jdGlvbihhKXtyZXR1
-cm4gVy5ISCh0aGlzLmEubG9jYXRpb24pfSwKJGlEMDoxLAokaXY2OjF9ClcuRmIucHJvdG90eXBlPXt9
-Clcua0YucHJvdG90eXBlPXt9ClcubWsucHJvdG90eXBlPXskaXkwOjF9ClcuS28ucHJvdG90eXBlPXsK
-UG46ZnVuY3Rpb24oYSl7bmV3IFcuZm0odGhpcykuJDIoYSxudWxsKX0sCkVQOmZ1bmN0aW9uKGEsYil7
-aWYoYj09bnVsbClKLkx0KGEpCmVsc2UgYi5yZW1vdmVDaGlsZChhKX0sCkk0OmZ1bmN0aW9uKGEsYil7
-dmFyIHQscyxyLHEscCxvPSEwLG49bnVsbCxtPW51bGwKdHJ5e249Si5pZyhhKQptPW4uYS5nZXRBdHRy
-aWJ1dGUoImlzIikKdS5oLmIoYSkKdD1mdW5jdGlvbihjKXtpZighKGMuYXR0cmlidXRlcyBpbnN0YW5j
-ZW9mIE5hbWVkTm9kZU1hcCkpcmV0dXJuIHRydWUKdmFyIGw9Yy5jaGlsZE5vZGVzCmlmKGMubGFzdENo
-aWxkJiZjLmxhc3RDaGlsZCE9PWxbbC5sZW5ndGgtMV0pcmV0dXJuIHRydWUKaWYoYy5jaGlsZHJlbilp
-ZighKGMuY2hpbGRyZW4gaW5zdGFuY2VvZiBIVE1MQ29sbGVjdGlvbnx8Yy5jaGlsZHJlbiBpbnN0YW5j
-ZW9mIE5vZGVMaXN0KSlyZXR1cm4gdHJ1ZQp2YXIgaz0wCmlmKGMuY2hpbGRyZW4paz1jLmNoaWxkcmVu
-Lmxlbmd0aApmb3IodmFyIGo9MDtqPGs7aisrKXt2YXIgaT1jLmNoaWxkcmVuW2pdCmlmKGkuaWQ9PSdh
-dHRyaWJ1dGVzJ3x8aS5uYW1lPT0nYXR0cmlidXRlcyd8fGkuaWQ9PSdsYXN0Q2hpbGQnfHxpLm5hbWU9
-PSdsYXN0Q2hpbGQnfHxpLmlkPT0nY2hpbGRyZW4nfHxpLm5hbWU9PSdjaGlsZHJlbicpcmV0dXJuIHRy
-dWV9cmV0dXJuIGZhbHNlfShhKQpvPUgub1QodCk/ITA6IShhLmF0dHJpYnV0ZXMgaW5zdGFuY2VvZiBO
-YW1lZE5vZGVNYXApfWNhdGNoKHEpe0guUnUocSl9cz0iZWxlbWVudCB1bnByaW50YWJsZSIKdHJ5e3M9
-Si5qKGEpfWNhdGNoKHEpe0guUnUocSl9dHJ5e3I9Vy5yUyhhKQp0aGlzLmtSKHUuaC5iKGEpLGIsbyxz
-LHIsdS5HLmIobiksSC55KG0pKX1jYXRjaChxKXtpZihILlJ1KHEpIGluc3RhbmNlb2YgUC51KXRocm93
-IHEKZWxzZXt0aGlzLkVQKGEsYikKd2luZG93CnA9IlJlbW92aW5nIGNvcnJ1cHRlZCBlbGVtZW50ICIr
-SC5kKHMpCmlmKHR5cGVvZiBjb25zb2xlIT0idW5kZWZpbmVkIil3aW5kb3cuY29uc29sZS53YXJuKHAp
-fX19LAprUjpmdW5jdGlvbihhLGIsYyxkLGUsZixnKXt2YXIgdCxzLHIscSxwLG8sbj10aGlzCmlmKGMp
-e24uRVAoYSxiKQp3aW5kb3cKdD0iUmVtb3ZpbmcgZWxlbWVudCBkdWUgdG8gY29ycnVwdGVkIGF0dHJp
-YnV0ZXMgb24gPCIrZCsiPiIKaWYodHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25z
-b2xlLndhcm4odCkKcmV0dXJufWlmKCFuLmEuaTAoYSkpe24uRVAoYSxiKQp3aW5kb3cKdD0iUmVtb3Zp
-bmcgZGlzYWxsb3dlZCBlbGVtZW50IDwiK0guZChlKSsiPiBmcm9tICIrSC5kKGIpCmlmKHR5cGVvZiBj
-b25zb2xlIT0idW5kZWZpbmVkIil3aW5kb3cuY29uc29sZS53YXJuKHQpCnJldHVybn1pZihnIT1udWxs
-KWlmKCFuLmEuRWIoYSwiaXMiLGcpKXtuLkVQKGEsYikKd2luZG93CnQ9IlJlbW92aW5nIGRpc2FsbG93
-ZWQgdHlwZSBleHRlbnNpb24gPCIrSC5kKGUpKycgaXM9IicrZysnIj4nCmlmKHR5cGVvZiBjb25zb2xl
-IT0idW5kZWZpbmVkIil3aW5kb3cuY29uc29sZS53YXJuKHQpCnJldHVybn10PWYuZ1YoKQpzPUguVk0o
-dC5zbGljZSgwKSxILnQ2KHQpLkMoImpkPDE+IikpCmZvcihyPWYuZ1YoKS5sZW5ndGgtMSx0PWYuYTty
-Pj0wOy0tcil7aWYocj49cy5sZW5ndGgpcmV0dXJuIEguT0gocyxyKQpxPXNbcl0KcD1uLmEKbz1KLmNI
-KHEpCkgueShxKQppZighcC5FYihhLG8sdC5nZXRBdHRyaWJ1dGUocSkpKXt3aW5kb3cKcD0iUmVtb3Zp
-bmcgZGlzYWxsb3dlZCBhdHRyaWJ1dGUgPCIrSC5kKGUpKyIgIitxKyc9IicrSC5kKHQuZ2V0QXR0cmli
-dXRlKHEpKSsnIj4nCmlmKHR5cGVvZiBjb25zb2xlIT0idW5kZWZpbmVkIil3aW5kb3cuY29uc29sZS53
-YXJuKHApCnQucmVtb3ZlQXR0cmlidXRlKHEpfX1pZih1LmFXLmMoYSkpbi5QbihhLmNvbnRlbnQpfSwK
-JGlvbjoxfQpXLmZtLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEscD10aGlz
-LmEKc3dpdGNoKGEubm9kZVR5cGUpe2Nhc2UgMTpwLkk0KGEsYikKYnJlYWsKY2FzZSA4OmNhc2UgMTE6
-Y2FzZSAzOmNhc2UgNDpicmVhawpkZWZhdWx0OnAuRVAoYSxiKX10PWEubGFzdENoaWxkCmZvcihwPXUu
-QTtudWxsIT10Oyl7cz1udWxsCnRyeXtzPXQucHJldmlvdXNTaWJsaW5nfWNhdGNoKHIpe0guUnUocikK
-cT1wLmIodCkKYS5yZW1vdmVDaGlsZChxKQp0PW51bGwKcz1hLmxhc3RDaGlsZH1pZih0IT1udWxsKXRo
-aXMuJDIodCxhKQp0PXAuYihzKX19LAokUzozMH0KVy5MZS5wcm90b3R5cGU9e30KVy5LNy5wcm90b3R5
-cGU9e30KVy5yQi5wcm90b3R5cGU9e30KVy5YVy5wcm90b3R5cGU9e30KVy5vYS5wcm90b3R5cGU9e30K
-UC5pSi5wcm90b3R5cGU9ewpWSDpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuYSxyPXMubGVuZ3RoCmZv
-cih0PTA7dDxyOysrdClpZihzW3RdPT09YSlyZXR1cm4gdApDLk5tLmkocyxhKQpDLk5tLmkodGhpcy5i
-LG51bGwpCnJldHVybiByfSwKUHY6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9dGhpcyxwPXt9CmlmKGE9
-PW51bGwpcmV0dXJuIGEKaWYoSC5sKGEpKXJldHVybiBhCmlmKHR5cGVvZiBhPT0ibnVtYmVyIilyZXR1
-cm4gYQppZih0eXBlb2YgYT09InN0cmluZyIpcmV0dXJuIGEKaWYoYSBpbnN0YW5jZW9mIFAuaVApcmV0
-dXJuIG5ldyBEYXRlKGEuYSkKaWYodS5mdi5jKGEpKXRocm93IEguYihQLlNZKCJzdHJ1Y3R1cmVkIGNs
-b25lIG9mIFJlZ0V4cCIpKQppZih1LmM4LmMoYSkpcmV0dXJuIGEKaWYodS5kLmMoYSkpcmV0dXJuIGEK
-aWYodS5JLmMoYSkpcmV0dXJuIGEKdD11LmRELmMoYSl8fCExCmlmKHQpcmV0dXJuIGEKaWYodS5HLmMo
-YSkpe3M9cS5WSChhKQp0PXEuYgppZihzPj10Lmxlbmd0aClyZXR1cm4gSC5PSCh0LHMpCnI9cC5hPXRb
-c10KaWYociE9bnVsbClyZXR1cm4gcgpyPXt9CnAuYT1yCkMuTm0uWSh0LHMscikKYS5LKDAsbmV3IFAu
-bFIocCxxKSkKcmV0dXJuIHAuYX1pZih1LmouYyhhKSl7cz1xLlZIKGEpCnA9cS5iCmlmKHM+PXAubGVu
-Z3RoKXJldHVybiBILk9IKHAscykKcj1wW3NdCmlmKHIhPW51bGwpcmV0dXJuIHIKcmV0dXJuIHEuZWso
-YSxzKX1pZih1LmVILmMoYSkpe3M9cS5WSChhKQp0PXEuYgppZihzPj10Lmxlbmd0aClyZXR1cm4gSC5P
-SCh0LHMpCnI9cC5iPXRbc10KaWYociE9bnVsbClyZXR1cm4gcgpyPXt9CnAuYj1yCkMuTm0uWSh0LHMs
-cikKcS5pbShhLG5ldyBQLmpnKHAscSkpCnJldHVybiBwLmJ9dGhyb3cgSC5iKFAuU1koInN0cnVjdHVy
-ZWQgY2xvbmUgb2Ygb3RoZXIgdHlwZSIpKX0sCmVrOmZ1bmN0aW9uKGEsYil7dmFyIHQscz1KLlU2KGEp
-LHI9cy5nQShhKSxxPW5ldyBBcnJheShyKQpDLk5tLlkodGhpcy5iLGIscSkKZm9yKHQ9MDt0PHI7Kyt0
-KUMuTm0uWShxLHQsdGhpcy5QdihzLnEoYSx0KSkpCnJldHVybiBxfX0KUC5sUi5wcm90b3R5cGU9ewok
-MjpmdW5jdGlvbihhLGIpe3RoaXMuYS5hW2FdPXRoaXMuYi5QdihiKX0sCiRTOjR9ClAuamcucHJvdG90
-eXBlPXsKJDI6ZnVuY3Rpb24oYSxiKXt0aGlzLmEuYlthXT10aGlzLmIuUHYoYil9LAokUzo0fQpQLkJm
-LnByb3RvdHlwZT17CmltOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxyLHEKdS5iOC5iKGIpCmZvcih0PU9i
-amVjdC5rZXlzKGEpLHM9dC5sZW5ndGgscj0wO3I8czsrK3Ipe3E9dFtyXQpiLiQyKHEsYVtxXSl9fX0K
-UC5Bcy5wcm90b3R5cGU9ewpUOmZ1bmN0aW9uKGEpe3ZhciB0CkgueShhKQp0PSQuaEcoKS5iCmlmKHR5
-cGVvZiBhIT0ic3RyaW5nIilILnZoKEgudEwoYSkpCmlmKHQudGVzdChhKSlyZXR1cm4gYQp0aHJvdyBI
-LmIoUC5MMyhhLCJ2YWx1ZSIsIk5vdCBhIHZhbGlkIGNsYXNzIHRva2VuIikpfSwKdzpmdW5jdGlvbihh
-KXtyZXR1cm4gdGhpcy5ERygpLkgoMCwiICIpfSwKZ2t6OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMuREco
-KQpyZXR1cm4gUC5yaih0LHQucixILkxoKHQpLmQpfSwKZ0E6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMu
-REcoKS5hfSwKdGc6ZnVuY3Rpb24oYSxiKXt0aGlzLlQoYikKcmV0dXJuIHRoaXMuREcoKS50ZygwLGIp
-fSwKaTpmdW5jdGlvbihhLGIpe3RoaXMuVChiKQpyZXR1cm4gSC54ZCh0aGlzLk9TKG5ldyBQLkdFKGIp
-KSl9LApSOmZ1bmN0aW9uKGEsYil7dmFyIHQscwp0aGlzLlQoYikKdD10aGlzLkRHKCkKcz10LlIoMCxi
-KQp0aGlzLlgodCkKcmV0dXJuIHN9LApGVjpmdW5jdGlvbihhLGIpe3RoaXMuT1MobmV3IFAuTjcodGhp
-cyx1LlguYihiKSkpfSwKVjE6ZnVuY3Rpb24oYSl7dGhpcy5PUyhuZXcgUC51USgpKX0sCk9TOmZ1bmN0
-aW9uKGEpe3ZhciB0LHMKdS5jaC5iKGEpCnQ9dGhpcy5ERygpCnM9YS4kMSh0KQp0aGlzLlgodCkKcmV0
-dXJuIHN9fQpQLkdFLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB1LkMuYihhKS5pKDAs
-dGhpcy5hKX0sCiRTOjMxfQpQLk43LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMu
-YixzPUgudDYodCkKcmV0dXJuIHUuQy5iKGEpLkZWKDAsbmV3IEguQTgodCxzLkMoInFVKDEpIikuYih0
-aGlzLmEuZ3VNKCkpLHMuQygiQTg8MSxxVT4iKSkpfSwKJFM6MTF9ClAudVEucHJvdG90eXBlPXsKJDE6
-ZnVuY3Rpb24oYSl7dS5DLmIoYSkKaWYoYS5hPjApe2EuYj1hLmM9YS5kPWEuZT1hLmY9bnVsbAphLmE9
-MAphLlMoKX1yZXR1cm4gbnVsbH0sCiRTOjExfQpQLmhGLnByb3RvdHlwZT17JGloRjoxfQpQLlBDLnBy
-b3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0CnUuWi5iKGEpCnQ9ZnVuY3Rpb24oYixjLGQpe3Jl
-dHVybiBmdW5jdGlvbigpe3JldHVybiBiKGMsZCx0aGlzLEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBs
-eShhcmd1bWVudHMpKX19KFAuUjQsYSwhMSkKUC5EbSh0LCQudygpLGEpCnJldHVybiB0fSwKJFM6MX0K
-UC5tdC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IHRoaXMuYShhKX0sCiRTOjF9
-ClAuTnoucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLnI3KGEpfSwKJFM6MzN9
-ClAuUVMucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLlR6KGEsdS5hbSl9LAok
-UzozNH0KUC5ucC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuRTQoYSl9LAok
-UzozNX0KUC5FNC5wcm90b3R5cGU9ewpxOmZ1bmN0aW9uKGEsYil7aWYodHlwZW9mIGIhPSJzdHJpbmci
-JiZ0eXBlb2YgYiE9Im51bWJlciIpdGhyb3cgSC5iKFAueFkoInByb3BlcnR5IGlzIG5vdCBhIFN0cmlu
-ZyBvciBudW0iKSkKcmV0dXJuIFAuTDcodGhpcy5hW2JdKX0sClk6ZnVuY3Rpb24oYSxiLGMpe2lmKHR5
-cGVvZiBiIT0ic3RyaW5nIiYmdHlwZW9mIGIhPSJudW1iZXIiKXRocm93IEguYihQLnhZKCJwcm9wZXJ0
-eSBpcyBub3QgYSBTdHJpbmcgb3IgbnVtIikpCnRoaXMuYVtiXT1QLndZKGMpfSwKRE46ZnVuY3Rpb24o
-YSxiKXtpZihiPT1udWxsKXJldHVybiExCnJldHVybiBiIGluc3RhbmNlb2YgUC5FNCYmdGhpcy5hPT09
-Yi5hfSwKdzpmdW5jdGlvbihhKXt2YXIgdCxzCnRyeXt0PVN0cmluZyh0aGlzLmEpCnJldHVybiB0fWNh
-dGNoKHMpe0guUnUocykKdD10aGlzLnhiKDApCnJldHVybiB0fX0sClY3OmZ1bmN0aW9uKGEsYil7dmFy
-IHQscz10aGlzLmEKaWYoYj09bnVsbCl0PW51bGwKZWxzZXt0PUgudDYoYikKdD1QLkNIKG5ldyBILkE4
-KGIsdC5DKCJAKDEpIikuYihQLmlHKCkpLHQuQygiQTg8MSxAPiIpKSwhMCx1LnopfXJldHVybiBQLkw3
-KHNbYV0uYXBwbHkocyx0KSl9LApnaU86ZnVuY3Rpb24oYSl7cmV0dXJuIDB9fQpQLnI3LnByb3RvdHlw
-ZT17fQpQLlR6LnByb3RvdHlwZT17CmNQOmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMscz1hPDB8fGE+PXQu
-Z0EodCkKaWYocyl0aHJvdyBILmIoUC5URShhLDAsdC5nQSh0KSxudWxsLG51bGwpKX0sCnE6ZnVuY3Rp
-b24oYSxiKXtpZih0eXBlb2YgYj09Im51bWJlciImJmI9PT1DLmpuLnl1KGIpKXRoaXMuY1AoSC5TYyhi
-KSkKcmV0dXJuIHRoaXMuJHRpLmQuYih0aGlzLlVyKDAsYikpfSwKWTpmdW5jdGlvbihhLGIsYyl7dmFy
-IHQKdGhpcy4kdGkuZC5iKGMpCnQ9Qy5qbi55dShiKQppZihiPT09dCl0aGlzLmNQKGIpCnRoaXMuZTQo
-MCxiLGMpfSwKZ0E6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcy5hLmxlbmd0aAppZih0eXBlb2YgdD09PSJu
-dW1iZXIiJiZ0Pj4+MD09PXQpcmV0dXJuIHQKdGhyb3cgSC5iKFAuUFYoIkJhZCBKc0FycmF5IGxlbmd0
-aCIpKX0sCiRpYlE6MSwKJGljWDoxLAokaXpNOjF9ClAuY28ucHJvdG90eXBlPXt9ClAubmQucHJvdG90
-eXBlPXskaW5kOjF9ClAuS2UucHJvdG90eXBlPXsKREc6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwPXRo
-aXMuYS5nZXRBdHRyaWJ1dGUoImNsYXNzIiksbz1QLkxzKHUuTikKaWYocD09bnVsbClyZXR1cm4gbwpm
-b3IodD1wLnNwbGl0KCIgIikscz10Lmxlbmd0aCxyPTA7cjxzOysrcil7cT1KLlQwKHRbcl0pCmlmKHEu
-bGVuZ3RoIT09MClvLmkoMCxxKX1yZXR1cm4gb30sClg6ZnVuY3Rpb24oYSl7dGhpcy5hLnNldEF0dHJp
-YnV0ZSgiY2xhc3MiLGEuSCgwLCIgIikpfX0KUC5kNS5wcm90b3R5cGU9ewpnUDpmdW5jdGlvbihhKXty
-ZXR1cm4gbmV3IFAuS2UoYSl9LApzaGY6ZnVuY3Rpb24oYSxiKXt0aGlzLllDKGEsYil9LApyNjpmdW5j
-dGlvbihhLGIsYyxkKXt2YXIgdCxzLHIscSxwLG8KaWYoZD09bnVsbCl7dD1ILlZNKFtdLHUuaSkKZD1u
-ZXcgVy52RCh0KQpDLk5tLmkodCxXLlR3KG51bGwpKQpDLk5tLmkodCxXLkJsKCkpCkMuTm0uaSh0LG5l
-dyBXLk93KCkpfWM9bmV3IFcuS28oZCkKcz0nPHN2ZyB2ZXJzaW9uPSIxLjEiPicrSC5kKGIpKyI8L3N2
-Zz4iCnQ9ZG9jdW1lbnQKcj10LmJvZHkKcT0ociYmQy5SWSkuQUgocixzLGMpCnA9dC5jcmVhdGVEb2N1
-bWVudEZyYWdtZW50KCkKcS50b1N0cmluZwp0PW5ldyBXLmU3KHEpCm89dC5ncjgodCkKZm9yKDt0PW8u
-Zmlyc3RDaGlsZCx0IT1udWxsOylwLmFwcGVuZENoaWxkKHQpCnJldHVybiBwfSwKbno6ZnVuY3Rpb24o
-YSxiLGMsZCxlKXt0aHJvdyBILmIoUC5MNCgiQ2Fubm90IGludm9rZSBpbnNlcnRBZGphY2VudEh0bWwg
-b24gU1ZHLiIpKX0sCmdWbDpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFcuZXUoYSwiY2xpY2siLCExLHUu
-USl9LAokaWQ1OjF9ClAubjYucHJvdG90eXBlPXskaWJROjEsJGljWDoxLCRpek06MSwkaWVxOjF9Ck0u
-SDcucHJvdG90eXBlPXsKdzpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5ifX0KVS5MTC5wcm90b3R5cGU9
-ewpMdDpmdW5jdGlvbigpe3JldHVybiBQLkVGKFsibm9kZUlkIix0aGlzLmIsImtpbmQiLHRoaXMuYS5h
-XSx1Lk4sdS5LKX19ClUuTUQucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIHUuZ3AuYihh
-KS5hPT09dGhpcy5hLnEoMCwia2luZCIpfSwKJFM6MzZ9ClUuZDIucHJvdG90eXBlPXsKTHQ6ZnVuY3Rp
-b24oKXt2YXIgdCxzLHIscSxwPXRoaXMsbz11Lk4sbj11LkssbT1QLkZsKG8sbiksbD1wLmEKaWYobCE9
-bnVsbCl7dD1ILlZNKFtdLHUuSikKZm9yKHM9bC5sZW5ndGgscj0wO3I8bC5sZW5ndGg7bC5sZW5ndGg9
-PT1zfHwoMCxILmxrKShsKSwrK3Ipe3E9bFtyXQpDLk5tLmkodCxQLkVGKFsiZGVzY3JpcHRpb24iLHEu
-YSwiaHJlZiIscS5iXSxvLG4pKX1tLlkoMCwiZWRpdHMiLHQpfW0uWSgwLCJleHBsYW5hdGlvbiIscC5i
-KQptLlkoMCwibGluZSIscC5jKQptLlkoMCwiZGlzcGxheVBhdGgiLHAuZCkKbS5ZKDAsInVyaVBhdGgi
-LHAuZSkKbz1wLmYKaWYobyE9bnVsbCl7bj1ILlZNKFtdLHUuSikKZm9yKGw9by5sZW5ndGgscj0wO3I8
-by5sZW5ndGg7by5sZW5ndGg9PT1sfHwoMCxILmxrKShvKSwrK3IpQy5ObS5pKG4sb1tyXS5MdCgpKQpt
-LlkoMCwidHJhY2VzIixuKX1yZXR1cm4gbX19ClUuU2UucHJvdG90eXBlPXsKTHQ6ZnVuY3Rpb24oKXty
-ZXR1cm4gUC5FRihbImRlc2NyaXB0aW9uIix0aGlzLmEsImhyZWYiLHRoaXMuYl0sdS5OLHUuSyl9fQpV
-Lk1sLnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7cmV0dXJuIFAuRUYoWyJocmVmIix0aGlzLmEsImxp
-bmUiLHRoaXMuYiwicGF0aCIsdGhpcy5jXSx1Lk4sdS5LKX19ClUueUQucHJvdG90eXBlPXsKTHQ6ZnVu
-Y3Rpb24oKXt2YXIgdCxzLHIscT1ILlZNKFtdLHUuSikKZm9yKHQ9dGhpcy5iLHM9dC5sZW5ndGgscj0w
-O3I8dC5sZW5ndGg7dC5sZW5ndGg9PT1zfHwoMCxILmxrKSh0KSwrK3IpQy5ObS5pKHEsdFtyXS5MdCgp
-KQpyZXR1cm4gUC5FRihbImRlc2NyaXB0aW9uIix0aGlzLmEsImVudHJpZXMiLHFdLHUuTix1LkspfX0K
-VS53Yi5wcm90b3R5cGU9ewpMdDpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzLHE9UC5GbCh1Lk4sdS5L
-KQpxLlkoMCwiZGVzY3JpcHRpb24iLHIuYSkKdD1yLmIKaWYodCE9bnVsbClxLlkoMCwiZnVuY3Rpb24i
-LHQpCnQ9ci5jCmlmKHQhPW51bGwpcS5ZKDAsImxpbmsiLHQuTHQoKSkKdD1yLmQKaWYodC5sZW5ndGgh
-PT0wKXtzPUgudDYodCkKcS5ZKDAsImhpbnRBY3Rpb25zIixuZXcgSC5BOCh0LHMuQygiWjA8cVUsaz4o
-MSkiKS5iKG5ldyBVLmIwKCkpLHMuQygiQTg8MSxaMDxxVSxrPj4iKSkuYnIoMCkpfXJldHVybiBxfX0K
-VS5hTi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gVS5ueih1LlMuYShhKSl9LAokUzoz
-N30KVS5iMC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdS5ELmIoYSkuTHQoKX0sCiRT
-OjM4fQpCLmo4LnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7cmV0dXJuIFAuRUYoWyJsaW5lIix0aGlz
-LmEsImV4cGxhbmF0aW9uIix0aGlzLmIsIm9mZnNldCIsdGhpcy5jXSx1Lk4sdS5LKX19CkIucXAucHJv
-dG90eXBlPXsKTHQ6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwLG8sbixtPXRoaXMsbD11Lk4saz1QLkZs
-KGwsdS5kMykKZm9yKHQ9bS5kLHQ9dC5nUHUodCksdD10Lmdreih0KSxzPXUuSyxyPXUuSjt0LkYoKTsp
-e3E9dC5nbCgpCnA9cS5hCm89SC5WTShbXSxyKQpmb3IocT1KLklUKHEuYik7cS5GKCk7KXtuPXEuZ2wo
-KQpDLk5tLmkobyxQLkVGKFsibGluZSIsbi5hLCJleHBsYW5hdGlvbiIsbi5iLCJvZmZzZXQiLG4uY10s
-bCxzKSl9ay5ZKDAscCxvKX1yZXR1cm4gUC5FRihbInJlZ2lvbnMiLG0uYSwibmF2aWdhdGlvbkNvbnRl
-bnQiLG0uYiwic291cmNlQ29kZSIsbS5jLCJlZGl0cyIsa10sbCxzKX19ClQubVEucHJvdG90eXBlPXt9
-CkwuZS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbgp1LkIuYihhKQp0
-PXdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZQpzPUwuRzYod2luZG93LmxvY2F0aW9uLmhyZWYpCnI9TC5h
-Syh3aW5kb3cubG9jYXRpb24uaHJlZikKTC5HZSgpCmlmKHQhPT0iLyImJnQhPT1KLlQwKGRvY3VtZW50
-LnF1ZXJ5U2VsZWN0b3IoIi5yb290IikudGV4dENvbnRlbnQpKUwuRzcodCxzLHIsITAsbmV3IEwuVlco
-dCxzLHIpKQpxPWRvY3VtZW50CnA9Si5xRihxLnF1ZXJ5U2VsZWN0b3IoIi5hcHBseS1taWdyYXRpb24i
-KSkKbz1wLiR0aQpuPW8uQygifigxKSIpLmIobmV3IEwub1ooKSkKdS5NLmIobnVsbCkKVy5KRShwLmEs
-cC5iLG4sITEsby5kKQpvPUoucUYocS5xdWVyeVNlbGVjdG9yKCIucmVydW4tbWlncmF0aW9uIikpCm49
-by4kdGkKVy5KRShvLmEsby5iLG4uQygifigxKSIpLmIobmV3IEwueTgoKSksITEsbi5kKQpuPUoucUYo
-cS5xdWVyeVNlbGVjdG9yKCIucmVwb3J0LXByb2JsZW0iKSkKbz1uLiR0aQpXLkpFKG4uYSxuLmIsby5D
-KCJ+KDEpIikuYihuZXcgTC5IaSgpKSwhMSxvLmQpCnE9Si5xRihxLnF1ZXJ5U2VsZWN0b3IoIi5wb3B1
-cC1wYW5lIC5jbG9zZSIpKQpvPXEuJHRpClcuSkUocS5hLHEuYixvLkMoIn4oMSkiKS5iKG5ldyBMLkJU
-KCkpLCExLG8uZCl9LAokUzoxNn0KTC5WVy5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuRnIodGhp
-cy5hLHRoaXMuYix0aGlzLmMpfSwKJFM6MH0KTC5vWi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2
-YXIgdCxzLHIscQp1LlYuYihhKQppZihILm9UKHdpbmRvdy5jb25maXJtKCJUaGlzIHdpbGwgYXBwbHkg
-dGhlIGNoYW5nZXMgeW91J3ZlIHByZXZpZXdlZCB0byB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5LiBJdCBp
-cyByZWNvbW1lbmRlZCB5b3UgY29tbWl0IGFueSBjaGFuZ2VzIHlvdSBtYWRlIGJlZm9yZSBkb2luZyB0
-aGlzLiIpKSl7dD1MLnR5KCIvYXBwbHktbWlncmF0aW9uIixudWxsKS5XNyhuZXcgTC5qcigpLHUuUCkK
-cz1uZXcgTC5xbCgpCnUuYmYuYihudWxsKQpyPXQuJHRpCnE9JC5YMwppZihxIT09Qy5OVSlzPVAuVkgo
-cyxxKQp0LnhmKG5ldyBQLkZlKG5ldyBQLnZzKHEsciksMixudWxsLHMsci5DKCJAPDE+IikuS3Eoci5k
-KS5DKCJGZTwxLDI+IikpKX19LAokUzozfQpMLmpyLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3Zh
-ciB0CnUuUy5iKGEpCnQ9ZG9jdW1lbnQuYm9keQp0LmNsYXNzTGlzdC5yZW1vdmUoInByb3Bvc2VkIikK
-dC5jbGFzc0xpc3QuYWRkKCJhcHBsaWVkIil9LAokUzo0MX0KTC5xbC5wcm90b3R5cGU9ewokMjpmdW5j
-dGlvbihhLGIpe0wuQzIoIkNvdWxkIG5vdCBhcHBseSBtaWdyYXRpb24iLGEsYil9LAokQzoiJDIiLAok
-UjoyLAokUzo0fQpMLnk4LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnhuKHUu
-Vi5iKGEpKX0sCnhuOmZ1bmN0aW9uKGEpe3ZhciB0PTAscz1QLkZYKHUuUCkscj0xLHEscD1bXSxvLG4s
-bSxsCnZhciAkYXN5bmMkJDE9UC5seihmdW5jdGlvbihiLGMpe2lmKGI9PT0xKXtxPWMKdD1yfXdoaWxl
-KHRydWUpc3dpdGNoKHQpe2Nhc2UgMDpyPTMKZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuYWRkKCJyZXJ1
-bm5pbmciKQp0PTYKcmV0dXJuIFAualEoTC50eSgiL3JlcnVuLW1pZ3JhdGlvbiIsbnVsbCksJGFzeW5j
-JCQxKQpjYXNlIDY6d2luZG93LmxvY2F0aW9uLnJlbG9hZCgpCnAucHVzaCg1KQp0PTQKYnJlYWsKY2Fz
-ZSAzOnI9MgpsPXEKbz1ILlJ1KGwpCm49SC50cyhsKQpMLkMyKCJGYWlsZWQgdG8gcmVydW4gbWlncmF0
-aW9uIixvLG4pCnAucHVzaCg1KQp0PTQKYnJlYWsKY2FzZSAyOnA9WzFdCmNhc2UgNDpyPTEKZG9jdW1l
-bnQuYm9keS5jbGFzc0xpc3QucmVtb3ZlKCJyZXJ1bm5pbmciKQp0PXAucG9wKCkKYnJlYWsKY2FzZSA1
-OnJldHVybiBQLnlDKG51bGwscykKY2FzZSAxOnJldHVybiBQLmYzKHEscyl9fSkKcmV0dXJuIFAuREko
-JGFzeW5jJCQxLHMpfSwKJFM6MTd9CkwuSGkucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQK
-dS5WLmIoYSkKdD11Lk4KQy5vbC5Qbyh3aW5kb3csUC5YZCgiaHR0cHMiLCJnaXRodWIuY29tIiwiZGFy
-dC1sYW5nL3Nkay9pc3N1ZXMvbmV3IixQLkVGKFsidGl0bGUiLCJDdXN0b21lci1yZXBvcnRlZCBpc3N1
-ZSB3aXRoIE5OQkQgbWlncmF0aW9uIHRvb2wiLCJsYWJlbHMiLCJhcmVhLWFuYWx5emVyLGFuYWx5emVy
-LW5uYmQtbWlncmF0aW9uLHR5cGUtYnVnIiwiYm9keSIsIiMjIyMgU3RlcHMgdG8gcmVwcm9kdWNlXG5c
-biMjIyMgV2hhdCBkaWQgeW91IGV4cGVjdCB0byBoYXBwZW4/XG5cbiMjIyMgV2hhdCBhY3R1YWxseSBo
-YXBwZW5lZD9cblxuX1NjcmVlbnNob3RzIGFyZSBhcHByZWNpYXRlZF9cblxuKipEYXJ0IFNESyB2ZXJz
-aW9uKio6ICIrSC5kKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCJzZGstdmVyc2lvbiIpLnRleHRDb250
-ZW50KSsiXG5cblRoYW5rcyBmb3IgZmlsaW5nIVxuIl0sdCx0KSkudygwKSwicmVwb3J0LXByb2JsZW0i
-KX0sCiRTOjN9CkwuQlQucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQKdS5WLmIoYSkKdD1k
-b2N1bWVudC5xdWVyeVNlbGVjdG9yKCIucG9wdXAtcGFuZSIpLnN0eWxlCnJldHVybiB0LmRpc3BsYXk9
-Im5vbmUifSwKJFM6NDN9CkwuTC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIKdS5C
-LmIoYSkKdD13aW5kb3cubG9jYXRpb24ucGF0aG5hbWUKcz1MLkc2KHdpbmRvdy5sb2NhdGlvbi5ocmVm
-KQpyPUwuYUsod2luZG93LmxvY2F0aW9uLmhyZWYpCmlmKHQubGVuZ3RoPjEpTC5HNyh0LHMsciwhMSxu
-dWxsKQplbHNle0wuQkUodCxuZXcgQi5xcCgiIiwiIiwiIixDLkNNKSwhMCkKTC5CWCgiJm5ic3A7Iixu
-dWxsKX19LAokUzoxNn0KTC5XeC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT0i
-Y29sbGFwc2VkIgp1LlYuYihhKQp0PXRoaXMuYQpzPUouUkUodCkKcj10aGlzLmIKaWYoIXMuZ1AodCku
-dGcoMCxxKSl7cy5nUCh0KS5pKDAscSkKSi5kUihyKS5pKDAscSl9ZWxzZXtzLmdQKHQpLlIoMCxxKQpK
-LmRSKHIpLlIoMCxxKX19LAokUzozfQpMLkFPLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0
-PUoucUYodS5oLmIoYSkpLHM9dC4kdGkscj1zLkMoIn4oMSkiKS5iKG5ldyBMLmROKHRoaXMuYSkpCnUu
-TS5iKG51bGwpClcuSkUodC5hLHQuYixyLCExLHMuZCl9LAokUzo2fQpMLmROLnByb3RvdHlwZT17CiQx
-OmZ1bmN0aW9uKGEpe3ZhciB0CnUuVi5iKGEpCnQ9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigidGFibGVb
-ZGF0YS1wYXRoXSIpCnQudG9TdHJpbmcKTC50MihhLHRoaXMuYSx0LmdldEF0dHJpYnV0ZSgiZGF0YS0i
-K25ldyBXLlN5KG5ldyBXLmk3KHQpKS5PKCJwYXRoIikpKX0sCiRTOjN9CkwuSG8ucHJvdG90eXBlPXsK
-JDE6ZnVuY3Rpb24oYSl7dmFyIHQscyxyCnUuaC5iKGEpCnQ9Si5xRihhKQpzPXQuJHRpCnI9cy5DKCJ+
-KDEpIikuYihuZXcgTC54eihhLHRoaXMuYSkpCnUuTS5iKG51bGwpClcuSkUodC5hLHQuYixyLCExLHMu
-ZCl9LAokUzo2fQpMLnh6LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHM9bnVsbAp1LlYu
-YihhKQp0PXRoaXMuYQpMLmhYKHRoaXMuYixQLlFBKHQuZ2V0QXR0cmlidXRlKCJkYXRhLSIrbmV3IFcu
-U3kobmV3IFcuaTcodCkpLk8oIm9mZnNldCIpKSxzLHMpLFAuUUEodC5nZXRBdHRyaWJ1dGUoImRhdGEt
-IituZXcgVy5TeShuZXcgVy5pNyh0KSkuTygibGluZSIpKSxzLHMpKX0sCiRTOjN9CkwuSUMucHJvdG90
-eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQ9Si5xRih1LmguYihhKSkscz10LiR0aQpzLkMoIn4oMSki
-KS5iKEwuaVMoKSkKdS5NLmIobnVsbCkKVy5KRSh0LmEsdC5iLEwuaVMoKSwhMSxzLmQpfSwKJFM6Nn0K
-TC5mQy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt1LnAuYihhKQp0aGlzLmEuYU0oMCx0aGlzLmIp
-fSwKJFM6NDV9CkwublQucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtMLkZyKHRoaXMuYS5hLHRoaXMu
-Yix0aGlzLmMpfSwKJFM6MH0KTC5CWi5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuRnIodGhpcy5h
-LmEsbnVsbCxudWxsKX0sCiRTOjB9CkwuR0gucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dS5oLmIo
-YSkKJC56QigpLnRvU3RyaW5nCnUubS5hKCQub3coKS5xKDAsImhsanMiKSkuVjcoImhpZ2hsaWdodEJs
-b2NrIixbYV0pfSwKJFM6Nn0KTC5FRS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzCnUu
-Vi5iKGEpCnQ9dGhpcy5hCnM9dGhpcy5iCkwuYWYod2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLHQscywh
-MCxuZXcgTC5RTCh0LHMpKQpMLmhYKHRoaXMuYyx0LHMpfSwKJFM6M30KTC5RTC5wcm90b3R5cGU9ewok
-MDpmdW5jdGlvbigpe0wuRnIod2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLHRoaXMuYSx0aGlzLmIpfSwK
-JFM6MH0KTC5WUy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzPSJzZWxlY3RlZC1maWxl
-Igp1LmguYihhKQphLnRvU3RyaW5nCnQ9Si5SRShhKQppZihhLmdldEF0dHJpYnV0ZSgiZGF0YS0iK25l
-dyBXLlN5KG5ldyBXLmk3KGEpKS5PKCJuYW1lIikpPT09dGhpcy5hLmEpdC5nUChhKS5pKDAscykKZWxz
-ZSB0LmdQKGEpLlIoMCxzKX0sCiRTOjZ9CkwuVEQucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0
-dXJuIEwudDIodS5WLmIoYSksITAsbnVsbCl9LAokUzoxOH0KTC5BUy5wcm90b3R5cGU9ewokMTpmdW5j
-dGlvbihhKXtyZXR1cm4gdGhpcy5QTCh1LlYuYihhKSl9LApQTDpmdW5jdGlvbihhKXt2YXIgdD0wLHM9
-UC5GWCh1LlApLHI9MSxxLHA9W10sbz10aGlzLG4sbSxsLGssagp2YXIgJGFzeW5jJCQxPVAubHooZnVu
-Y3Rpb24oYixjKXtpZihiPT09MSl7cT1jCnQ9cn13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6cj0z
-Cmw9dS5OCnQ9NgpyZXR1cm4gUC5qUShMLnR5KEwuUTQoIi9hcHBseS1oaW50IixQLkZsKGwsbCkpLG8u
-YS5MdCgpKSwkYXN5bmMkJDEpCmNhc2UgNjpsPW8uYgpMLkc3KGwuYyxudWxsLGwuYiwhMSxudWxsKQpk
-b2N1bWVudC5ib2R5LmNsYXNzTGlzdC5hZGQoIm5lZWRzLXJlcnVuIikKcj0xCnQ9NQpicmVhawpjYXNl
-IDM6cj0yCmo9cQpuPUguUnUoaikKbT1ILnRzKGopCkwuQzIoIkNvdWxkIG5vdCBhcHBseSBoaW50Iixu
-LG0pCnQ9NQpicmVhawpjYXNlIDI6dD0xCmJyZWFrCmNhc2UgNTpyZXR1cm4gUC55QyhudWxsLHMpCmNh
-c2UgMTpyZXR1cm4gUC5mMyhxLHMpfX0pCnJldHVybiBQLkRJKCRhc3luYyQkMSxzKX0sCiRTOjE3fQpM
-LlhBLnByb3RvdHlwZT17CkViOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4hMH0sCmkwOmZ1bmN0aW9uKGEp
-e3JldHVybiEwfSwKJGlrRjoxfQpMLlpaLnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7dmFyIHQscz10
-aGlzLHI9UC5GbCh1Lk4sdS5LKQpyLlkoMCwidHlwZSIsTC52eShzLmEpKQpyLlkoMCwibmFtZSIscy5i
-KQp0PXMuYwppZih0IT1udWxsKXIuWSgwLCJzdWJ0cmVlIixMLlZEKHQpKQp0PXMuZAppZih0IT1udWxs
-KXIuWSgwLCJwYXRoIix0KQp0PXMuZQppZih0IT1udWxsKXIuWSgwLCJocmVmIix0KQp0PXMuZgppZih0
-IT1udWxsKXIuWSgwLCJlZGl0Q291bnQiLHQpCnJldHVybiByfX0KTC5POS5wcm90b3R5cGU9ewp3OmZ1
-bmN0aW9uKGEpe3JldHVybiB0aGlzLmJ9fQpNLmxJLnByb3RvdHlwZT17CldPOmZ1bmN0aW9uKGEsYil7
-dmFyIHQscz1udWxsCk0uWUYoImFic29sdXRlIixILlZNKFtiLG51bGwsbnVsbCxudWxsLG51bGwsbnVs
-bCxudWxsXSx1LnMpKQp0PXRoaXMuYQp0PXQuWXIoYik+MCYmIXQuaEsoYikKaWYodClyZXR1cm4gYgp0
-PUQuUlgoKQpyZXR1cm4gdGhpcy5xNygwLHQsYixzLHMscyxzLHMscyl9LAp6ZjpmdW5jdGlvbihhKXt2
-YXIgdCxzLHI9WC5DTChhLHRoaXMuYSkKci5JVigpCnQ9ci5kCnM9dC5sZW5ndGgKaWYocz09PTApe3Q9
-ci5iCnJldHVybiB0PT1udWxsPyIuIjp0fWlmKHM9PT0xKXt0PXIuYgpyZXR1cm4gdD09bnVsbD8iLiI6
-dH1pZigwPj1zKXJldHVybiBILk9IKHQsLTEpCnQucG9wKCkKQy5ObS5tdihyLmUpCnIuSVYoKQpyZXR1
-cm4gci53KDApfSwKcTc6ZnVuY3Rpb24oYSxiLGMsZCxlLGYsZyxoLGkpe3ZhciB0PUguVk0oW2IsYyxk
-LGUsZixnLGgsaV0sdS5zKQpNLllGKCJqb2luIix0KQpyZXR1cm4gdGhpcy5JUChuZXcgSC5VNSh0LHUu
-YkIuYihuZXcgTS5NaSgpKSx1LmNjKSl9LApJUDpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbixt
-LGwsawp1LlguYihhKQpmb3IodD1hLiR0aSxzPXQuQygiYTIoY1guRSkiKS5iKG5ldyBNLnE3KCkpLHI9
-YS5na3ooYSksdD1uZXcgSC5TTyhyLHMsdC5DKCJTTzxjWC5FPiIpKSxzPXRoaXMuYSxxPSExLHA9ITEs
-bz0iIjt0LkYoKTspe249ci5nbCgpCmlmKHMuaEsobikmJnApe209WC5DTChuLHMpCmw9by5jaGFyQ29k
-ZUF0KDApPT0wP286bwpvPUMueEIuTmoobCwwLHMuU3AobCwhMCkpCm0uYj1vCmlmKHMuZHMobykpQy5O
-bS5ZKG0uZSwwLHMuZ21JKCkpCm89bS53KDApfWVsc2UgaWYocy5ZcihuKT4wKXtwPSFzLmhLKG4pCm89
-SC5kKG4pfWVsc2V7az1uLmxlbmd0aAppZihrIT09MCl7aWYoMD49aylyZXR1cm4gSC5PSChuLDApCms9
-cy5VZChuWzBdKX1lbHNlIGs9ITEKaWYoIWspaWYocSlvKz1zLmdtSSgpCm8rPW59cT1zLmRzKG4pfXJl
-dHVybiBvLmNoYXJDb2RlQXQoMCk9PTA/bzpvfSwKbzU6ZnVuY3Rpb24oYSl7dmFyIHQKaWYoIXRoaXMu
-eTMoYSkpcmV0dXJuIGEKdD1YLkNMKGEsdGhpcy5hKQp0LnJSKCkKcmV0dXJuIHQudygwKX0sCnkzOmZ1
-bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrCmEudG9TdHJpbmcKdD10aGlzLmEKcz10Llly
-KGEpCmlmKHMhPT0wKXtpZih0PT09JC5LaygpKWZvcihyPTA7cjxzOysrcilpZihDLnhCLlcoYSxyKT09
-PTQ3KXJldHVybiEwCnE9cwpwPTQ3fWVsc2V7cT0wCnA9bnVsbH1mb3Iobz1uZXcgSC5xaihhKS5hLG49
-by5sZW5ndGgscj1xLG09bnVsbDtyPG47KytyLG09cCxwPWwpe2w9Qy54Qi5tKG8scikKaWYodC5yNChs
-KSl7aWYodD09PSQuS2soKSYmbD09PTQ3KXJldHVybiEwCmlmKHAhPW51bGwmJnQucjQocCkpcmV0dXJu
-ITAKaWYocD09PTQ2KWs9bT09bnVsbHx8bT09PTQ2fHx0LnI0KG0pCmVsc2Ugaz0hMQppZihrKXJldHVy
-biEwfX1pZihwPT1udWxsKXJldHVybiEwCmlmKHQucjQocCkpcmV0dXJuITAKaWYocD09PTQ2KXQ9bT09
-bnVsbHx8dC5yNChtKXx8bT09PTQ2CmVsc2UgdD0hMQppZih0KXJldHVybiEwCnJldHVybiExfSwKSFA6
-ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwLG8sbixtPXRoaXMsbD0nVW5hYmxlIHRvIGZpbmQgYSBw
-YXRoIHRvICInCmI9bS5XTygwLGIpCnQ9bS5hCmlmKHQuWXIoYik8PTAmJnQuWXIoYSk+MClyZXR1cm4g
-bS5vNShhKQppZih0LllyKGEpPD0wfHx0LmhLKGEpKWE9bS5XTygwLGEpCmlmKHQuWXIoYSk8PTAmJnQu
-WXIoYik+MCl0aHJvdyBILmIoWC5JNyhsK0guZChhKSsnIiBmcm9tICInK0guZChiKSsnIi4nKSkKcz1Y
-LkNMKGIsdCkKcy5yUigpCnI9WC5DTChhLHQpCnIuclIoKQpxPXMuZApwPXEubGVuZ3RoCmlmKHAhPT0w
-KXtpZigwPj1wKXJldHVybiBILk9IKHEsMCkKcT1KLlJNKHFbMF0sIi4iKX1lbHNlIHE9ITEKaWYocSly
-ZXR1cm4gci53KDApCnE9cy5iCnA9ci5iCmlmKHEhPXApcT1xPT1udWxsfHxwPT1udWxsfHwhdC5OYyhx
-LHApCmVsc2UgcT0hMQppZihxKXJldHVybiByLncoMCkKd2hpbGUoITApe3E9cy5kCnA9cS5sZW5ndGgK
-aWYocCE9PTApe289ci5kCm49by5sZW5ndGgKaWYobiE9PTApe2lmKDA+PXApcmV0dXJuIEguT0gocSww
-KQpxPXFbMF0KaWYoMD49bilyZXR1cm4gSC5PSChvLDApCm89dC5OYyhxLG9bMF0pCnE9b31lbHNlIHE9
-ITF9ZWxzZSBxPSExCmlmKCFxKWJyZWFrCkMuTm0uVzQocy5kLDApCkMuTm0uVzQocy5lLDEpCkMuTm0u
-VzQoci5kLDApCkMuTm0uVzQoci5lLDEpfXE9cy5kCnA9cS5sZW5ndGgKaWYocCE9PTApe2lmKDA+PXAp
-cmV0dXJuIEguT0gocSwwKQpxPUouUk0ocVswXSwiLi4iKX1lbHNlIHE9ITEKaWYocSl0aHJvdyBILmIo
-WC5JNyhsK0guZChhKSsnIiBmcm9tICInK0guZChiKSsnIi4nKSkKcT11Lk4KQy5ObS5VRyhyLmQsMCxQ
-Lk84KHMuZC5sZW5ndGgsIi4uIiwhMSxxKSkKQy5ObS5ZKHIuZSwwLCIiKQpDLk5tLlVHKHIuZSwxLFAu
-Tzgocy5kLmxlbmd0aCx0LmdtSSgpLCExLHEpKQp0PXIuZApxPXQubGVuZ3RoCmlmKHE9PT0wKXJldHVy
-biIuIgppZihxPjEmJkouUk0oQy5ObS5ncloodCksIi4iKSl7dD1yLmQKaWYoMD49dC5sZW5ndGgpcmV0
-dXJuIEguT0godCwtMSkKdC5wb3AoKQp0PXIuZQpDLk5tLm12KHQpCkMuTm0ubXYodCkKQy5ObS5pKHQs
-IiIpfXIuYj0iIgpyLklWKCkKcmV0dXJuIHIudygwKX19Ck0uTWkucHJvdG90eXBlPXsKJDE6ZnVuY3Rp
-b24oYSl7cmV0dXJuIEgueShhKSE9bnVsbH0sCiRTOjd9Ck0ucTcucHJvdG90eXBlPXsKJDE6ZnVuY3Rp
-b24oYSl7cmV0dXJuIEgueShhKSE9PSIifSwKJFM6N30KTS5Oby5wcm90b3R5cGU9ewokMTpmdW5jdGlv
-bihhKXtILnkoYSkKcmV0dXJuIGE9PW51bGw/Im51bGwiOiciJythKyciJ30sCiRTOjV9CkIuZnYucHJv
-dG90eXBlPXsKeFo6ZnVuY3Rpb24oYSl7dmFyIHQscz10aGlzLllyKGEpCmlmKHM+MClyZXR1cm4gSi5s
-ZChhLDAscykKaWYodGhpcy5oSyhhKSl7aWYoMD49YS5sZW5ndGgpcmV0dXJuIEguT0goYSwwKQp0PWFb
-MF19ZWxzZSB0PW51bGwKcmV0dXJuIHR9LApOYzpmdW5jdGlvbihhLGIpe3JldHVybiBhPT1ifX0KWC5X
-RC5wcm90b3R5cGU9ewpJVjpmdW5jdGlvbigpe3ZhciB0LHMscj10aGlzCndoaWxlKCEwKXt0PXIuZApp
-ZighKHQubGVuZ3RoIT09MCYmSi5STShDLk5tLmdyWih0KSwiIikpKWJyZWFrCnQ9ci5kCmlmKDA+PXQu
-bGVuZ3RoKXJldHVybiBILk9IKHQsLTEpCnQucG9wKCkKQy5ObS5tdihyLmUpfXQ9ci5lCnM9dC5sZW5n
-dGgKaWYocyE9PTApQy5ObS5ZKHQscy0xLCIiKX0sCnJSOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxv
-LG49dGhpcyxtPUguVk0oW10sdS5zKQpmb3IodD1uLmQscz10Lmxlbmd0aCxyPTAscT0wO3E8dC5sZW5n
-dGg7dC5sZW5ndGg9PT1zfHwoMCxILmxrKSh0KSwrK3Epe3A9dFtxXQpvPUouaWEocCkKaWYoIShvLkRO
-KHAsIi4iKXx8by5ETihwLCIiKSkpaWYoby5ETihwLCIuLiIpKXtvPW0ubGVuZ3RoCmlmKG8hPT0wKXtp
-ZigwPj1vKXJldHVybiBILk9IKG0sLTEpCm0ucG9wKCl9ZWxzZSArK3J9ZWxzZSBDLk5tLmkobSxwKX1p
-ZihuLmI9PW51bGwpQy5ObS5VRyhtLDAsUC5POChyLCIuLiIsITEsdS5OKSkKaWYobS5sZW5ndGg9PT0w
-JiZuLmI9PW51bGwpQy5ObS5pKG0sIi4iKQpuLnNuSihtKQp0PW4uYQpuLnNQaChQLk84KG0ubGVuZ3Ro
-KzEsdC5nbUkoKSwhMCx1Lk4pKQpzPW4uYgppZihzPT1udWxsfHxtLmxlbmd0aD09PTB8fCF0LmRzKHMp
-KUMuTm0uWShuLmUsMCwiIikKcz1uLmIKaWYocyE9bnVsbCYmdD09PSQuS2soKSl7cy50b1N0cmluZwpu
-LmI9SC55cyhzLCIvIiwiXFwiKX1uLklWKCl9LAp3OmZ1bmN0aW9uKGEpe3ZhciB0LHMscj10aGlzLHE9
-ci5iCnE9cSE9bnVsbD9xOiIiCmZvcih0PTA7dDxyLmQubGVuZ3RoOysrdCl7cz1yLmUKaWYodD49cy5s
-ZW5ndGgpcmV0dXJuIEguT0gocyx0KQpzPXErSC5kKHNbdF0pCnE9ci5kCmlmKHQ+PXEubGVuZ3RoKXJl
-dHVybiBILk9IKHEsdCkKcT1zK0guZChxW3RdKX1xKz1ILmQoQy5ObS5nclooci5lKSkKcmV0dXJuIHEu
-Y2hhckNvZGVBdCgwKT09MD9xOnF9LApzbko6ZnVuY3Rpb24oYSl7dGhpcy5kPXUuYS5iKGEpfSwKc1Bo
-OmZ1bmN0aW9uKGEpe3RoaXMuZT11LmEuYihhKX19ClguZHYucHJvdG90eXBlPXsKdzpmdW5jdGlvbihh
-KXtyZXR1cm4iUGF0aEV4Y2VwdGlvbjogIit0aGlzLmF9LAokaVJ6OjF9Ck8uekwucHJvdG90eXBlPXsK
-dzpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nb2ModGhpcyl9fQpFLk9GLnByb3RvdHlwZT17ClVkOmZ1
-bmN0aW9uKGEpe3JldHVybiBDLnhCLnRnKGEsIi8iKX0sCnI0OmZ1bmN0aW9uKGEpe3JldHVybiBhPT09
-NDd9LApkczpmdW5jdGlvbihhKXt2YXIgdD1hLmxlbmd0aApyZXR1cm4gdCE9PTAmJkMueEIubShhLHQt
-MSkhPT00N30sClNwOmZ1bmN0aW9uKGEsYil7aWYoYS5sZW5ndGghPT0wJiZDLnhCLlcoYSwwKT09PTQ3
-KXJldHVybiAxCnJldHVybiAwfSwKWXI6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuU3AoYSwhMSl9LApo
-SzpmdW5jdGlvbihhKXtyZXR1cm4hMX0sCmdvYzpmdW5jdGlvbigpe3JldHVybiJwb3NpeCJ9LApnbUk6
-ZnVuY3Rpb24oKXtyZXR1cm4iLyJ9fQpGLnJ1LnByb3RvdHlwZT17ClVkOmZ1bmN0aW9uKGEpe3JldHVy
-biBDLnhCLnRnKGEsIi8iKX0sCnI0OmZ1bmN0aW9uKGEpe3JldHVybiBhPT09NDd9LApkczpmdW5jdGlv
-bihhKXt2YXIgdD1hLmxlbmd0aAppZih0PT09MClyZXR1cm4hMQppZihDLnhCLm0oYSx0LTEpIT09NDcp
-cmV0dXJuITAKcmV0dXJuIEMueEIuVGMoYSwiOi8vIikmJnRoaXMuWXIoYSk9PT10fSwKU3A6ZnVuY3Rp
-b24oYSxiKXt2YXIgdCxzLHIscSxwPWEubGVuZ3RoCmlmKHA9PT0wKXJldHVybiAwCmlmKEMueEIuVyhh
-LDApPT09NDcpcmV0dXJuIDEKZm9yKHQ9MDt0PHA7Kyt0KXtzPUMueEIuVyhhLHQpCmlmKHM9PT00Nyly
-ZXR1cm4gMAppZihzPT09NTgpe2lmKHQ9PT0wKXJldHVybiAwCnI9Qy54Qi5YVShhLCIvIixDLnhCLlFp
-KGEsIi8vIix0KzEpP3QrMzp0KQppZihyPD0wKXJldHVybiBwCmlmKCFifHxwPHIrMylyZXR1cm4gcgpp
-ZighQy54Qi5uKGEsImZpbGU6Ly8iKSlyZXR1cm4gcgppZighQi5ZdShhLHIrMSkpcmV0dXJuIHIKcT1y
-KzMKcmV0dXJuIHA9PT1xP3E6cis0fX1yZXR1cm4gMH0sCllyOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlz
-LlNwKGEsITEpfSwKaEs6ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RoIT09MCYmQy54Qi5XKGEsMCk9
-PT00N30sCmdvYzpmdW5jdGlvbigpe3JldHVybiJ1cmwifSwKZ21JOmZ1bmN0aW9uKCl7cmV0dXJuIi8i
-fX0KTC5JVi5wcm90b3R5cGU9ewpVZDpmdW5jdGlvbihhKXtyZXR1cm4gQy54Qi50ZyhhLCIvIil9LApy
-NDpmdW5jdGlvbihhKXtyZXR1cm4gYT09PTQ3fHxhPT09OTJ9LApkczpmdW5jdGlvbihhKXt2YXIgdD1h
-Lmxlbmd0aAppZih0PT09MClyZXR1cm4hMQp0PUMueEIubShhLHQtMSkKcmV0dXJuISh0PT09NDd8fHQ9
-PT05Mil9LApTcDpmdW5jdGlvbihhLGIpe3ZhciB0LHMscj1hLmxlbmd0aAppZihyPT09MClyZXR1cm4g
-MAp0PUMueEIuVyhhLDApCmlmKHQ9PT00NylyZXR1cm4gMQppZih0PT09OTIpe2lmKHI8Mnx8Qy54Qi5X
-KGEsMSkhPT05MilyZXR1cm4gMQpzPUMueEIuWFUoYSwiXFwiLDIpCmlmKHM+MCl7cz1DLnhCLlhVKGEs
-IlxcIixzKzEpCmlmKHM+MClyZXR1cm4gc31yZXR1cm4gcn1pZihyPDMpcmV0dXJuIDAKaWYoIUIuT1Mo
-dCkpcmV0dXJuIDAKaWYoQy54Qi5XKGEsMSkhPT01OClyZXR1cm4gMApyPUMueEIuVyhhLDIpCmlmKCEo
-cj09PTQ3fHxyPT09OTIpKXJldHVybiAwCnJldHVybiAzfSwKWXI6ZnVuY3Rpb24oYSl7cmV0dXJuIHRo
-aXMuU3AoYSwhMSl9LApoSzpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5ZcihhKT09PTF9LApPdDpmdW5j
-dGlvbihhLGIpe3ZhciB0CmlmKGE9PT1iKXJldHVybiEwCmlmKGE9PT00NylyZXR1cm4gYj09PTkyCmlm
-KGE9PT05MilyZXR1cm4gYj09PTQ3CmlmKChhXmIpIT09MzIpcmV0dXJuITEKdD1hfDMyCnJldHVybiB0
-Pj05NyYmdDw9MTIyfSwKTmM6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIKaWYoYT09YilyZXR1cm4hMAp0
-PWEubGVuZ3RoCmlmKHQhPT1iLmxlbmd0aClyZXR1cm4hMQpmb3Iocz1KLnJZKGIpLHI9MDtyPHQ7Kyty
-KWlmKCF0aGlzLk90KEMueEIuVyhhLHIpLHMuVyhiLHIpKSlyZXR1cm4hMQpyZXR1cm4hMH0sCmdvYzpm
-dW5jdGlvbigpe3JldHVybiJ3aW5kb3dzIn0sCmdtSTpmdW5jdGlvbigpe3JldHVybiJcXCJ9fTsoZnVu
-Y3Rpb24gYWxpYXNlcygpe3ZhciB0PUoudkIucHJvdG90eXBlCnQuVT10LncKdC5Taj10LmU3CnQ9Si5N
-Ri5wcm90b3R5cGUKdC50PXQudwp0PVAuY1gucHJvdG90eXBlCnQuR0c9dC5ldgp0PVAuay5wcm90b3R5
-cGUKdC54Yj10LncKdD1XLmN2LnByb3RvdHlwZQp0LkRXPXQucjYKdD1XLm02LnByb3RvdHlwZQp0LmpG
-PXQuRWIKdD1QLkU0LnByb3RvdHlwZQp0LlVyPXQucQp0LmU0PXQuWX0pKCk7KGZ1bmN0aW9uIGluc3Rh
-bGxUZWFyT2Zmcygpe3ZhciB0PWh1bmtIZWxwZXJzLl9zdGF0aWNfMSxzPWh1bmtIZWxwZXJzLl9zdGF0
-aWNfMCxyPWh1bmtIZWxwZXJzLmluc3RhbGxJbnN0YW5jZVRlYXJPZmYscT1odW5rSGVscGVycy5pbnN0
-YWxsU3RhdGljVGVhck9mZixwPWh1bmtIZWxwZXJzLl9pbnN0YW5jZV8xdQp0KFAsIkVYIiwiWlYiLDgp
-CnQoUCwieXQiLCJvQSIsOCkKdChQLCJxVyIsIkJ6Iiw4KQpzKFAsIlVJIiwiZU4iLDIpCnIoUC5QZi5w
-cm90b3R5cGUsImdZSiIsMCwxLG51bGwsWyIkMiIsIiQxIl0sWyJ3MCIsInBtIl0sMjgsMCkKdChQLCJD
-eSIsIk5DIiwxKQp0KFAsIlBIIiwiTXQiLDUpCnEoVywicFMiLDQsbnVsbCxbIiQ0Il0sWyJxRCJdLDks
-MCkKcShXLCJWNCIsNCxudWxsLFsiJDQiXSxbIlFXIl0sOSwwKQpwKFAuQXMucHJvdG90eXBlLCJndU0i
-LCJUIiw1KQp0KFAsImlHIiwid1kiLDEpCnQoUCwidzAiLCJMNyIsMzIpCnQoTCwiaVMiLCJpNiIsMTgp
-fSkoKTsoZnVuY3Rpb24gaW5oZXJpdGFuY2UoKXt2YXIgdD1odW5rSGVscGVycy5taXhpbixzPWh1bmtI
-ZWxwZXJzLmluaGVyaXQscj1odW5rSGVscGVycy5pbmhlcml0TWFueQpzKFAuayxudWxsKQpyKFAuayxb
-SC5lbyxKLnZCLEoubTEsUC5uWSxQLmNYLEguYTcsUC5BbixILlNVLEguUmUsSC53dixQLlBuLEguV1Us
-SC5MSSxILlRwLEguZjksUC5YUyxILmJxLEguWE8sUC5ZayxILmRiLEguTjYsSC5WUixILkVLLEguUGIs
-SC50USxILlNkLEguSmMsSC5HLFAuVzMsUC5paCxQLkZ5LFAuR1YsUC5iOCxQLlBmLFAuRmUsUC52cyxQ
-Lk9NLFAucWgsUC5NTyxQLmtULFAueEksUC5DdyxQLm0wLFAuWHYsUC5ibixQLmxtLFAubEQsUC5LUCxQ
-LmxmLFAuVEMsUC5VayxQLlNoLFAuUncsUC5ieixQLmEyLFAuaVAsUC5GSyxQLms1LFAuS1ksUC5DRCxQ
-LmFFLFAuRUgsUC56TSxQLlowLFAuTjMsUC5jOCxQLk9kLFAuaWIsUC5HeixQLnFVLFAuUm4sUC5HRCxQ
-LkRuLFAuUEUsUC5VZixXLmlkLFcuRmssVy5KUSxXLkdtLFcudkQsVy5tNixXLk93LFcuVzksVy5kVyxX
-LkZiLFcua0YsVy5tayxXLktvLFAuaUosUC5FNCxQLm42LE0uSDcsVS5MTCxVLmQyLFUuU2UsVS5NbCxV
-LnlELFUud2IsQi5qOCxCLnFwLFQubVEsTC5YQSxMLlpaLEwuTzksTS5sSSxPLnpMLFguV0QsWC5kdl0p
-CnIoSi52QixbSi55RSxKLllFLEouTUYsSi5qZCxKLnFJLEouRHIsSC5FVCxXLkQwLFcuQXosVy5MZSxX
-Lk5oLFcuSUIsVy5uNyxXLmVhLFcuYnIsVy5TZyxXLnU4LFcuSzcsVy5YVyxQLmhGXSkKcihKLk1GLFtK
-LmlDLEoua2QsSi5jNV0pCnMoSi5QbyxKLmpkKQpyKEoucUksW0ouYlUsSi5WQV0pCnMoUC51eSxQLm5Z
-KQpyKFAudXksW0guWEMsVy53eixXLmU3XSkKcyhILnFqLEguWEMpCnIoUC5jWCxbSC5iUSxILmkxLEgu
-VTUsSC5YUixQLm1XLEgudW5dKQpyKEguYlEsW0guYUwsSC5pNSxQLnh1XSkKcihILmFMLFtILm5ILEgu
-QTgsUC5pOF0pCnMoSC54eSxILmkxKQpyKFAuQW4sW0guTUgsSC5TT10pCnMoUC5SVSxQLlBuKQpzKFAu
-R2osUC5SVSkKcyhILlBELFAuR2opCnMoSC5MUCxILldVKQpyKEguVHAsW0guQ2osSC5BbSxILmxjLEgu
-ZEMsSC53TixILlZYLFAudGgsUC5oYSxQLlZzLFAuRnQsUC55SCxQLldNLFAuU1gsUC5HcyxQLmRhLFAu
-b1EsUC5wVixQLlU3LFAudnIsUC5ySCxQLktGLFAuWkwsUC5SVCxQLmpaLFAucnEsUC5SVyxQLkI1LFAu
-dU8sUC5wSyxQLmhqLFAuVnAsUC5PUixQLnJhLFAueVEsUC50aSxQLldGLFAubjEsUC5jUyxQLlZDLFAu
-SlQsUC5lMSxQLk5ZLFAuUlosUC5NRSxQLnk1LFAucTMsUC55SSxQLmM2LFAucWQsVy5DdixXLktTLFcu
-QTMsVy52TixXLlV2LFcuRWcsVy5FbyxXLldrLFcuSUEsVy5mbSxQLmxSLFAuamcsUC5HRSxQLk43LFAu
-dVEsUC5QQyxQLm10LFAuTnosUC5RUyxQLm5wLFUuTUQsVS5hTixVLmIwLEwuZSxMLlZXLEwub1osTC5q
-cixMLnFsLEwueTgsTC5IaSxMLkJULEwuTCxMLld4LEwuQU8sTC5kTixMLkhvLEwueHosTC5JQyxMLmZD
-LEwublQsTC5CWixMLkdILEwuRUUsTC5RTCxMLlZTLEwuVEQsTC5BUyxNLk1pLE0ucTcsTS5Ob10pCnIo
-UC5YUyxbSC5XMCxILmF6LEgudlYsSC5FcSxQLkM2LEgudTksUC5VZCxQLm4sUC51LFAubXAsUC51YixQ
-LmRzLFAubGosUC5VVixQLmNdKQpyKEgubGMsW0guengsSC5yVF0pCnMoSC5rWSxQLkM2KQpzKFAuaWws
-UC5ZaykKcihQLmlsLFtILk41LFAudXcsVy5jZixXLlN5XSkKcihQLm1XLFtILktXLFAucTRdKQpzKEgu
-TFosSC5FVCkKcihILkxaLFtILlJHLEguV0JdKQpzKEguVlAsSC5SRykKcyhILkRnLEguVlApCnMoSC5a
-RyxILldCKQpzKEguUGcsSC5aRykKcihILlBnLFtILnhqLEguZEUsSC5aQSxILndmLEguUHEsSC5lRSxI
-LlY2XSkKcihILnU5LFtILmh6LEguaU1dKQpzKFAuWmYsUC5QZikKcyhQLkppLFAubTApCnMoUC5iNixQ
-Llh2KQpzKFAuVmosUC5UQykKcihQLlVrLFtQLkNWLFAuWmksUC5ieV0pCnMoUC53SSxQLmtUKQpyKFAu
-d0ksW1AuVTgsUC5vaixQLk14LFAuRTMsUC5HWV0pCnMoUC5LOCxQLlVkKQpzKFAudHUsUC5TaCkKcyhQ
-LnU1LFAuWmkpCnIoUC5GSyxbUC5DUCxQLktOXSkKcihQLnUsW1AuYkosUC5lWV0pCnMoUC5xZSxQLkRu
-KQpyKFcuRDAsW1cudUgsVy53YSxXLks1LFcuQ21dKQpyKFcudUgsW1cuY3YsVy5ueCxXLlFGLFcuQ1Fd
-KQpyKFcuY3YsW1cucUUsUC5kNV0pCnIoVy5xRSxbVy5HaCxXLmZZLFcubkIsVy5RUCxXLmg0LFcuU04s
-Vy5scCxXLlRiLFcuSXYsVy5XUCxXLnlZXSkKcyhXLm9KLFcuTGUpCnMoVy5oSCxXLkF6KQpzKFcuVmIs
-Vy5RRikKcyhXLk83LFcud2EpCnIoVy5lYSxbVy53NixXLmV3XSkKcyhXLkFqLFcudzYpCnMoVy5yQixX
-Lks3KQpzKFcuQkgsVy5yQikKcyhXLnc0LFcuSUIpCnMoVy5vYSxXLlhXKQpzKFcucmgsVy5vYSkKcyhX
-Lmk3LFcuY2YpCnMoUC5BcyxQLlZqKQpyKFAuQXMsW1cuSTQsUC5LZV0pCnMoVy5STyxQLnFoKQpzKFcu
-ZXUsVy5STykKcyhXLnhDLFAuTU8pCnMoVy5jdCxXLm02KQpzKFAuQmYsUC5pSikKcihQLkU0LFtQLnI3
-LFAuY29dKQpzKFAuVHosUC5jbykKcyhQLm5kLFAuZDUpCnMoQi5mdixPLnpMKQpyKEIuZnYsW0UuT0Ys
-Ri5ydSxMLklWXSkKdChILlhDLEguUmUpCnQoSC5SRyxQLmxEKQp0KEguVlAsSC5TVSkKdChILldCLFAu
-bEQpCnQoSC5aRyxILlNVKQp0KFAublksUC5sRCkKdChQLlRDLFAubGYpCnQoUC5SVSxQLktQKQp0KFcu
-TGUsVy5pZCkKdChXLks3LFAubEQpCnQoVy5yQixXLkdtKQp0KFcuWFcsUC5sRCkKdChXLm9hLFcuR20p
-CnQoUC5jbyxQLmxEKX0pKCkKdmFyIHY9e3R5cGVVbml2ZXJzZTp7ZUM6bmV3IE1hcCgpLHRSOnt9LGVU
-Ont9LHRQVjp7fSxzRUE6W119LG1hbmdsZWRHbG9iYWxOYW1lczp7S046ImludCIsQ1A6ImRvdWJsZSIs
-Rks6Im51bSIscVU6IlN0cmluZyIsYTI6ImJvb2wiLGM4OiJOdWxsIix6TToiTGlzdCJ9LG1hbmdsZWRO
-YW1lczp7fSxnZXRUeXBlRnJvbU5hbWU6Z2V0R2xvYmFsRnJvbU5hbWUsbWV0YWRhdGE6W10sdHlwZXM6
-WyJjOCgpIiwiQChAKSIsIn4oKSIsImM4KEFqKSIsImM4KEAsQCkiLCJxVShxVSkiLCJjOChjdikiLCJh
-MihxVSkiLCJ+KH4oKSkiLCJhMihjdixxVSxxVSxKUSkiLCJjOChAKSIsIn4oeHU8cVU+KSIsImM4KHFV
-LEApIiwiYzgocVUpIiwiYzgocVUscVUpIiwiYTIoa0YpIiwiYzgoZWEpIiwiYjg8Yzg+KEFqKSIsIn4o
-QWopIiwiWjA8cVUscVU+KFowPHFVLHFVPixxVSkiLCJjOCh+KCkpIiwiYzgoQCxHeikiLCJ+KHFVLHFV
-KSIsIm42KEtOKSIsIm42KEAsQCkiLCJhMih1SCkiLCJjOChLTixAKSIsIkAoZWEpIiwifihrW0d6XSki
-LCJjOChAW0d6XSkiLCJ+KHVILHVIKSIsImEyKHh1PHFVPikiLCJrKEApIiwicjcoQCkiLCJUejxAPihA
-KSIsIkU0KEApIiwiYTIoSDcpIiwiTEwoQCkiLCJaMDxxVSxrPihMTCkiLCJ2czxAPihAKSIsIkAocVUp
-IiwiYzgoWjA8cVUsaz4pIiwiYzgoR0QsQCkiLCJxVShBaikiLCJAKEAscVUpIiwiYzgoZXcpIiwifihx
-VSxLTikiLCJ+KHFVW0BdKSIsIktOKEtOLEtOKSIsIn4oQCkiXSxpbnRlcmNlcHRvcnNCeVRhZzpudWxs
-LGxlYWZUYWdzOm51bGx9CkgueGIodi50eXBlVW5pdmVyc2UsSlNPTi5wYXJzZSgneyJjNSI6Ik1GIiwi
-aUMiOiJNRiIsImtkIjoiTUYiLCJyeCI6ImVhIiwiZTUiOiJlYSIsIlkwIjoiZDUiLCJ0cCI6ImQ1Iiwi
-djAiOiJldyIsIk1yIjoicUUiLCJlTCI6InFFIiwiSTAiOiJ1SCIsImhzIjoidUgiLCJYZyI6IlFGIiwi
-bnIiOiJBaiIsInk0IjoidzYiLCJhUCI6IkNtIiwieGMiOiJueCIsImtKIjoibngiLCJ6VSI6IkRnIiwi
-ZGYiOiJFVCIsInlFIjp7ImEyIjpbXX0sIllFIjp7ImM4IjpbXX0sIk1GIjp7InZtIjpbXSwiRUgiOltd
-fSwiamQiOnsiek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIlBvIjp7ImpkIjpbIjEiXSwi
-ek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIm0xIjp7IkFuIjpbIjEiXX0sInFJIjp7IkNQ
-IjpbXSwiRksiOltdfSwiYlUiOnsiS04iOltdLCJDUCI6W10sIkZLIjpbXX0sIlZBIjp7IkNQIjpbXSwi
-RksiOltdfSwiRHIiOnsicVUiOltdLCJ2WCI6W119LCJxaiI6eyJSZSI6WyJLTiJdLCJsRCI6WyJLTiJd
-LCJ6TSI6WyJLTiJdLCJiUSI6WyJLTiJdLCJjWCI6WyJLTiJdLCJsRC5FIjoiS04iLCJSZS5FIjoiS04i
-fSwiYlEiOnsiY1giOlsiMSJdfSwiYUwiOnsiYlEiOlsiMSJdLCJjWCI6WyIxIl19LCJuSCI6eyJhTCI6
-WyIxIl0sImJRIjpbIjEiXSwiY1giOlsiMSJdLCJhTC5FIjoiMSIsImNYLkUiOiIxIn0sImE3Ijp7IkFu
-IjpbIjEiXX0sImkxIjp7ImNYIjpbIjIiXSwiY1guRSI6IjIifSwieHkiOnsiaTEiOlsiMSIsIjIiXSwi
-YlEiOlsiMiJdLCJjWCI6WyIyIl0sImNYLkUiOiIyIn0sIk1IIjp7IkFuIjpbIjIiXX0sIkE4Ijp7ImFM
-IjpbIjIiXSwiYlEiOlsiMiJdLCJjWCI6WyIyIl0sImFMLkUiOiIyIiwiY1guRSI6IjIifSwiVTUiOnsi
-Y1giOlsiMSJdLCJjWC5FIjoiMSJ9LCJTTyI6eyJBbiI6WyIxIl19LCJYQyI6eyJSZSI6WyIxIl0sImxE
-IjpbIjEiXSwiek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sInd2Ijp7IkdEIjpbXX0sIlBE
-Ijp7IkdqIjpbIjEiLCIyIl0sIlJVIjpbIjEiLCIyIl0sIlBuIjpbIjEiLCIyIl0sIktQIjpbIjEiLCIy
-Il0sIlowIjpbIjEiLCIyIl19LCJXVSI6eyJaMCI6WyIxIiwiMiJdfSwiTFAiOnsiV1UiOlsiMSIsIjIi
-XSwiWjAiOlsiMSIsIjIiXX0sIlhSIjp7ImNYIjpbIjEiXSwiY1guRSI6IjEifSwiTEkiOnsidlEiOltd
-fSwiVzAiOnsiWFMiOltdfSwiYXoiOnsiWFMiOltdfSwidlYiOnsiWFMiOltdfSwiWE8iOnsiR3oiOltd
-fSwiVHAiOnsiRUgiOltdfSwibGMiOnsiRUgiOltdfSwiengiOnsiRUgiOltdfSwiclQiOnsiRUgiOltd
-fSwiRXEiOnsiWFMiOltdfSwia1kiOnsiWFMiOltdfSwiTjUiOnsiRm8iOlsiMSIsIjIiXSwiWWsiOlsi
-MSIsIjIiXSwiWjAiOlsiMSIsIjIiXSwiWWsuSyI6IjEiLCJZay5WIjoiMiJ9LCJpNSI6eyJiUSI6WyIx
-Il0sImNYIjpbIjEiXSwiY1guRSI6IjEifSwiTjYiOnsiQW4iOlsiMSJdfSwiVlIiOnsid0wiOltdLCJ2
-WCI6W119LCJFSyI6eyJpYiI6W10sIk9kIjpbXX0sIktXIjp7ImNYIjpbImliIl0sImNYLkUiOiJpYiJ9
-LCJQYiI6eyJBbiI6WyJpYiJdfSwidFEiOnsiT2QiOltdfSwidW4iOnsiY1giOlsiT2QiXSwiY1guRSI6
-Ik9kIn0sIlNkIjp7IkFuIjpbIk9kIl19LCJFVCI6eyJlcSI6W119LCJMWiI6eyJYaiI6WyJAIl0sIkVU
-IjpbXSwiZXEiOltdfSwiRGciOnsibEQiOlsiQ1AiXSwiWGoiOlsiQCJdLCJ6TSI6WyJDUCJdLCJFVCI6
-W10sImJRIjpbIkNQIl0sIlNVIjpbIkNQIl0sImVxIjpbXSwiY1giOlsiQ1AiXSwibEQuRSI6IkNQIn0s
-IlBnIjp7ImxEIjpbIktOIl0sInpNIjpbIktOIl0sIlhqIjpbIkAiXSwiRVQiOltdLCJiUSI6WyJLTiJd
-LCJTVSI6WyJLTiJdLCJlcSI6W10sImNYIjpbIktOIl19LCJ4aiI6eyJsRCI6WyJLTiJdLCJ6TSI6WyJL
-TiJdLCJYaiI6WyJAIl0sIkVUIjpbXSwiYlEiOlsiS04iXSwiU1UiOlsiS04iXSwiZXEiOltdLCJjWCI6
-WyJLTiJdLCJsRC5FIjoiS04ifSwiZEUiOnsibEQiOlsiS04iXSwiek0iOlsiS04iXSwiWGoiOlsiQCJd
-LCJFVCI6W10sImJRIjpbIktOIl0sIlNVIjpbIktOIl0sImVxIjpbXSwiY1giOlsiS04iXSwibEQuRSI6
-IktOIn0sIlpBIjp7ImxEIjpbIktOIl0sInpNIjpbIktOIl0sIlhqIjpbIkAiXSwiRVQiOltdLCJiUSI6
-WyJLTiJdLCJTVSI6WyJLTiJdLCJlcSI6W10sImNYIjpbIktOIl0sImxELkUiOiJLTiJ9LCJ3ZiI6eyJs
-RCI6WyJLTiJdLCJ6TSI6WyJLTiJdLCJYaiI6WyJAIl0sIkVUIjpbXSwiYlEiOlsiS04iXSwiU1UiOlsi
-S04iXSwiZXEiOltdLCJjWCI6WyJLTiJdLCJsRC5FIjoiS04ifSwiUHEiOnsibEQiOlsiS04iXSwiek0i
-OlsiS04iXSwiWGoiOlsiQCJdLCJFVCI6W10sImJRIjpbIktOIl0sIlNVIjpbIktOIl0sImVxIjpbXSwi
-Y1giOlsiS04iXSwibEQuRSI6IktOIn0sImVFIjp7ImxEIjpbIktOIl0sInpNIjpbIktOIl0sIlhqIjpb
-IkAiXSwiRVQiOltdLCJiUSI6WyJLTiJdLCJTVSI6WyJLTiJdLCJlcSI6W10sImNYIjpbIktOIl0sImxE
-LkUiOiJLTiJ9LCJWNiI6eyJuNiI6W10sImxEIjpbIktOIl0sInpNIjpbIktOIl0sIlhqIjpbIkAiXSwi
-RVQiOltdLCJiUSI6WyJLTiJdLCJTVSI6WyJLTiJdLCJlcSI6W10sImNYIjpbIktOIl0sImxELkUiOiJL
-TiJ9LCJ1OSI6eyJYUyI6W119LCJoeiI6eyJYUyI6W119LCJpTSI6eyJYUyI6W119LCJHViI6eyJBbiI6
-WyIxIl19LCJxNCI6eyJjWCI6WyIxIl0sImNYLkUiOiIxIn0sIlpmIjp7IlBmIjpbIjEiXX0sInZzIjp7
-ImI4IjpbIjEiXX0sIkN3Ijp7IlhTIjpbXX0sIm0wIjp7IkpCIjpbXX0sIkppIjp7IkpCIjpbXX0sImI2
-Ijp7Ilh2IjpbIjEiXSwieHUiOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sImxtIjp7IkFuIjpb
-IjEiXX0sIm1XIjp7ImNYIjpbIjEiXX0sInV5Ijp7ImxEIjpbIjEiXSwiek0iOlsiMSJdLCJiUSI6WyIx
-Il0sImNYIjpbIjEiXX0sImlsIjp7IllrIjpbIjEiLCIyIl0sIlowIjpbIjEiLCIyIl19LCJZayI6eyJa
-MCI6WyIxIiwiMiJdfSwiUG4iOnsiWjAiOlsiMSIsIjIiXX0sIkdqIjp7IlJVIjpbIjEiLCIyIl0sIlBu
-IjpbIjEiLCIyIl0sIktQIjpbIjEiLCIyIl0sIlowIjpbIjEiLCIyIl19LCJWaiI6eyJsZiI6WyIxIl0s
-Inh1IjpbIjEiXSwiYlEiOlsiMSJdLCJjWCI6WyIxIl19LCJYdiI6eyJ4dSI6WyIxIl0sImJRIjpbIjEi
-XSwiY1giOlsiMSJdfSwidXciOnsiWWsiOlsicVUiLCJAIl0sIlowIjpbInFVIiwiQCJdLCJZay5LIjoi
-cVUiLCJZay5WIjoiQCJ9LCJpOCI6eyJhTCI6WyJxVSJdLCJiUSI6WyJxVSJdLCJjWCI6WyJxVSJdLCJh
-TC5FIjoicVUiLCJjWC5FIjoicVUifSwiQ1YiOnsiVWsiOlsiek08S04+IiwicVUiXSwiVWsuUyI6InpN
-PEtOPiJ9LCJVOCI6eyJ3SSI6WyJ6TTxLTj4iLCJxVSJdfSwiWmkiOnsiVWsiOlsicVUiLCJ6TTxLTj4i
-XX0sIlVkIjp7IlhTIjpbXX0sIks4Ijp7IlhTIjpbXX0sImJ5Ijp7IlVrIjpbImsiLCJxVSJdLCJVay5T
-IjoiayJ9LCJvaiI6eyJ3SSI6WyJrIiwicVUiXX0sIk14Ijp7IndJIjpbInFVIiwiayJdfSwidTUiOnsi
-VWsiOlsicVUiLCJ6TTxLTj4iXSwiVWsuUyI6InFVIn0sIkUzIjp7IndJIjpbInFVIiwiek08S04+Il19
-LCJHWSI6eyJ3SSI6WyJ6TTxLTj4iLCJxVSJdfSwiQ1AiOnsiRksiOltdfSwiQzYiOnsiWFMiOltdfSwi
-biI6eyJYUyI6W119LCJ1Ijp7IlhTIjpbXX0sImJKIjp7IlhTIjpbXX0sImVZIjp7IlhTIjpbXX0sIm1w
-Ijp7IlhTIjpbXX0sInViIjp7IlhTIjpbXX0sImRzIjp7IlhTIjpbXX0sImxqIjp7IlhTIjpbXX0sIlVW
-Ijp7IlhTIjpbXX0sIms1Ijp7IlhTIjpbXX0sIktZIjp7IlhTIjpbXX0sImMiOnsiWFMiOltdfSwiQ0Qi
-OnsiUnoiOltdfSwiYUUiOnsiUnoiOltdfSwiS04iOnsiRksiOltdfSwiek0iOnsiYlEiOlsiMSJdLCJj
-WCI6WyIxIl19LCJpYiI6eyJPZCI6W119LCJ4dSI6eyJiUSI6WyIxIl0sImNYIjpbIjEiXX0sInFVIjp7
-InZYIjpbXX0sIlJuIjp7IkJMIjpbXX0sIkRuIjp7ImlEIjpbXX0sIlVmIjp7ImlEIjpbXX0sInFlIjp7
-ImlEIjpbXX0sInFFIjp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJHaCI6eyJjdiI6W10sInVIIjpb
-XSwiRDAiOltdfSwiZlkiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpbXX0sIm5CIjp7ImN2IjpbXSwidUgi
-OltdLCJEMCI6W119LCJRUCI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwibngiOnsidUgiOltdLCJE
-MCI6W119LCJRRiI6eyJ1SCI6W10sIkQwIjpbXX0sIklCIjp7InRuIjpbIkZLIl19LCJ3eiI6eyJsRCI6
-WyIxIl0sInpNIjpbIjEiXSwiYlEiOlsiMSJdLCJjWCI6WyIxIl0sImxELkUiOiIxIn0sImN2Ijp7InVI
-IjpbXSwiRDAiOltdfSwiaEgiOnsiQXoiOltdfSwiaDQiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpbXX0s
-IlZiIjp7InVIIjpbXSwiRDAiOltdfSwiTzciOnsiRDAiOltdfSwid2EiOnsiRDAiOltdfSwiQWoiOnsi
-ZWEiOltdfSwiZTciOnsibEQiOlsidUgiXSwiek0iOlsidUgiXSwiYlEiOlsidUgiXSwiY1giOlsidUgi
-XSwibEQuRSI6InVIIn0sInVIIjp7IkQwIjpbXX0sIkJIIjp7IkdtIjpbInVIIl0sImxEIjpbInVIIl0s
-InpNIjpbInVIIl0sIlhqIjpbInVIIl0sImJRIjpbInVIIl0sImNYIjpbInVIIl0sImxELkUiOiJ1SCIs
-IkdtLkUiOiJ1SCJ9LCJTTiI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwiZXciOnsiZWEiOltdfSwi
-bHAiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpbXX0sIlRiIjp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119
-LCJJdiI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwiV1AiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpb
-XX0sInlZIjp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJ3NiI6eyJlYSI6W119LCJLNSI6eyJ2NiI6
-W10sIkQwIjpbXX0sIkNtIjp7IkQwIjpbXX0sIkNRIjp7InVIIjpbXSwiRDAiOltdfSwidzQiOnsidG4i
-OlsiRksiXX0sInJoIjp7IkdtIjpbInVIIl0sImxEIjpbInVIIl0sInpNIjpbInVIIl0sIlhqIjpbInVI
-Il0sImJRIjpbInVIIl0sImNYIjpbInVIIl0sImxELkUiOiJ1SCIsIkdtLkUiOiJ1SCJ9LCJjZiI6eyJZ
-ayI6WyJxVSIsInFVIl0sIlowIjpbInFVIiwicVUiXX0sImk3Ijp7IllrIjpbInFVIiwicVUiXSwiWjAi
-OlsicVUiLCJxVSJdLCJZay5LIjoicVUiLCJZay5WIjoicVUifSwiU3kiOnsiWWsiOlsicVUiLCJxVSJd
-LCJaMCI6WyJxVSIsInFVIl0sIllrLksiOiJxVSIsIllrLlYiOiJxVSJ9LCJJNCI6eyJsZiI6WyJxVSJd
-LCJ4dSI6WyJxVSJdLCJiUSI6WyJxVSJdLCJjWCI6WyJxVSJdfSwiUk8iOnsicWgiOlsiMSJdfSwiZXUi
-OnsiUk8iOlsiMSJdLCJxaCI6WyIxIl19LCJ4QyI6eyJNTyI6WyIxIl19LCJKUSI6eyJrRiI6W119LCJ2
-RCI6eyJrRiI6W119LCJtNiI6eyJrRiI6W119LCJjdCI6eyJrRiI6W119LCJPdyI6eyJrRiI6W119LCJX
-OSI6eyJBbiI6WyIxIl19LCJkVyI6eyJ2NiI6W10sIkQwIjpbXX0sIm1rIjp7InkwIjpbXX0sIktvIjp7
-Im9uIjpbXX0sIkFzIjp7ImxmIjpbInFVIl0sInh1IjpbInFVIl0sImJRIjpbInFVIl0sImNYIjpbInFV
-Il19LCJyNyI6eyJFNCI6W119LCJUeiI6eyJsRCI6WyIxIl0sInpNIjpbIjEiXSwiYlEiOlsiMSJdLCJF
-NCI6W10sImNYIjpbIjEiXSwibEQuRSI6IjEifSwibmQiOnsiZDUiOltdLCJjdiI6W10sInVIIjpbXSwi
-RDAiOltdfSwiS2UiOnsibGYiOlsicVUiXSwieHUiOlsicVUiXSwiYlEiOlsicVUiXSwiY1giOlsicVUi
-XX0sImQ1Ijp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJuNiI6eyJ6TSI6WyJLTiJdLCJiUSI6WyJL
-TiJdLCJlcSI6W10sImNYIjpbIktOIl19LCJYQSI6eyJrRiI6W119LCJkdiI6eyJSeiI6W119LCJPRiI6
-eyJmdiI6W119LCJydSI6eyJmdiI6W119LCJJViI6eyJmdiI6W119fScpKQpILkZGKHYudHlwZVVuaXZl
-cnNlLEpTT04ucGFyc2UoJ3siYlEiOjEsIlhDIjoxLCJNTyI6MSwia1QiOjIsIm1XIjoxLCJ1eSI6MSwi
-aWwiOjIsIlZqIjoxLCJuWSI6MSwiVEMiOjEsImNvIjoxfScpKQp2YXIgdT0oZnVuY3Rpb24gcnRpaSgp
-e3ZhciB0PUguTjAKcmV0dXJue2JxOnQoIkdoIiksbjp0KCJDdyIpLGNSOnQoIm5CIiksZDp0KCJBeiIp
-LFk6dCgiUVAiKSxnRjp0KCJQRDxHRCxAPiIpLGd3OnQoImJRPEA+IiksaDp0KCJjdiIpLGJVOnQoIlhT
-IiksQjp0KCJlYSIpLHI6dCgiRDAiKSxnODp0KCJSeiIpLGM4OnQoImhIIiksWjp0KCJFSCIpLGM6dCgi
-Yjg8QD4iKSxEOnQoIkxMIiksZ3A6dCgiSDciKSxJOnQoIlNnIiksbzp0KCJ2USIpLGVoOnQoImNYPHVI
-PiIpLFg6dCgiY1g8cVU+IiksUjp0KCJjWDxAPiIpLGZBOnQoImpkPFNlPiIpLGdpOnQoImpkPGo4PiIp
-LEo6dCgiamQ8WjA8cVUsaz4+IiksZmg6dCgiamQ8Wlo+IiksaTp0KCJqZDxrRj4iKSxzOnQoImpkPHFV
-PiIpLGhoOnQoImpkPHlEPiIpLGFKOnQoImpkPHdiPiIpLGI6dCgiamQ8QD4iKSx0OnQoImpkPEtOPiIp
-LGVIOnQoInZtIiksZzp0KCJjNSIpLGFVOnQoIlhqPEA+IiksYW06dCgiVHo8QD4iKSxlbzp0KCJONTxH
-RCxAPiIpLG06dCgiRTQiKSxkejp0KCJoRiIpLGY0OnQoInpNPGo4PiIpLGQzOnQoInpNPFowPHFVLGs+
-PiIpLGV3OnQoInpNPGs+IiksYTp0KCJ6TTxxVT4iKSxqOnQoInpNPEA+IiksTDp0KCJ6TTxLTj4iKSxh
-Xzp0KCJ1OCIpLFM6dCgiWjA8cVUsaz4iKSxmOnQoIlowPHFVLHFVPiIpLGs6dCgiWjA8cVUsQD4iKSxH
-OnQoIlowPEAsQD4iKSxkdjp0KCJBODxxVSxxVT4iKSxkbzp0KCJBODxxVSxAPiIpLFY6dCgiQWoiKSxk
-RDp0KCJFVCIpLGJtOnQoIlY2IiksQTp0KCJ1SCIpLGU6dCgia0YiKSxQOnQoImM4IiksSzp0KCJrIiks
-cDp0KCJldyIpLHE6dCgidG48Rks+IiksZnY6dCgid0wiKSxhdjp0KCJKYyIpLGFPOnQoIm5kIiksQzp0
-KCJ4dTxxVT4iKSxsOnQoIkd6IiksTjp0KCJxVSIpLGRHOnQoInFVKHFVKSIpLGc3OnQoImQ1IiksZm86
-dCgiR0QiKSxhVzp0KCJ5WSIpLHU6dCgiZXEiKSxnYzp0KCJuNiIpLGFrOnQoImtkIiksVzp0KCJHajxx
-VSxxVT4iKSx2OnQoImlEIiksY2M6dCgiVTU8cVU+IiksZzQ6dCgiSzUiKSxjaTp0KCJ2NiIpLGcyOnQo
-IkNtIiksYmo6dCgiWmY8Tzc+IiksaDk6dCgiQ1EiKSxhYzp0KCJlNyIpLFE6dCgiZXU8QWo+IiksVDp0
-KCJ3ejxjdj4iKSx4OnQoIkZlPEAsQD4iKSxhbzp0KCJ2czxPNz4iKSxfOnQoInZzPEA+IiksZko6dCgi
-dnM8S04+IiksTzp0KCJKUSIpLHk6dCgiYm4iKSxjSjp0KCJhMiIpLGFsOnQoImEyKGspIiksYkI6dCgi
-YTIocVUpIiksYmY6dCgiYTIoQCkiKSx6OnQoIkAiKSxmTzp0KCJAKCkiKSxVOnQoIkAoZWEpIiksdzp0
-KCJAKGspIiksZXA6dCgiQChrLGspIiksRTp0KCJAKGssR3opIiksY2g6dCgiQCh4dTxxVT4pIiksZE86
-dCgiQChxVSkiKSxiYzp0KCJAKEApIiksYjg6dCgiQChALEApIiksZWc6dCgiS04iKSxIOnQoIn4iKSxN
-OnQoIn4oKSIpLGFuOnQoIn4oZXcpIiksRjp0KCJ+KHFVLHFVKSIpLGNBOnQoIn4ocVUsQCkiKX19KSgp
-OyhmdW5jdGlvbiBjb25zdGFudHMoKXt2YXIgdD1odW5rSGVscGVycy5tYWtlQ29uc3RMaXN0CkMuUlk9
-Vy5RUC5wcm90b3R5cGUKQy5CWj1XLlZiLnByb3RvdHlwZQpDLkR0PVcuTzcucHJvdG90eXBlCkMuT2s9
-Si52Qi5wcm90b3R5cGUKQy5ObT1KLmpkLnByb3RvdHlwZQpDLmpuPUouYlUucHJvdG90eXBlCkMuQ0Q9
-Si5xSS5wcm90b3R5cGUKQy54Qj1KLkRyLnByb3RvdHlwZQpDLkRHPUouYzUucHJvdG90eXBlCkMuRXg9
-Vy51OC5wcm90b3R5cGUKQy50NT1XLkJILnByb3RvdHlwZQpDLkx0PVcuU04ucHJvdG90eXBlCkMuWlE9
-Si5pQy5wcm90b3R5cGUKQy5JZT1XLlRiLnByb3RvdHlwZQpDLnZCPUoua2QucHJvdG90eXBlCkMub2w9
-Vy5LNS5wcm90b3R5cGUKQy55OD1uZXcgUC5VOCgpCkMuaDk9bmV3IFAuQ1YoKQpDLk80PWZ1bmN0aW9u
-IGdldFRhZ0ZhbGxiYWNrKG8pIHsKICB2YXIgcyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2Fs
-bChvKTsKICByZXR1cm4gcy5zdWJzdHJpbmcoOCwgcy5sZW5ndGggLSAxKTsKfQpDLllxPWZ1bmN0aW9u
-KCkgewogIHZhciB0b1N0cmluZ0Z1bmN0aW9uID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZzsKICBm
-dW5jdGlvbiBnZXRUYWcobykgewogICAgdmFyIHMgPSB0b1N0cmluZ0Z1bmN0aW9uLmNhbGwobyk7CiAg
-ICByZXR1cm4gcy5zdWJzdHJpbmcoOCwgcy5sZW5ndGggLSAxKTsKICB9CiAgZnVuY3Rpb24gZ2V0VW5r
-bm93blRhZyhvYmplY3QsIHRhZykgewogICAgaWYgKC9eSFRNTFtBLVpdLipFbGVtZW50JC8udGVzdCh0
-YWcpKSB7CiAgICAgIHZhciBuYW1lID0gdG9TdHJpbmdGdW5jdGlvbi5jYWxsKG9iamVjdCk7CiAgICAg
-IGlmIChuYW1lID09ICJbb2JqZWN0IE9iamVjdF0iKSByZXR1cm4gbnVsbDsKICAgICAgcmV0dXJuICJI
-VE1MRWxlbWVudCI7CiAgICB9CiAgfQogIGZ1bmN0aW9uIGdldFVua25vd25UYWdHZW5lcmljQnJvd3Nl
-cihvYmplY3QsIHRhZykgewogICAgaWYgKHNlbGYuSFRNTEVsZW1lbnQgJiYgb2JqZWN0IGluc3RhbmNl
-b2YgSFRNTEVsZW1lbnQpIHJldHVybiAiSFRNTEVsZW1lbnQiOwogICAgcmV0dXJuIGdldFVua25vd25U
-YWcob2JqZWN0LCB0YWcpOwogIH0KICBmdW5jdGlvbiBwcm90b3R5cGVGb3JUYWcodGFnKSB7CiAgICBp
-ZiAodHlwZW9mIHdpbmRvdyA9PSAidW5kZWZpbmVkIikgcmV0dXJuIG51bGw7CiAgICBpZiAodHlwZW9m
-IHdpbmRvd1t0YWddID09ICJ1bmRlZmluZWQiKSByZXR1cm4gbnVsbDsKICAgIHZhciBjb25zdHJ1Y3Rv
-ciA9IHdpbmRvd1t0YWddOwogICAgaWYgKHR5cGVvZiBjb25zdHJ1Y3RvciAhPSAiZnVuY3Rpb24iKSBy
-ZXR1cm4gbnVsbDsKICAgIHJldHVybiBjb25zdHJ1Y3Rvci5wcm90b3R5cGU7CiAgfQogIGZ1bmN0aW9u
-IGRpc2NyaW1pbmF0b3IodGFnKSB7IHJldHVybiBudWxsOyB9CiAgdmFyIGlzQnJvd3NlciA9IHR5cGVv
-ZiBuYXZpZ2F0b3IgPT0gIm9iamVjdCI7CiAgcmV0dXJuIHsKICAgIGdldFRhZzogZ2V0VGFnLAogICAg
-Z2V0VW5rbm93blRhZzogaXNCcm93c2VyID8gZ2V0VW5rbm93blRhZ0dlbmVyaWNCcm93c2VyIDogZ2V0
-VW5rbm93blRhZywKICAgIHByb3RvdHlwZUZvclRhZzogcHJvdG90eXBlRm9yVGFnLAogICAgZGlzY3Jp
-bWluYXRvcjogZGlzY3JpbWluYXRvciB9Owp9CkMud2I9ZnVuY3Rpb24oZ2V0VGFnRmFsbGJhY2spIHsK
-ICByZXR1cm4gZnVuY3Rpb24oaG9va3MpIHsKICAgIGlmICh0eXBlb2YgbmF2aWdhdG9yICE9ICJvYmpl
-Y3QiKSByZXR1cm4gaG9va3M7CiAgICB2YXIgdWEgPSBuYXZpZ2F0b3IudXNlckFnZW50OwogICAgaWYg
-KHVhLmluZGV4T2YoIkR1bXBSZW5kZXJUcmVlIikgPj0gMCkgcmV0dXJuIGhvb2tzOwogICAgaWYgKHVh
-LmluZGV4T2YoIkNocm9tZSIpID49IDApIHsKICAgICAgZnVuY3Rpb24gY29uZmlybShwKSB7CiAgICAg
-ICAgcmV0dXJuIHR5cGVvZiB3aW5kb3cgPT0gIm9iamVjdCIgJiYgd2luZG93W3BdICYmIHdpbmRvd1tw
-XS5uYW1lID09IHA7CiAgICAgIH0KICAgICAgaWYgKGNvbmZpcm0oIldpbmRvdyIpICYmIGNvbmZpcm0o
-IkhUTUxFbGVtZW50IikpIHJldHVybiBob29rczsKICAgIH0KICAgIGhvb2tzLmdldFRhZyA9IGdldFRh
-Z0ZhbGxiYWNrOwogIH07Cn0KQy5LVT1mdW5jdGlvbihob29rcykgewogIGlmICh0eXBlb2YgZGFydEV4
-cGVyaW1lbnRhbEZpeHVwR2V0VGFnICE9ICJmdW5jdGlvbiIpIHJldHVybiBob29rczsKICBob29rcy5n
-ZXRUYWcgPSBkYXJ0RXhwZXJpbWVudGFsRml4dXBHZXRUYWcoaG9va3MuZ2V0VGFnKTsKfQpDLmZRPWZ1
-bmN0aW9uKGhvb2tzKSB7CiAgdmFyIGdldFRhZyA9IGhvb2tzLmdldFRhZzsKICB2YXIgcHJvdG90eXBl
-Rm9yVGFnID0gaG9va3MucHJvdG90eXBlRm9yVGFnOwogIGZ1bmN0aW9uIGdldFRhZ0ZpeGVkKG8pIHsK
-ICAgIHZhciB0YWcgPSBnZXRUYWcobyk7CiAgICBpZiAodGFnID09ICJEb2N1bWVudCIpIHsKICAgICAg
-aWYgKCEhby54bWxWZXJzaW9uKSByZXR1cm4gIiFEb2N1bWVudCI7CiAgICAgIHJldHVybiAiIUhUTUxE
-b2N1bWVudCI7CiAgICB9CiAgICByZXR1cm4gdGFnOwogIH0KICBmdW5jdGlvbiBwcm90b3R5cGVGb3JU
-YWdGaXhlZCh0YWcpIHsKICAgIGlmICh0YWcgPT0gIkRvY3VtZW50IikgcmV0dXJuIG51bGw7CiAgICBy
-ZXR1cm4gcHJvdG90eXBlRm9yVGFnKHRhZyk7CiAgfQogIGhvb2tzLmdldFRhZyA9IGdldFRhZ0ZpeGVk
-OwogIGhvb2tzLnByb3RvdHlwZUZvclRhZyA9IHByb3RvdHlwZUZvclRhZ0ZpeGVkOwp9CkMuZGs9ZnVu
-Y3Rpb24oaG9va3MpIHsKICB2YXIgdXNlckFnZW50ID0gdHlwZW9mIG5hdmlnYXRvciA9PSAib2JqZWN0
-IiA/IG5hdmlnYXRvci51c2VyQWdlbnQgOiAiIjsKICBpZiAodXNlckFnZW50LmluZGV4T2YoIkZpcmVm
-b3giKSA9PSAtMSkgcmV0dXJuIGhvb2tzOwogIHZhciBnZXRUYWcgPSBob29rcy5nZXRUYWc7CiAgdmFy
-IHF1aWNrTWFwID0gewogICAgIkJlZm9yZVVubG9hZEV2ZW50IjogIkV2ZW50IiwKICAgICJEYXRhVHJh
-bnNmZXIiOiAiQ2xpcGJvYXJkIiwKICAgICJHZW9HZW9sb2NhdGlvbiI6ICJHZW9sb2NhdGlvbiIsCiAg
-ICAiTG9jYXRpb24iOiAiIUxvY2F0aW9uIiwKICAgICJXb3JrZXJNZXNzYWdlRXZlbnQiOiAiTWVzc2Fn
-ZUV2ZW50IiwKICAgICJYTUxEb2N1bWVudCI6ICIhRG9jdW1lbnQifTsKICBmdW5jdGlvbiBnZXRUYWdG
-aXJlZm94KG8pIHsKICAgIHZhciB0YWcgPSBnZXRUYWcobyk7CiAgICByZXR1cm4gcXVpY2tNYXBbdGFn
-XSB8fCB0YWc7CiAgfQogIGhvb2tzLmdldFRhZyA9IGdldFRhZ0ZpcmVmb3g7Cn0KQy54aT1mdW5jdGlv
-bihob29rcykgewogIHZhciB1c2VyQWdlbnQgPSB0eXBlb2YgbmF2aWdhdG9yID09ICJvYmplY3QiID8g
-bmF2aWdhdG9yLnVzZXJBZ2VudCA6ICIiOwogIGlmICh1c2VyQWdlbnQuaW5kZXhPZigiVHJpZGVudC8i
-KSA9PSAtMSkgcmV0dXJuIGhvb2tzOwogIHZhciBnZXRUYWcgPSBob29rcy5nZXRUYWc7CiAgdmFyIHF1
-aWNrTWFwID0gewogICAgIkJlZm9yZVVubG9hZEV2ZW50IjogIkV2ZW50IiwKICAgICJEYXRhVHJhbnNm
-ZXIiOiAiQ2xpcGJvYXJkIiwKICAgICJIVE1MRERFbGVtZW50IjogIkhUTUxFbGVtZW50IiwKICAgICJI
-VE1MRFRFbGVtZW50IjogIkhUTUxFbGVtZW50IiwKICAgICJIVE1MUGhyYXNlRWxlbWVudCI6ICJIVE1M
-RWxlbWVudCIsCiAgICAiUG9zaXRpb24iOiAiR2VvcG9zaXRpb24iCiAgfTsKICBmdW5jdGlvbiBnZXRU
-YWdJRShvKSB7CiAgICB2YXIgdGFnID0gZ2V0VGFnKG8pOwogICAgdmFyIG5ld1RhZyA9IHF1aWNrTWFw
-W3RhZ107CiAgICBpZiAobmV3VGFnKSByZXR1cm4gbmV3VGFnOwogICAgaWYgKHRhZyA9PSAiT2JqZWN0
-IikgewogICAgICBpZiAod2luZG93LkRhdGFWaWV3ICYmIChvIGluc3RhbmNlb2Ygd2luZG93LkRhdGFW
-aWV3KSkgcmV0dXJuICJEYXRhVmlldyI7CiAgICB9CiAgICByZXR1cm4gdGFnOwogIH0KICBmdW5jdGlv
-biBwcm90b3R5cGVGb3JUYWdJRSh0YWcpIHsKICAgIHZhciBjb25zdHJ1Y3RvciA9IHdpbmRvd1t0YWdd
-OwogICAgaWYgKGNvbnN0cnVjdG9yID09IG51bGwpIHJldHVybiBudWxsOwogICAgcmV0dXJuIGNvbnN0
-cnVjdG9yLnByb3RvdHlwZTsKICB9CiAgaG9va3MuZ2V0VGFnID0gZ2V0VGFnSUU7CiAgaG9va3MucHJv
-dG90eXBlRm9yVGFnID0gcHJvdG90eXBlRm9yVGFnSUU7Cn0KQy5pNz1mdW5jdGlvbihob29rcykgeyBy
-ZXR1cm4gaG9va3M7IH0KCkMuQ3Q9bmV3IFAuYnkoKQpDLkVxPW5ldyBQLms1KCkKQy54TT1uZXcgUC51
-NSgpCkMuUWs9bmV3IFAuRTMoKQpDLk5VPW5ldyBQLkppKCkKQy5BZD1uZXcgTS5INygwLCJIaW50QWN0
-aW9uS2luZC5hZGROdWxsYWJsZUhpbnQiKQpDLm5lPW5ldyBNLkg3KDEsIkhpbnRBY3Rpb25LaW5kLmFk
-ZE5vbk51bGxhYmxlSGludCIpCkMubXk9bmV3IE0uSDcoMiwiSGludEFjdGlvbktpbmQuY2hhbmdlVG9O
-dWxsYWJsZUhpbnQiKQpDLnJ4PW5ldyBNLkg3KDMsIkhpbnRBY3Rpb25LaW5kLmNoYW5nZVRvTm9uTnVs
-bGFibGVIaW50IikKQy53Vj1uZXcgTS5INyg0LCJIaW50QWN0aW9uS2luZC5yZW1vdmVOdWxsYWJsZUhp
-bnQiKQpDLmZSPW5ldyBNLkg3KDUsIkhpbnRBY3Rpb25LaW5kLnJlbW92ZU5vbk51bGxhYmxlSGludCIp
-CkMuQTM9bmV3IFAuTXgobnVsbCkKQy5uWD1uZXcgUC5vaihudWxsKQpDLkdiPUguVk0odChbMTI3LDIw
-NDcsNjU1MzUsMTExNDExMV0pLHUudCkKQy5haz1ILlZNKHQoWzAsMCwzMjc3NiwzMzc5MiwxLDEwMjQw
-LDAsMF0pLHUudCkKQy5jbT1ILlZNKHQoWyIqOjpjbGFzcyIsIio6OmRpciIsIio6OmRyYWdnYWJsZSIs
-Iio6OmhpZGRlbiIsIio6OmlkIiwiKjo6aW5lcnQiLCIqOjppdGVtcHJvcCIsIio6Oml0ZW1yZWYiLCIq
-OjppdGVtc2NvcGUiLCIqOjpsYW5nIiwiKjo6c3BlbGxjaGVjayIsIio6OnRpdGxlIiwiKjo6dHJhbnNs
-YXRlIiwiQTo6YWNjZXNza2V5IiwiQTo6Y29vcmRzIiwiQTo6aHJlZmxhbmciLCJBOjpuYW1lIiwiQTo6
-c2hhcGUiLCJBOjp0YWJpbmRleCIsIkE6OnRhcmdldCIsIkE6OnR5cGUiLCJBUkVBOjphY2Nlc3NrZXki
-LCJBUkVBOjphbHQiLCJBUkVBOjpjb29yZHMiLCJBUkVBOjpub2hyZWYiLCJBUkVBOjpzaGFwZSIsIkFS
-RUE6OnRhYmluZGV4IiwiQVJFQTo6dGFyZ2V0IiwiQVVESU86OmNvbnRyb2xzIiwiQVVESU86Omxvb3Ai
-LCJBVURJTzo6bWVkaWFncm91cCIsIkFVRElPOjptdXRlZCIsIkFVRElPOjpwcmVsb2FkIiwiQkRPOjpk
-aXIiLCJCT0RZOjphbGluayIsIkJPRFk6OmJnY29sb3IiLCJCT0RZOjpsaW5rIiwiQk9EWTo6dGV4dCIs
-IkJPRFk6OnZsaW5rIiwiQlI6OmNsZWFyIiwiQlVUVE9OOjphY2Nlc3NrZXkiLCJCVVRUT046OmRpc2Fi
-bGVkIiwiQlVUVE9OOjpuYW1lIiwiQlVUVE9OOjp0YWJpbmRleCIsIkJVVFRPTjo6dHlwZSIsIkJVVFRP
-Tjo6dmFsdWUiLCJDQU5WQVM6OmhlaWdodCIsIkNBTlZBUzo6d2lkdGgiLCJDQVBUSU9OOjphbGlnbiIs
-IkNPTDo6YWxpZ24iLCJDT0w6OmNoYXIiLCJDT0w6OmNoYXJvZmYiLCJDT0w6OnNwYW4iLCJDT0w6OnZh
-bGlnbiIsIkNPTDo6d2lkdGgiLCJDT0xHUk9VUDo6YWxpZ24iLCJDT0xHUk9VUDo6Y2hhciIsIkNPTEdS
-T1VQOjpjaGFyb2ZmIiwiQ09MR1JPVVA6OnNwYW4iLCJDT0xHUk9VUDo6dmFsaWduIiwiQ09MR1JPVVA6
-OndpZHRoIiwiQ09NTUFORDo6Y2hlY2tlZCIsIkNPTU1BTkQ6OmNvbW1hbmQiLCJDT01NQU5EOjpkaXNh
-YmxlZCIsIkNPTU1BTkQ6OmxhYmVsIiwiQ09NTUFORDo6cmFkaW9ncm91cCIsIkNPTU1BTkQ6OnR5cGUi
-LCJEQVRBOjp2YWx1ZSIsIkRFTDo6ZGF0ZXRpbWUiLCJERVRBSUxTOjpvcGVuIiwiRElSOjpjb21wYWN0
-IiwiRElWOjphbGlnbiIsIkRMOjpjb21wYWN0IiwiRklFTERTRVQ6OmRpc2FibGVkIiwiRk9OVDo6Y29s
-b3IiLCJGT05UOjpmYWNlIiwiRk9OVDo6c2l6ZSIsIkZPUk06OmFjY2VwdCIsIkZPUk06OmF1dG9jb21w
-bGV0ZSIsIkZPUk06OmVuY3R5cGUiLCJGT1JNOjptZXRob2QiLCJGT1JNOjpuYW1lIiwiRk9STTo6bm92
-YWxpZGF0ZSIsIkZPUk06OnRhcmdldCIsIkZSQU1FOjpuYW1lIiwiSDE6OmFsaWduIiwiSDI6OmFsaWdu
-IiwiSDM6OmFsaWduIiwiSDQ6OmFsaWduIiwiSDU6OmFsaWduIiwiSDY6OmFsaWduIiwiSFI6OmFsaWdu
-IiwiSFI6Om5vc2hhZGUiLCJIUjo6c2l6ZSIsIkhSOjp3aWR0aCIsIkhUTUw6OnZlcnNpb24iLCJJRlJB
-TUU6OmFsaWduIiwiSUZSQU1FOjpmcmFtZWJvcmRlciIsIklGUkFNRTo6aGVpZ2h0IiwiSUZSQU1FOjpt
-YXJnaW5oZWlnaHQiLCJJRlJBTUU6Om1hcmdpbndpZHRoIiwiSUZSQU1FOjp3aWR0aCIsIklNRzo6YWxp
-Z24iLCJJTUc6OmFsdCIsIklNRzo6Ym9yZGVyIiwiSU1HOjpoZWlnaHQiLCJJTUc6OmhzcGFjZSIsIklN
-Rzo6aXNtYXAiLCJJTUc6Om5hbWUiLCJJTUc6OnVzZW1hcCIsIklNRzo6dnNwYWNlIiwiSU1HOjp3aWR0
-aCIsIklOUFVUOjphY2NlcHQiLCJJTlBVVDo6YWNjZXNza2V5IiwiSU5QVVQ6OmFsaWduIiwiSU5QVVQ6
-OmFsdCIsIklOUFVUOjphdXRvY29tcGxldGUiLCJJTlBVVDo6YXV0b2ZvY3VzIiwiSU5QVVQ6OmNoZWNr
-ZWQiLCJJTlBVVDo6ZGlzYWJsZWQiLCJJTlBVVDo6aW5wdXRtb2RlIiwiSU5QVVQ6OmlzbWFwIiwiSU5Q
-VVQ6Omxpc3QiLCJJTlBVVDo6bWF4IiwiSU5QVVQ6Om1heGxlbmd0aCIsIklOUFVUOjptaW4iLCJJTlBV
-VDo6bXVsdGlwbGUiLCJJTlBVVDo6bmFtZSIsIklOUFVUOjpwbGFjZWhvbGRlciIsIklOUFVUOjpyZWFk
-b25seSIsIklOUFVUOjpyZXF1aXJlZCIsIklOUFVUOjpzaXplIiwiSU5QVVQ6OnN0ZXAiLCJJTlBVVDo6
-dGFiaW5kZXgiLCJJTlBVVDo6dHlwZSIsIklOUFVUOjp1c2VtYXAiLCJJTlBVVDo6dmFsdWUiLCJJTlM6
-OmRhdGV0aW1lIiwiS0VZR0VOOjpkaXNhYmxlZCIsIktFWUdFTjo6a2V5dHlwZSIsIktFWUdFTjo6bmFt
-ZSIsIkxBQkVMOjphY2Nlc3NrZXkiLCJMQUJFTDo6Zm9yIiwiTEVHRU5EOjphY2Nlc3NrZXkiLCJMRUdF
-TkQ6OmFsaWduIiwiTEk6OnR5cGUiLCJMSTo6dmFsdWUiLCJMSU5LOjpzaXplcyIsIk1BUDo6bmFtZSIs
-Ik1FTlU6OmNvbXBhY3QiLCJNRU5VOjpsYWJlbCIsIk1FTlU6OnR5cGUiLCJNRVRFUjo6aGlnaCIsIk1F
-VEVSOjpsb3ciLCJNRVRFUjo6bWF4IiwiTUVURVI6Om1pbiIsIk1FVEVSOjp2YWx1ZSIsIk9CSkVDVDo6
-dHlwZW11c3RtYXRjaCIsIk9MOjpjb21wYWN0IiwiT0w6OnJldmVyc2VkIiwiT0w6OnN0YXJ0IiwiT0w6
-OnR5cGUiLCJPUFRHUk9VUDo6ZGlzYWJsZWQiLCJPUFRHUk9VUDo6bGFiZWwiLCJPUFRJT046OmRpc2Fi
-bGVkIiwiT1BUSU9OOjpsYWJlbCIsIk9QVElPTjo6c2VsZWN0ZWQiLCJPUFRJT046OnZhbHVlIiwiT1VU
-UFVUOjpmb3IiLCJPVVRQVVQ6Om5hbWUiLCJQOjphbGlnbiIsIlBSRTo6d2lkdGgiLCJQUk9HUkVTUzo6
-bWF4IiwiUFJPR1JFU1M6Om1pbiIsIlBST0dSRVNTOjp2YWx1ZSIsIlNFTEVDVDo6YXV0b2NvbXBsZXRl
-IiwiU0VMRUNUOjpkaXNhYmxlZCIsIlNFTEVDVDo6bXVsdGlwbGUiLCJTRUxFQ1Q6Om5hbWUiLCJTRUxF
-Q1Q6OnJlcXVpcmVkIiwiU0VMRUNUOjpzaXplIiwiU0VMRUNUOjp0YWJpbmRleCIsIlNPVVJDRTo6dHlw
-ZSIsIlRBQkxFOjphbGlnbiIsIlRBQkxFOjpiZ2NvbG9yIiwiVEFCTEU6OmJvcmRlciIsIlRBQkxFOjpj
-ZWxscGFkZGluZyIsIlRBQkxFOjpjZWxsc3BhY2luZyIsIlRBQkxFOjpmcmFtZSIsIlRBQkxFOjpydWxl
-cyIsIlRBQkxFOjpzdW1tYXJ5IiwiVEFCTEU6OndpZHRoIiwiVEJPRFk6OmFsaWduIiwiVEJPRFk6OmNo
-YXIiLCJUQk9EWTo6Y2hhcm9mZiIsIlRCT0RZOjp2YWxpZ24iLCJURDo6YWJiciIsIlREOjphbGlnbiIs
-IlREOjpheGlzIiwiVEQ6OmJnY29sb3IiLCJURDo6Y2hhciIsIlREOjpjaGFyb2ZmIiwiVEQ6OmNvbHNw
-YW4iLCJURDo6aGVhZGVycyIsIlREOjpoZWlnaHQiLCJURDo6bm93cmFwIiwiVEQ6OnJvd3NwYW4iLCJU
-RDo6c2NvcGUiLCJURDo6dmFsaWduIiwiVEQ6OndpZHRoIiwiVEVYVEFSRUE6OmFjY2Vzc2tleSIsIlRF
-WFRBUkVBOjphdXRvY29tcGxldGUiLCJURVhUQVJFQTo6Y29scyIsIlRFWFRBUkVBOjpkaXNhYmxlZCIs
-IlRFWFRBUkVBOjppbnB1dG1vZGUiLCJURVhUQVJFQTo6bmFtZSIsIlRFWFRBUkVBOjpwbGFjZWhvbGRl
-ciIsIlRFWFRBUkVBOjpyZWFkb25seSIsIlRFWFRBUkVBOjpyZXF1aXJlZCIsIlRFWFRBUkVBOjpyb3dz
-IiwiVEVYVEFSRUE6OnRhYmluZGV4IiwiVEVYVEFSRUE6OndyYXAiLCJURk9PVDo6YWxpZ24iLCJURk9P
-VDo6Y2hhciIsIlRGT09UOjpjaGFyb2ZmIiwiVEZPT1Q6OnZhbGlnbiIsIlRIOjphYmJyIiwiVEg6OmFs
-aWduIiwiVEg6OmF4aXMiLCJUSDo6Ymdjb2xvciIsIlRIOjpjaGFyIiwiVEg6OmNoYXJvZmYiLCJUSDo6
-Y29sc3BhbiIsIlRIOjpoZWFkZXJzIiwiVEg6OmhlaWdodCIsIlRIOjpub3dyYXAiLCJUSDo6cm93c3Bh
-biIsIlRIOjpzY29wZSIsIlRIOjp2YWxpZ24iLCJUSDo6d2lkdGgiLCJUSEVBRDo6YWxpZ24iLCJUSEVB
-RDo6Y2hhciIsIlRIRUFEOjpjaGFyb2ZmIiwiVEhFQUQ6OnZhbGlnbiIsIlRSOjphbGlnbiIsIlRSOjpi
-Z2NvbG9yIiwiVFI6OmNoYXIiLCJUUjo6Y2hhcm9mZiIsIlRSOjp2YWxpZ24iLCJUUkFDSzo6ZGVmYXVs
-dCIsIlRSQUNLOjpraW5kIiwiVFJBQ0s6OmxhYmVsIiwiVFJBQ0s6OnNyY2xhbmciLCJVTDo6Y29tcGFj
-dCIsIlVMOjp0eXBlIiwiVklERU86OmNvbnRyb2xzIiwiVklERU86OmhlaWdodCIsIlZJREVPOjpsb29w
-IiwiVklERU86Om1lZGlhZ3JvdXAiLCJWSURFTzo6bXV0ZWQiLCJWSURFTzo6cHJlbG9hZCIsIlZJREVP
-Ojp3aWR0aCJdKSx1LnMpCkMuVkM9SC5WTSh0KFswLDAsNjU0OTAsNDUwNTUsNjU1MzUsMzQ4MTUsNjU1
-MzQsMTg0MzFdKSx1LnQpCkMubUs9SC5WTSh0KFswLDAsMjY2MjQsMTAyMyw2NTUzNCwyMDQ3LDY1NTM0
-LDIwNDddKSx1LnQpCkMuU3E9SC5WTSh0KFsiSEVBRCIsIkFSRUEiLCJCQVNFIiwiQkFTRUZPTlQiLCJC
-UiIsIkNPTCIsIkNPTEdST1VQIiwiRU1CRUQiLCJGUkFNRSIsIkZSQU1FU0VUIiwiSFIiLCJJTUFHRSIs
-IklNRyIsIklOUFVUIiwiSVNJTkRFWCIsIkxJTksiLCJNRVRBIiwiUEFSQU0iLCJTT1VSQ0UiLCJTVFlM
-RSIsIlRJVExFIiwiV0JSIl0pLHUucykKQy5kbj1ILlZNKHQoW10pLEguTjAoImpkPExMPiIpKQpDLnhE
-PUguVk0odChbXSksdS5zKQpDLmhVPUguVk0odChbXSksdS5iKQpDLnRvPUguVk0odChbMCwwLDMyNzIy
-LDEyMjg3LDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLnJrPUguVk0odChbQy5BZCxDLm5l
-LEMubXksQy5yeCxDLndWLEMuZlJdKSxILk4wKCJqZDxINz4iKSkKQy5GMz1ILlZNKHQoWzAsMCwyNDU3
-NiwxMDIzLDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLmVhPUguVk0odChbMCwwLDMyNzU0
-LDExMjYzLDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLlpKPUguVk0odChbMCwwLDMyNzIy
-LDEyMjg3LDY1NTM1LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLldkPUguVk0odChbMCwwLDY1NDkw
-LDEyMjg3LDY1NTM1LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLlF4PUguVk0odChbImJpbmQiLCJp
-ZiIsInJlZiIsInJlcGVhdCIsInN5bnRheCJdKSx1LnMpCkMuQkk9SC5WTSh0KFsiQTo6aHJlZiIsIkFS
-RUE6OmhyZWYiLCJCTE9DS1FVT1RFOjpjaXRlIiwiQk9EWTo6YmFja2dyb3VuZCIsIkNPTU1BTkQ6Omlj
-b24iLCJERUw6OmNpdGUiLCJGT1JNOjphY3Rpb24iLCJJTUc6OnNyYyIsIklOUFVUOjpzcmMiLCJJTlM6
-OmNpdGUiLCJROjpjaXRlIiwiVklERU86OnBvc3RlciJdKSx1LnMpCkMuQ009bmV3IEguTFAoMCx7fSxD
-LnhELEguTjAoIkxQPHFVLHpNPGo4Pj4iKSkKQy5XTz1uZXcgSC5MUCgwLHt9LEMueEQsSC5OMCgiTFA8
-cVUscVU+IikpCkMuaUg9SC5WTSh0KFtdKSxILk4wKCJqZDxHRD4iKSkKQy5EeD1uZXcgSC5MUCgwLHt9
-LEMuaUgsSC5OMCgiTFA8R0QsQD4iKSkKQy5ZMj1uZXcgTC5POSgiTmF2aWdhdGlvblRyZWVOb2RlVHlw
-ZS5kaXJlY3RvcnkiKQpDLnJmPW5ldyBMLk85KCJOYXZpZ2F0aW9uVHJlZU5vZGVUeXBlLmZpbGUiKQpD
-LlRlPW5ldyBILnd2KCJjYWxsIikKQy53UT1uZXcgUC5GeShudWxsLDIpfSkoKTsoZnVuY3Rpb24gc3Rh
-dGljRmllbGRzKCl7JC55aj0wCiQubUo9bnVsbAokLlA0PW51bGwKJC5ORj1udWxsCiQuVFg9bnVsbAok
-Lng3PW51bGwKJC5udz1udWxsCiQudnY9bnVsbAokLkJ2PW51bGwKJC5TNj1udWxsCiQuazg9bnVsbAok
-Lm1nPW51bGwKJC5VRD0hMQokLlgzPUMuTlUKJC54Zz1bXQokLnhvPW51bGwKJC5CTz1udWxsCiQubHQ9
-bnVsbAokLkVVPW51bGwKJC5vcj1QLkZsKHUuTix1LlopCiQuSTY9bnVsbAokLkZmPW51bGx9KSgpOyhm
-dW5jdGlvbiBsYXp5SW5pdGlhbGl6ZXJzKCl7dmFyIHQ9aHVua0hlbHBlcnMubGF6eQp0KCQsImZhIiwi
-dyIsZnVuY3Rpb24oKXtyZXR1cm4gSC5ZZygiXyRkYXJ0X2RhcnRDbG9zdXJlIil9KQp0KCQsIlkyIiwi
-VU4iLGZ1bmN0aW9uKCl7cmV0dXJuIEguWWcoIl8kZGFydF9qcyIpfSkKdCgkLCJVMiIsIlNuIixmdW5j
-dGlvbigpe3JldHVybiBILmNNKEguUzcoewp0b1N0cmluZzpmdW5jdGlvbigpe3JldHVybiIkcmVjZWl2
-ZXIkIn19KSl9KQp0KCQsInhxIiwibHEiLGZ1bmN0aW9uKCl7cmV0dXJuIEguY00oSC5TNyh7JG1ldGhv
-ZCQ6bnVsbCwKdG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1cm4iJHJlY2VpdmVyJCJ9fSkpfSkKdCgkLCJS
-MSIsIk45IixmdW5jdGlvbigpe3JldHVybiBILmNNKEguUzcobnVsbCkpfSkKdCgkLCJmTiIsImlJIixm
-dW5jdGlvbigpe3JldHVybiBILmNNKGZ1bmN0aW9uKCl7dmFyICRhcmd1bWVudHNFeHByJD0nJGFyZ3Vt
-ZW50cyQnCnRyeXtudWxsLiRtZXRob2QkKCRhcmd1bWVudHNFeHByJCl9Y2F0Y2gocyl7cmV0dXJuIHMu
-bWVzc2FnZX19KCkpfSkKdCgkLCJxaSIsIktmIixmdW5jdGlvbigpe3JldHVybiBILmNNKEguUzcodm9p
-ZCAwKSl9KQp0KCQsInJaIiwiWmgiLGZ1bmN0aW9uKCl7cmV0dXJuIEguY00oZnVuY3Rpb24oKXt2YXIg
-JGFyZ3VtZW50c0V4cHIkPSckYXJndW1lbnRzJCcKdHJ5eyh2b2lkIDApLiRtZXRob2QkKCRhcmd1bWVu
-dHNFeHByJCl9Y2F0Y2gocyl7cmV0dXJuIHMubWVzc2FnZX19KCkpfSkKdCgkLCJrcSIsInJOIixmdW5j
-dGlvbigpe3JldHVybiBILmNNKEguTWoobnVsbCkpfSkKdCgkLCJ0dCIsImMzIixmdW5jdGlvbigpe3Jl
-dHVybiBILmNNKGZ1bmN0aW9uKCl7dHJ5e251bGwuJG1ldGhvZCR9Y2F0Y2gocyl7cmV0dXJuIHMubWVz
-c2FnZX19KCkpfSkKdCgkLCJkdCIsIkhLIixmdW5jdGlvbigpe3JldHVybiBILmNNKEguTWoodm9pZCAw
-KSl9KQp0KCQsIkE3IiwicjEiLGZ1bmN0aW9uKCl7cmV0dXJuIEguY00oZnVuY3Rpb24oKXt0cnl7KHZv
-aWQgMCkuJG1ldGhvZCR9Y2F0Y2gocyl7cmV0dXJuIHMubWVzc2FnZX19KCkpfSkKdCgkLCJXYyIsInV0
-IixmdW5jdGlvbigpe3JldHVybiBQLk9qKCl9KQp0KCQsImtoIiwicmYiLGZ1bmN0aW9uKCl7cmV0dXJu
-IFAuV0koKX0pCnQoJCwiYnQiLCJWNyIsZnVuY3Rpb24oKXtyZXR1cm4gSC5EUShILlhGKEguVk0oWy0y
-LC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0y
-LC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0yLC0xLC0yLC0yLC0y
-LC0yLC0yLDYyLC0yLDYyLC0yLDYzLDUyLDUzLDU0LDU1LDU2LDU3LDU4LDU5LDYwLDYxLC0yLC0yLC0y
-LC0xLC0yLC0yLC0yLDAsMSwyLDMsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgs
-MTksMjAsMjEsMjIsMjMsMjQsMjUsLTIsLTIsLTIsLTIsNjMsLTIsMjYsMjcsMjgsMjksMzAsMzEsMzIs
-MzMsMzQsMzUsMzYsMzcsMzgsMzksNDAsNDEsNDIsNDMsNDQsNDUsNDYsNDcsNDgsNDksNTAsNTEsLTIs
-LTIsLTIsLTIsLTJdLHUudCkpKX0pCnQoJCwiTTUiLCJ3USIsZnVuY3Rpb24oKXtyZXR1cm4gdHlwZW9m
-IHByb2Nlc3MhPSJ1bmRlZmluZWQiJiZPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwocHJvY2Vz
-cyk9PSJbb2JqZWN0IHByb2Nlc3NdIiYmcHJvY2Vzcy5wbGF0Zm9ybT09IndpbjMyIn0pCnQoJCwibWYi
-LCJ6NCIsZnVuY3Rpb24oKXtyZXR1cm4gUC5udSgiXltcXC1cXC4wLTlBLVpfYS16fl0qJCIpfSkKdCgk
-LCJKRyIsInZaIixmdW5jdGlvbigpe3JldHVybiBQLnV4KCl9KQp0KCQsIlNDIiwiQU4iLGZ1bmN0aW9u
-KCl7cmV0dXJuIFAudE0oWyJBIiwiQUJCUiIsIkFDUk9OWU0iLCJBRERSRVNTIiwiQVJFQSIsIkFSVElD
-TEUiLCJBU0lERSIsIkFVRElPIiwiQiIsIkJESSIsIkJETyIsIkJJRyIsIkJMT0NLUVVPVEUiLCJCUiIs
-IkJVVFRPTiIsIkNBTlZBUyIsIkNBUFRJT04iLCJDRU5URVIiLCJDSVRFIiwiQ09ERSIsIkNPTCIsIkNP
-TEdST1VQIiwiQ09NTUFORCIsIkRBVEEiLCJEQVRBTElTVCIsIkREIiwiREVMIiwiREVUQUlMUyIsIkRG
-TiIsIkRJUiIsIkRJViIsIkRMIiwiRFQiLCJFTSIsIkZJRUxEU0VUIiwiRklHQ0FQVElPTiIsIkZJR1VS
-RSIsIkZPTlQiLCJGT09URVIiLCJGT1JNIiwiSDEiLCJIMiIsIkgzIiwiSDQiLCJINSIsIkg2IiwiSEVB
-REVSIiwiSEdST1VQIiwiSFIiLCJJIiwiSUZSQU1FIiwiSU1HIiwiSU5QVVQiLCJJTlMiLCJLQkQiLCJM
-QUJFTCIsIkxFR0VORCIsIkxJIiwiTUFQIiwiTUFSSyIsIk1FTlUiLCJNRVRFUiIsIk5BViIsIk5PQlIi
-LCJPTCIsIk9QVEdST1VQIiwiT1BUSU9OIiwiT1VUUFVUIiwiUCIsIlBSRSIsIlBST0dSRVNTIiwiUSIs
-IlMiLCJTQU1QIiwiU0VDVElPTiIsIlNFTEVDVCIsIlNNQUxMIiwiU09VUkNFIiwiU1BBTiIsIlNUUklL
-RSIsIlNUUk9ORyIsIlNVQiIsIlNVTU1BUlkiLCJTVVAiLCJUQUJMRSIsIlRCT0RZIiwiVEQiLCJURVhU
-QVJFQSIsIlRGT09UIiwiVEgiLCJUSEVBRCIsIlRJTUUiLCJUUiIsIlRSQUNLIiwiVFQiLCJVIiwiVUwi
-LCJWQVIiLCJWSURFTyIsIldCUiJdLHUuTil9KQp0KCQsIlg0IiwiaEciLGZ1bmN0aW9uKCl7cmV0dXJu
-IFAubnUoIl5cXFMrJCIpfSkKdCgkLCJ3TyIsIm93IixmdW5jdGlvbigpe3JldHVybiB1Lm0uYihQLk5E
-KHNlbGYpKX0pCnQoJCwia3QiLCJSOCIsZnVuY3Rpb24oKXtyZXR1cm4gSC5ZZygiXyRkYXJ0X2RhcnRP
-YmplY3QiKX0pCnQoJCwiZksiLCJrSSIsZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24gRGFydE9iamVj
-dChhKXt0aGlzLm89YX19KQp0KCQsInF0IiwiekIiLGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBULm1RKCl9
-KQp0KCQsIk9sIiwiVUUiLGZ1bmN0aW9uKCl7cmV0dXJuIFAuaEsoQy5vbC5nbVcoVy54MygpKS5ocmVm
-KS5naFkoKS5xKDAsImF1dGhUb2tlbiIpfSkKdCgkLCJoVCIsInlQIixmdW5jdGlvbigpe3JldHVybiBX
-LlpyKCkucXVlcnlTZWxlY3RvcigiLmVkaXQtbGlzdCAucGFuZWwtY29udGVudCIpfSkKdCgkLCJXNiIs
-ImhMIixmdW5jdGlvbigpe3JldHVybiBXLlpyKCkucXVlcnlTZWxlY3RvcigiLmVkaXQtcGFuZWwgLnBh
-bmVsLWNvbnRlbnQiKX0pCnQoJCwiVFIiLCJEVyIsZnVuY3Rpb24oKXtyZXR1cm4gVy5acigpLnF1ZXJ5
-U2VsZWN0b3IoImZvb3RlciIpfSkKdCgkLCJFWSIsImZpIixmdW5jdGlvbigpe3JldHVybiBXLlpyKCku
-cXVlcnlTZWxlY3RvcigiaGVhZGVyIil9KQp0KCQsImF2IiwiRDkiLGZ1bmN0aW9uKCl7cmV0dXJuIFcu
-WnIoKS5xdWVyeVNlbGVjdG9yKCIjdW5pdC1uYW1lIil9KQp0KCQsImZlIiwiS0ciLGZ1bmN0aW9uKCl7
-cmV0dXJuIG5ldyBMLlhBKCl9KQp0KCQsIm1NIiwiblUiLGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBNLmxJ
-KCQuSGsoKSl9KQp0KCQsInlyIiwiYkQiLGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBFLk9GKFAubnUoIi8i
-KSxQLm51KCJbXi9dJCIpLFAubnUoIl4vIikpfSkKdCgkLCJNayIsIktrIixmdW5jdGlvbigpe3JldHVy
-biBuZXcgTC5JVihQLm51KCJbL1xcXFxdIiksUC5udSgiW14vXFxcXF0kIiksUC5udSgiXihcXFxcXFxc
-XFteXFxcXF0rXFxcXFteXFxcXC9dK3xbYS16QS1aXTpbL1xcXFxdKSIpLFAubnUoIl5bL1xcXFxdKD8h
-Wy9cXFxcXSkiKSl9KQp0KCQsImFrIiwiRWIiLGZ1bmN0aW9uKCl7cmV0dXJuIG5ldyBGLnJ1KFAubnUo
-Ii8iKSxQLm51KCIoXlthLXpBLVpdWy0rLmEtekEtWlxcZF0qOi8vfFteL10pJCIpLFAubnUoIlthLXpB
-LVpdWy0rLmEtekEtWlxcZF0qOi8vW14vXSoiKSxQLm51KCJeLyIpKX0pCnQoJCwibHMiLCJIayIsZnVu
-Y3Rpb24oKXtyZXR1cm4gTy5SaCgpfSl9KSgpOyhmdW5jdGlvbiBuYXRpdmVTdXBwb3J0KCl7IWZ1bmN0
-aW9uKCl7dmFyIHQ9ZnVuY3Rpb24oYSl7dmFyIG49e30KblthXT0xCnJldHVybiBPYmplY3Qua2V5cyho
-dW5rSGVscGVycy5jb252ZXJ0VG9GYXN0T2JqZWN0KG4pKVswXX0Kdi5nZXRJc29sYXRlVGFnPWZ1bmN0
-aW9uKGEpe3JldHVybiB0KCJfX19kYXJ0XyIrYSt2Lmlzb2xhdGVUYWcpfQp2YXIgcz0iX19fZGFydF9p
-c29sYXRlX3RhZ3NfIgp2YXIgcj1PYmplY3Rbc118fChPYmplY3Rbc109T2JqZWN0LmNyZWF0ZShudWxs
-KSkKdmFyIHE9Il9aeFl4WCIKZm9yKHZhciBwPTA7O3ArKyl7dmFyIG89dChxKyJfIitwKyJfIikKaWYo
-IShvIGluIHIpKXtyW29dPTEKdi5pc29sYXRlVGFnPW8KYnJlYWt9fXYuZGlzcGF0Y2hQcm9wZXJ0eU5h
-bWU9di5nZXRJc29sYXRlVGFnKCJkaXNwYXRjaF9yZWNvcmQiKX0oKQpodW5rSGVscGVycy5zZXRPclVw
-ZGF0ZUludGVyY2VwdG9yc0J5VGFnKHtET01FcnJvcjpKLnZCLERPTUltcGxlbWVudGF0aW9uOkoudkIs
-TWVkaWFFcnJvcjpKLnZCLE5hdmlnYXRvcjpKLnZCLE5hdmlnYXRvckNvbmN1cnJlbnRIYXJkd2FyZTpK
-LnZCLE5hdmlnYXRvclVzZXJNZWRpYUVycm9yOkoudkIsT3ZlcmNvbnN0cmFpbmVkRXJyb3I6Si52QixQ
-b3NpdGlvbkVycm9yOkoudkIsUmFuZ2U6Si52QixTUUxFcnJvcjpKLnZCLERhdGFWaWV3OkguRVQsQXJy
-YXlCdWZmZXJWaWV3OkguRVQsRmxvYXQzMkFycmF5OkguRGcsRmxvYXQ2NEFycmF5OkguRGcsSW50MTZB
-cnJheTpILnhqLEludDMyQXJyYXk6SC5kRSxJbnQ4QXJyYXk6SC5aQSxVaW50MTZBcnJheTpILndmLFVp
-bnQzMkFycmF5OkguUHEsVWludDhDbGFtcGVkQXJyYXk6SC5lRSxDYW52YXNQaXhlbEFycmF5OkguZUUs
-VWludDhBcnJheTpILlY2LEhUTUxBdWRpb0VsZW1lbnQ6Vy5xRSxIVE1MQlJFbGVtZW50OlcucUUsSFRN
-TEJ1dHRvbkVsZW1lbnQ6Vy5xRSxIVE1MQ2FudmFzRWxlbWVudDpXLnFFLEhUTUxDb250ZW50RWxlbWVu
-dDpXLnFFLEhUTUxETGlzdEVsZW1lbnQ6Vy5xRSxIVE1MRGF0YUVsZW1lbnQ6Vy5xRSxIVE1MRGF0YUxp
-c3RFbGVtZW50OlcucUUsSFRNTERldGFpbHNFbGVtZW50OlcucUUsSFRNTERpYWxvZ0VsZW1lbnQ6Vy5x
-RSxIVE1MRGl2RWxlbWVudDpXLnFFLEhUTUxFbWJlZEVsZW1lbnQ6Vy5xRSxIVE1MRmllbGRTZXRFbGVt
-ZW50OlcucUUsSFRNTEhSRWxlbWVudDpXLnFFLEhUTUxIZWFkRWxlbWVudDpXLnFFLEhUTUxIZWFkaW5n
-RWxlbWVudDpXLnFFLEhUTUxIdG1sRWxlbWVudDpXLnFFLEhUTUxJRnJhbWVFbGVtZW50OlcucUUsSFRN
-TEltYWdlRWxlbWVudDpXLnFFLEhUTUxJbnB1dEVsZW1lbnQ6Vy5xRSxIVE1MTElFbGVtZW50OlcucUUs
-SFRNTExhYmVsRWxlbWVudDpXLnFFLEhUTUxMZWdlbmRFbGVtZW50OlcucUUsSFRNTExpbmtFbGVtZW50
-OlcucUUsSFRNTE1hcEVsZW1lbnQ6Vy5xRSxIVE1MTWVkaWFFbGVtZW50OlcucUUsSFRNTE1lbnVFbGVt
-ZW50OlcucUUsSFRNTE1ldGFFbGVtZW50OlcucUUsSFRNTE1ldGVyRWxlbWVudDpXLnFFLEhUTUxNb2RF
-bGVtZW50OlcucUUsSFRNTE9MaXN0RWxlbWVudDpXLnFFLEhUTUxPYmplY3RFbGVtZW50OlcucUUsSFRN
-TE9wdEdyb3VwRWxlbWVudDpXLnFFLEhUTUxPcHRpb25FbGVtZW50OlcucUUsSFRNTE91dHB1dEVsZW1l
-bnQ6Vy5xRSxIVE1MUGFyYW1FbGVtZW50OlcucUUsSFRNTFBpY3R1cmVFbGVtZW50OlcucUUsSFRNTFBy
-ZUVsZW1lbnQ6Vy5xRSxIVE1MUHJvZ3Jlc3NFbGVtZW50OlcucUUsSFRNTFF1b3RlRWxlbWVudDpXLnFF
-LEhUTUxTY3JpcHRFbGVtZW50OlcucUUsSFRNTFNoYWRvd0VsZW1lbnQ6Vy5xRSxIVE1MU2xvdEVsZW1l
-bnQ6Vy5xRSxIVE1MU291cmNlRWxlbWVudDpXLnFFLEhUTUxTcGFuRWxlbWVudDpXLnFFLEhUTUxTdHls
-ZUVsZW1lbnQ6Vy5xRSxIVE1MVGFibGVDYXB0aW9uRWxlbWVudDpXLnFFLEhUTUxUYWJsZUNlbGxFbGVt
-ZW50OlcucUUsSFRNTFRhYmxlRGF0YUNlbGxFbGVtZW50OlcucUUsSFRNTFRhYmxlSGVhZGVyQ2VsbEVs
-ZW1lbnQ6Vy5xRSxIVE1MVGFibGVDb2xFbGVtZW50OlcucUUsSFRNTFRleHRBcmVhRWxlbWVudDpXLnFF
-LEhUTUxUaW1lRWxlbWVudDpXLnFFLEhUTUxUaXRsZUVsZW1lbnQ6Vy5xRSxIVE1MVHJhY2tFbGVtZW50
-OlcucUUsSFRNTFVMaXN0RWxlbWVudDpXLnFFLEhUTUxVbmtub3duRWxlbWVudDpXLnFFLEhUTUxWaWRl
-b0VsZW1lbnQ6Vy5xRSxIVE1MRGlyZWN0b3J5RWxlbWVudDpXLnFFLEhUTUxGb250RWxlbWVudDpXLnFF
-LEhUTUxGcmFtZUVsZW1lbnQ6Vy5xRSxIVE1MRnJhbWVTZXRFbGVtZW50OlcucUUsSFRNTE1hcnF1ZWVF
-bGVtZW50OlcucUUsSFRNTEVsZW1lbnQ6Vy5xRSxIVE1MQW5jaG9yRWxlbWVudDpXLkdoLEhUTUxBcmVh
-RWxlbWVudDpXLmZZLEhUTUxCYXNlRWxlbWVudDpXLm5CLEJsb2I6Vy5BeixIVE1MQm9keUVsZW1lbnQ6
-Vy5RUCxDREFUQVNlY3Rpb246Vy5ueCxDaGFyYWN0ZXJEYXRhOlcubngsQ29tbWVudDpXLm54LFByb2Nl
-c3NpbmdJbnN0cnVjdGlvbjpXLm54LFRleHQ6Vy5ueCxDU1NTdHlsZURlY2xhcmF0aW9uOlcub0osTVNT
-dHlsZUNTU1Byb3BlcnRpZXM6Vy5vSixDU1MyUHJvcGVydGllczpXLm9KLFhNTERvY3VtZW50OlcuUUYs
-RG9jdW1lbnQ6Vy5RRixET01FeGNlcHRpb246Vy5OaCxET01SZWN0UmVhZE9ubHk6Vy5JQixET01Ub2tl
-bkxpc3Q6Vy5uNyxFbGVtZW50OlcuY3YsQWJvcnRQYXltZW50RXZlbnQ6Vy5lYSxBbmltYXRpb25FdmVu
-dDpXLmVhLEFuaW1hdGlvblBsYXliYWNrRXZlbnQ6Vy5lYSxBcHBsaWNhdGlvbkNhY2hlRXJyb3JFdmVu
-dDpXLmVhLEJhY2tncm91bmRGZXRjaENsaWNrRXZlbnQ6Vy5lYSxCYWNrZ3JvdW5kRmV0Y2hFdmVudDpX
-LmVhLEJhY2tncm91bmRGZXRjaEZhaWxFdmVudDpXLmVhLEJhY2tncm91bmRGZXRjaGVkRXZlbnQ6Vy5l
-YSxCZWZvcmVJbnN0YWxsUHJvbXB0RXZlbnQ6Vy5lYSxCZWZvcmVVbmxvYWRFdmVudDpXLmVhLEJsb2JF
-dmVudDpXLmVhLENhbk1ha2VQYXltZW50RXZlbnQ6Vy5lYSxDbGlwYm9hcmRFdmVudDpXLmVhLENsb3Nl
-RXZlbnQ6Vy5lYSxDdXN0b21FdmVudDpXLmVhLERldmljZU1vdGlvbkV2ZW50OlcuZWEsRGV2aWNlT3Jp
-ZW50YXRpb25FdmVudDpXLmVhLEVycm9yRXZlbnQ6Vy5lYSxFeHRlbmRhYmxlRXZlbnQ6Vy5lYSxFeHRl
-bmRhYmxlTWVzc2FnZUV2ZW50OlcuZWEsRmV0Y2hFdmVudDpXLmVhLEZvbnRGYWNlU2V0TG9hZEV2ZW50
-OlcuZWEsRm9yZWlnbkZldGNoRXZlbnQ6Vy5lYSxHYW1lcGFkRXZlbnQ6Vy5lYSxIYXNoQ2hhbmdlRXZl
-bnQ6Vy5lYSxJbnN0YWxsRXZlbnQ6Vy5lYSxNZWRpYUVuY3J5cHRlZEV2ZW50OlcuZWEsTWVkaWFLZXlN
-ZXNzYWdlRXZlbnQ6Vy5lYSxNZWRpYVF1ZXJ5TGlzdEV2ZW50OlcuZWEsTWVkaWFTdHJlYW1FdmVudDpX
-LmVhLE1lZGlhU3RyZWFtVHJhY2tFdmVudDpXLmVhLE1lc3NhZ2VFdmVudDpXLmVhLE1JRElDb25uZWN0
-aW9uRXZlbnQ6Vy5lYSxNSURJTWVzc2FnZUV2ZW50OlcuZWEsTXV0YXRpb25FdmVudDpXLmVhLE5vdGlm
-aWNhdGlvbkV2ZW50OlcuZWEsUGFnZVRyYW5zaXRpb25FdmVudDpXLmVhLFBheW1lbnRSZXF1ZXN0RXZl
-bnQ6Vy5lYSxQYXltZW50UmVxdWVzdFVwZGF0ZUV2ZW50OlcuZWEsUG9wU3RhdGVFdmVudDpXLmVhLFBy
-ZXNlbnRhdGlvbkNvbm5lY3Rpb25BdmFpbGFibGVFdmVudDpXLmVhLFByZXNlbnRhdGlvbkNvbm5lY3Rp
-b25DbG9zZUV2ZW50OlcuZWEsUHJvbWlzZVJlamVjdGlvbkV2ZW50OlcuZWEsUHVzaEV2ZW50OlcuZWEs
-UlRDRGF0YUNoYW5uZWxFdmVudDpXLmVhLFJUQ0RUTUZUb25lQ2hhbmdlRXZlbnQ6Vy5lYSxSVENQZWVy
-Q29ubmVjdGlvbkljZUV2ZW50OlcuZWEsUlRDVHJhY2tFdmVudDpXLmVhLFNlY3VyaXR5UG9saWN5Vmlv
-bGF0aW9uRXZlbnQ6Vy5lYSxTZW5zb3JFcnJvckV2ZW50OlcuZWEsU3BlZWNoUmVjb2duaXRpb25FcnJv
-cjpXLmVhLFNwZWVjaFJlY29nbml0aW9uRXZlbnQ6Vy5lYSxTcGVlY2hTeW50aGVzaXNFdmVudDpXLmVh
-LFN0b3JhZ2VFdmVudDpXLmVhLFN5bmNFdmVudDpXLmVhLFRyYWNrRXZlbnQ6Vy5lYSxUcmFuc2l0aW9u
-RXZlbnQ6Vy5lYSxXZWJLaXRUcmFuc2l0aW9uRXZlbnQ6Vy5lYSxWUkRldmljZUV2ZW50OlcuZWEsVlJE
-aXNwbGF5RXZlbnQ6Vy5lYSxWUlNlc3Npb25FdmVudDpXLmVhLE1vam9JbnRlcmZhY2VSZXF1ZXN0RXZl
-bnQ6Vy5lYSxVU0JDb25uZWN0aW9uRXZlbnQ6Vy5lYSxJREJWZXJzaW9uQ2hhbmdlRXZlbnQ6Vy5lYSxB
-dWRpb1Byb2Nlc3NpbmdFdmVudDpXLmVhLE9mZmxpbmVBdWRpb0NvbXBsZXRpb25FdmVudDpXLmVhLFdl
-YkdMQ29udGV4dEV2ZW50OlcuZWEsRXZlbnQ6Vy5lYSxJbnB1dEV2ZW50OlcuZWEsRXZlbnRUYXJnZXQ6
-Vy5EMCxGaWxlOlcuaEgsSFRNTEZvcm1FbGVtZW50OlcuaDQsSGlzdG9yeTpXLmJyLEhUTUxEb2N1bWVu
-dDpXLlZiLFhNTEh0dHBSZXF1ZXN0OlcuTzcsWE1MSHR0cFJlcXVlc3RFdmVudFRhcmdldDpXLndhLElt
-YWdlRGF0YTpXLlNnLExvY2F0aW9uOlcudTgsTW91c2VFdmVudDpXLkFqLERyYWdFdmVudDpXLkFqLFBv
-aW50ZXJFdmVudDpXLkFqLFdoZWVsRXZlbnQ6Vy5BaixEb2N1bWVudEZyYWdtZW50OlcudUgsU2hhZG93
-Um9vdDpXLnVILERvY3VtZW50VHlwZTpXLnVILE5vZGU6Vy51SCxOb2RlTGlzdDpXLkJILFJhZGlvTm9k
-ZUxpc3Q6Vy5CSCxIVE1MUGFyYWdyYXBoRWxlbWVudDpXLlNOLFByb2dyZXNzRXZlbnQ6Vy5ldyxSZXNv
-dXJjZVByb2dyZXNzRXZlbnQ6Vy5ldyxIVE1MU2VsZWN0RWxlbWVudDpXLmxwLEhUTUxUYWJsZUVsZW1l
-bnQ6Vy5UYixIVE1MVGFibGVSb3dFbGVtZW50OlcuSXYsSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQ6Vy5X
-UCxIVE1MVGVtcGxhdGVFbGVtZW50OlcueVksQ29tcG9zaXRpb25FdmVudDpXLnc2LEZvY3VzRXZlbnQ6
-Vy53NixLZXlib2FyZEV2ZW50OlcudzYsVGV4dEV2ZW50OlcudzYsVG91Y2hFdmVudDpXLnc2LFVJRXZl
-bnQ6Vy53NixXaW5kb3c6Vy5LNSxET01XaW5kb3c6Vy5LNSxEZWRpY2F0ZWRXb3JrZXJHbG9iYWxTY29w
-ZTpXLkNtLFNlcnZpY2VXb3JrZXJHbG9iYWxTY29wZTpXLkNtLFNoYXJlZFdvcmtlckdsb2JhbFNjb3Bl
-OlcuQ20sV29ya2VyR2xvYmFsU2NvcGU6Vy5DbSxBdHRyOlcuQ1EsQ2xpZW50UmVjdDpXLnc0LERPTVJl
-Y3Q6Vy53NCxOYW1lZE5vZGVNYXA6Vy5yaCxNb3pOYW1lZEF0dHJNYXA6Vy5yaCxJREJLZXlSYW5nZTpQ
-LmhGLFNWR1NjcmlwdEVsZW1lbnQ6UC5uZCxTVkdBRWxlbWVudDpQLmQ1LFNWR0FuaW1hdGVFbGVtZW50
-OlAuZDUsU1ZHQW5pbWF0ZU1vdGlvbkVsZW1lbnQ6UC5kNSxTVkdBbmltYXRlVHJhbnNmb3JtRWxlbWVu
-dDpQLmQ1LFNWR0FuaW1hdGlvbkVsZW1lbnQ6UC5kNSxTVkdDaXJjbGVFbGVtZW50OlAuZDUsU1ZHQ2xp
-cFBhdGhFbGVtZW50OlAuZDUsU1ZHRGVmc0VsZW1lbnQ6UC5kNSxTVkdEZXNjRWxlbWVudDpQLmQ1LFNW
-R0Rpc2NhcmRFbGVtZW50OlAuZDUsU1ZHRWxsaXBzZUVsZW1lbnQ6UC5kNSxTVkdGRUJsZW5kRWxlbWVu
-dDpQLmQ1LFNWR0ZFQ29sb3JNYXRyaXhFbGVtZW50OlAuZDUsU1ZHRkVDb21wb25lbnRUcmFuc2ZlckVs
-ZW1lbnQ6UC5kNSxTVkdGRUNvbXBvc2l0ZUVsZW1lbnQ6UC5kNSxTVkdGRUNvbnZvbHZlTWF0cml4RWxl
-bWVudDpQLmQ1LFNWR0ZFRGlmZnVzZUxpZ2h0aW5nRWxlbWVudDpQLmQ1LFNWR0ZFRGlzcGxhY2VtZW50
-TWFwRWxlbWVudDpQLmQ1LFNWR0ZFRGlzdGFudExpZ2h0RWxlbWVudDpQLmQ1LFNWR0ZFRmxvb2RFbGVt
-ZW50OlAuZDUsU1ZHRkVGdW5jQUVsZW1lbnQ6UC5kNSxTVkdGRUZ1bmNCRWxlbWVudDpQLmQ1LFNWR0ZF
-RnVuY0dFbGVtZW50OlAuZDUsU1ZHRkVGdW5jUkVsZW1lbnQ6UC5kNSxTVkdGRUdhdXNzaWFuQmx1ckVs
-ZW1lbnQ6UC5kNSxTVkdGRUltYWdlRWxlbWVudDpQLmQ1LFNWR0ZFTWVyZ2VFbGVtZW50OlAuZDUsU1ZH
-RkVNZXJnZU5vZGVFbGVtZW50OlAuZDUsU1ZHRkVNb3JwaG9sb2d5RWxlbWVudDpQLmQ1LFNWR0ZFT2Zm
-c2V0RWxlbWVudDpQLmQ1LFNWR0ZFUG9pbnRMaWdodEVsZW1lbnQ6UC5kNSxTVkdGRVNwZWN1bGFyTGln
-aHRpbmdFbGVtZW50OlAuZDUsU1ZHRkVTcG90TGlnaHRFbGVtZW50OlAuZDUsU1ZHRkVUaWxlRWxlbWVu
-dDpQLmQ1LFNWR0ZFVHVyYnVsZW5jZUVsZW1lbnQ6UC5kNSxTVkdGaWx0ZXJFbGVtZW50OlAuZDUsU1ZH
-Rm9yZWlnbk9iamVjdEVsZW1lbnQ6UC5kNSxTVkdHRWxlbWVudDpQLmQ1LFNWR0dlb21ldHJ5RWxlbWVu
-dDpQLmQ1LFNWR0dyYXBoaWNzRWxlbWVudDpQLmQ1LFNWR0ltYWdlRWxlbWVudDpQLmQ1LFNWR0xpbmVF
-bGVtZW50OlAuZDUsU1ZHTGluZWFyR3JhZGllbnRFbGVtZW50OlAuZDUsU1ZHTWFya2VyRWxlbWVudDpQ
-LmQ1LFNWR01hc2tFbGVtZW50OlAuZDUsU1ZHTWV0YWRhdGFFbGVtZW50OlAuZDUsU1ZHUGF0aEVsZW1l
-bnQ6UC5kNSxTVkdQYXR0ZXJuRWxlbWVudDpQLmQ1LFNWR1BvbHlnb25FbGVtZW50OlAuZDUsU1ZHUG9s
-eWxpbmVFbGVtZW50OlAuZDUsU1ZHUmFkaWFsR3JhZGllbnRFbGVtZW50OlAuZDUsU1ZHUmVjdEVsZW1l
-bnQ6UC5kNSxTVkdTZXRFbGVtZW50OlAuZDUsU1ZHU3RvcEVsZW1lbnQ6UC5kNSxTVkdTdHlsZUVsZW1l
-bnQ6UC5kNSxTVkdTVkdFbGVtZW50OlAuZDUsU1ZHU3dpdGNoRWxlbWVudDpQLmQ1LFNWR1N5bWJvbEVs
-ZW1lbnQ6UC5kNSxTVkdUU3BhbkVsZW1lbnQ6UC5kNSxTVkdUZXh0Q29udGVudEVsZW1lbnQ6UC5kNSxT
-VkdUZXh0RWxlbWVudDpQLmQ1LFNWR1RleHRQYXRoRWxlbWVudDpQLmQ1LFNWR1RleHRQb3NpdGlvbmlu
-Z0VsZW1lbnQ6UC5kNSxTVkdUaXRsZUVsZW1lbnQ6UC5kNSxTVkdVc2VFbGVtZW50OlAuZDUsU1ZHVmll
-d0VsZW1lbnQ6UC5kNSxTVkdHcmFkaWVudEVsZW1lbnQ6UC5kNSxTVkdDb21wb25lbnRUcmFuc2ZlckZ1
-bmN0aW9uRWxlbWVudDpQLmQ1LFNWR0ZFRHJvcFNoYWRvd0VsZW1lbnQ6UC5kNSxTVkdNUGF0aEVsZW1l
-bnQ6UC5kNSxTVkdFbGVtZW50OlAuZDV9KQpodW5rSGVscGVycy5zZXRPclVwZGF0ZUxlYWZUYWdzKHtE
-T01FcnJvcjp0cnVlLERPTUltcGxlbWVudGF0aW9uOnRydWUsTWVkaWFFcnJvcjp0cnVlLE5hdmlnYXRv
-cjp0cnVlLE5hdmlnYXRvckNvbmN1cnJlbnRIYXJkd2FyZTp0cnVlLE5hdmlnYXRvclVzZXJNZWRpYUVy
-cm9yOnRydWUsT3ZlcmNvbnN0cmFpbmVkRXJyb3I6dHJ1ZSxQb3NpdGlvbkVycm9yOnRydWUsUmFuZ2U6
-dHJ1ZSxTUUxFcnJvcjp0cnVlLERhdGFWaWV3OnRydWUsQXJyYXlCdWZmZXJWaWV3OmZhbHNlLEZsb2F0
-MzJBcnJheTp0cnVlLEZsb2F0NjRBcnJheTp0cnVlLEludDE2QXJyYXk6dHJ1ZSxJbnQzMkFycmF5OnRy
-dWUsSW50OEFycmF5OnRydWUsVWludDE2QXJyYXk6dHJ1ZSxVaW50MzJBcnJheTp0cnVlLFVpbnQ4Q2xh
-bXBlZEFycmF5OnRydWUsQ2FudmFzUGl4ZWxBcnJheTp0cnVlLFVpbnQ4QXJyYXk6ZmFsc2UsSFRNTEF1
-ZGlvRWxlbWVudDp0cnVlLEhUTUxCUkVsZW1lbnQ6dHJ1ZSxIVE1MQnV0dG9uRWxlbWVudDp0cnVlLEhU
-TUxDYW52YXNFbGVtZW50OnRydWUsSFRNTENvbnRlbnRFbGVtZW50OnRydWUsSFRNTERMaXN0RWxlbWVu
-dDp0cnVlLEhUTUxEYXRhRWxlbWVudDp0cnVlLEhUTUxEYXRhTGlzdEVsZW1lbnQ6dHJ1ZSxIVE1MRGV0
-YWlsc0VsZW1lbnQ6dHJ1ZSxIVE1MRGlhbG9nRWxlbWVudDp0cnVlLEhUTUxEaXZFbGVtZW50OnRydWUs
-SFRNTEVtYmVkRWxlbWVudDp0cnVlLEhUTUxGaWVsZFNldEVsZW1lbnQ6dHJ1ZSxIVE1MSFJFbGVtZW50
-OnRydWUsSFRNTEhlYWRFbGVtZW50OnRydWUsSFRNTEhlYWRpbmdFbGVtZW50OnRydWUsSFRNTEh0bWxF
-bGVtZW50OnRydWUsSFRNTElGcmFtZUVsZW1lbnQ6dHJ1ZSxIVE1MSW1hZ2VFbGVtZW50OnRydWUsSFRN
-TElucHV0RWxlbWVudDp0cnVlLEhUTUxMSUVsZW1lbnQ6dHJ1ZSxIVE1MTGFiZWxFbGVtZW50OnRydWUs
-SFRNTExlZ2VuZEVsZW1lbnQ6dHJ1ZSxIVE1MTGlua0VsZW1lbnQ6dHJ1ZSxIVE1MTWFwRWxlbWVudDp0
-cnVlLEhUTUxNZWRpYUVsZW1lbnQ6dHJ1ZSxIVE1MTWVudUVsZW1lbnQ6dHJ1ZSxIVE1MTWV0YUVsZW1l
-bnQ6dHJ1ZSxIVE1MTWV0ZXJFbGVtZW50OnRydWUsSFRNTE1vZEVsZW1lbnQ6dHJ1ZSxIVE1MT0xpc3RF
-bGVtZW50OnRydWUsSFRNTE9iamVjdEVsZW1lbnQ6dHJ1ZSxIVE1MT3B0R3JvdXBFbGVtZW50OnRydWUs
-SFRNTE9wdGlvbkVsZW1lbnQ6dHJ1ZSxIVE1MT3V0cHV0RWxlbWVudDp0cnVlLEhUTUxQYXJhbUVsZW1l
-bnQ6dHJ1ZSxIVE1MUGljdHVyZUVsZW1lbnQ6dHJ1ZSxIVE1MUHJlRWxlbWVudDp0cnVlLEhUTUxQcm9n
-cmVzc0VsZW1lbnQ6dHJ1ZSxIVE1MUXVvdGVFbGVtZW50OnRydWUsSFRNTFNjcmlwdEVsZW1lbnQ6dHJ1
-ZSxIVE1MU2hhZG93RWxlbWVudDp0cnVlLEhUTUxTbG90RWxlbWVudDp0cnVlLEhUTUxTb3VyY2VFbGVt
-ZW50OnRydWUsSFRNTFNwYW5FbGVtZW50OnRydWUsSFRNTFN0eWxlRWxlbWVudDp0cnVlLEhUTUxUYWJs
-ZUNhcHRpb25FbGVtZW50OnRydWUsSFRNTFRhYmxlQ2VsbEVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVEYXRh
-Q2VsbEVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVIZWFkZXJDZWxsRWxlbWVudDp0cnVlLEhUTUxUYWJsZUNv
-bEVsZW1lbnQ6dHJ1ZSxIVE1MVGV4dEFyZWFFbGVtZW50OnRydWUsSFRNTFRpbWVFbGVtZW50OnRydWUs
-SFRNTFRpdGxlRWxlbWVudDp0cnVlLEhUTUxUcmFja0VsZW1lbnQ6dHJ1ZSxIVE1MVUxpc3RFbGVtZW50
-OnRydWUsSFRNTFVua25vd25FbGVtZW50OnRydWUsSFRNTFZpZGVvRWxlbWVudDp0cnVlLEhUTUxEaXJl
-Y3RvcnlFbGVtZW50OnRydWUsSFRNTEZvbnRFbGVtZW50OnRydWUsSFRNTEZyYW1lRWxlbWVudDp0cnVl
-LEhUTUxGcmFtZVNldEVsZW1lbnQ6dHJ1ZSxIVE1MTWFycXVlZUVsZW1lbnQ6dHJ1ZSxIVE1MRWxlbWVu
-dDpmYWxzZSxIVE1MQW5jaG9yRWxlbWVudDp0cnVlLEhUTUxBcmVhRWxlbWVudDp0cnVlLEhUTUxCYXNl
-RWxlbWVudDp0cnVlLEJsb2I6ZmFsc2UsSFRNTEJvZHlFbGVtZW50OnRydWUsQ0RBVEFTZWN0aW9uOnRy
-dWUsQ2hhcmFjdGVyRGF0YTp0cnVlLENvbW1lbnQ6dHJ1ZSxQcm9jZXNzaW5nSW5zdHJ1Y3Rpb246dHJ1
-ZSxUZXh0OnRydWUsQ1NTU3R5bGVEZWNsYXJhdGlvbjp0cnVlLE1TU3R5bGVDU1NQcm9wZXJ0aWVzOnRy
-dWUsQ1NTMlByb3BlcnRpZXM6dHJ1ZSxYTUxEb2N1bWVudDp0cnVlLERvY3VtZW50OmZhbHNlLERPTUV4
-Y2VwdGlvbjp0cnVlLERPTVJlY3RSZWFkT25seTpmYWxzZSxET01Ub2tlbkxpc3Q6dHJ1ZSxFbGVtZW50
-OmZhbHNlLEFib3J0UGF5bWVudEV2ZW50OnRydWUsQW5pbWF0aW9uRXZlbnQ6dHJ1ZSxBbmltYXRpb25Q
-bGF5YmFja0V2ZW50OnRydWUsQXBwbGljYXRpb25DYWNoZUVycm9yRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5k
-RmV0Y2hDbGlja0V2ZW50OnRydWUsQmFja2dyb3VuZEZldGNoRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5kRmV0
-Y2hGYWlsRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5kRmV0Y2hlZEV2ZW50OnRydWUsQmVmb3JlSW5zdGFsbFBy
-b21wdEV2ZW50OnRydWUsQmVmb3JlVW5sb2FkRXZlbnQ6dHJ1ZSxCbG9iRXZlbnQ6dHJ1ZSxDYW5NYWtl
-UGF5bWVudEV2ZW50OnRydWUsQ2xpcGJvYXJkRXZlbnQ6dHJ1ZSxDbG9zZUV2ZW50OnRydWUsQ3VzdG9t
-RXZlbnQ6dHJ1ZSxEZXZpY2VNb3Rpb25FdmVudDp0cnVlLERldmljZU9yaWVudGF0aW9uRXZlbnQ6dHJ1
-ZSxFcnJvckV2ZW50OnRydWUsRXh0ZW5kYWJsZUV2ZW50OnRydWUsRXh0ZW5kYWJsZU1lc3NhZ2VFdmVu
-dDp0cnVlLEZldGNoRXZlbnQ6dHJ1ZSxGb250RmFjZVNldExvYWRFdmVudDp0cnVlLEZvcmVpZ25GZXRj
-aEV2ZW50OnRydWUsR2FtZXBhZEV2ZW50OnRydWUsSGFzaENoYW5nZUV2ZW50OnRydWUsSW5zdGFsbEV2
-ZW50OnRydWUsTWVkaWFFbmNyeXB0ZWRFdmVudDp0cnVlLE1lZGlhS2V5TWVzc2FnZUV2ZW50OnRydWUs
-TWVkaWFRdWVyeUxpc3RFdmVudDp0cnVlLE1lZGlhU3RyZWFtRXZlbnQ6dHJ1ZSxNZWRpYVN0cmVhbVRy
-YWNrRXZlbnQ6dHJ1ZSxNZXNzYWdlRXZlbnQ6dHJ1ZSxNSURJQ29ubmVjdGlvbkV2ZW50OnRydWUsTUlE
-SU1lc3NhZ2VFdmVudDp0cnVlLE11dGF0aW9uRXZlbnQ6dHJ1ZSxOb3RpZmljYXRpb25FdmVudDp0cnVl
-LFBhZ2VUcmFuc2l0aW9uRXZlbnQ6dHJ1ZSxQYXltZW50UmVxdWVzdEV2ZW50OnRydWUsUGF5bWVudFJl
-cXVlc3RVcGRhdGVFdmVudDp0cnVlLFBvcFN0YXRlRXZlbnQ6dHJ1ZSxQcmVzZW50YXRpb25Db25uZWN0
-aW9uQXZhaWxhYmxlRXZlbnQ6dHJ1ZSxQcmVzZW50YXRpb25Db25uZWN0aW9uQ2xvc2VFdmVudDp0cnVl
-LFByb21pc2VSZWplY3Rpb25FdmVudDp0cnVlLFB1c2hFdmVudDp0cnVlLFJUQ0RhdGFDaGFubmVsRXZl
-bnQ6dHJ1ZSxSVENEVE1GVG9uZUNoYW5nZUV2ZW50OnRydWUsUlRDUGVlckNvbm5lY3Rpb25JY2VFdmVu
-dDp0cnVlLFJUQ1RyYWNrRXZlbnQ6dHJ1ZSxTZWN1cml0eVBvbGljeVZpb2xhdGlvbkV2ZW50OnRydWUs
-U2Vuc29yRXJyb3JFdmVudDp0cnVlLFNwZWVjaFJlY29nbml0aW9uRXJyb3I6dHJ1ZSxTcGVlY2hSZWNv
-Z25pdGlvbkV2ZW50OnRydWUsU3BlZWNoU3ludGhlc2lzRXZlbnQ6dHJ1ZSxTdG9yYWdlRXZlbnQ6dHJ1
-ZSxTeW5jRXZlbnQ6dHJ1ZSxUcmFja0V2ZW50OnRydWUsVHJhbnNpdGlvbkV2ZW50OnRydWUsV2ViS2l0
-VHJhbnNpdGlvbkV2ZW50OnRydWUsVlJEZXZpY2VFdmVudDp0cnVlLFZSRGlzcGxheUV2ZW50OnRydWUs
-VlJTZXNzaW9uRXZlbnQ6dHJ1ZSxNb2pvSW50ZXJmYWNlUmVxdWVzdEV2ZW50OnRydWUsVVNCQ29ubmVj
-dGlvbkV2ZW50OnRydWUsSURCVmVyc2lvbkNoYW5nZUV2ZW50OnRydWUsQXVkaW9Qcm9jZXNzaW5nRXZl
-bnQ6dHJ1ZSxPZmZsaW5lQXVkaW9Db21wbGV0aW9uRXZlbnQ6dHJ1ZSxXZWJHTENvbnRleHRFdmVudDp0
-cnVlLEV2ZW50OmZhbHNlLElucHV0RXZlbnQ6ZmFsc2UsRXZlbnRUYXJnZXQ6ZmFsc2UsRmlsZTp0cnVl
-LEhUTUxGb3JtRWxlbWVudDp0cnVlLEhpc3Rvcnk6dHJ1ZSxIVE1MRG9jdW1lbnQ6dHJ1ZSxYTUxIdHRw
-UmVxdWVzdDp0cnVlLFhNTEh0dHBSZXF1ZXN0RXZlbnRUYXJnZXQ6ZmFsc2UsSW1hZ2VEYXRhOnRydWUs
-TG9jYXRpb246dHJ1ZSxNb3VzZUV2ZW50OnRydWUsRHJhZ0V2ZW50OnRydWUsUG9pbnRlckV2ZW50OnRy
-dWUsV2hlZWxFdmVudDp0cnVlLERvY3VtZW50RnJhZ21lbnQ6dHJ1ZSxTaGFkb3dSb290OnRydWUsRG9j
-dW1lbnRUeXBlOnRydWUsTm9kZTpmYWxzZSxOb2RlTGlzdDp0cnVlLFJhZGlvTm9kZUxpc3Q6dHJ1ZSxI
-VE1MUGFyYWdyYXBoRWxlbWVudDp0cnVlLFByb2dyZXNzRXZlbnQ6dHJ1ZSxSZXNvdXJjZVByb2dyZXNz
-RXZlbnQ6dHJ1ZSxIVE1MU2VsZWN0RWxlbWVudDp0cnVlLEhUTUxUYWJsZUVsZW1lbnQ6dHJ1ZSxIVE1M
-VGFibGVSb3dFbGVtZW50OnRydWUsSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQ6dHJ1ZSxIVE1MVGVtcGxh
-dGVFbGVtZW50OnRydWUsQ29tcG9zaXRpb25FdmVudDp0cnVlLEZvY3VzRXZlbnQ6dHJ1ZSxLZXlib2Fy
-ZEV2ZW50OnRydWUsVGV4dEV2ZW50OnRydWUsVG91Y2hFdmVudDp0cnVlLFVJRXZlbnQ6ZmFsc2UsV2lu
-ZG93OnRydWUsRE9NV2luZG93OnRydWUsRGVkaWNhdGVkV29ya2VyR2xvYmFsU2NvcGU6dHJ1ZSxTZXJ2
-aWNlV29ya2VyR2xvYmFsU2NvcGU6dHJ1ZSxTaGFyZWRXb3JrZXJHbG9iYWxTY29wZTp0cnVlLFdvcmtl
-ckdsb2JhbFNjb3BlOnRydWUsQXR0cjp0cnVlLENsaWVudFJlY3Q6dHJ1ZSxET01SZWN0OnRydWUsTmFt
-ZWROb2RlTWFwOnRydWUsTW96TmFtZWRBdHRyTWFwOnRydWUsSURCS2V5UmFuZ2U6dHJ1ZSxTVkdTY3Jp
-cHRFbGVtZW50OnRydWUsU1ZHQUVsZW1lbnQ6dHJ1ZSxTVkdBbmltYXRlRWxlbWVudDp0cnVlLFNWR0Fu
-aW1hdGVNb3Rpb25FbGVtZW50OnRydWUsU1ZHQW5pbWF0ZVRyYW5zZm9ybUVsZW1lbnQ6dHJ1ZSxTVkdB
-bmltYXRpb25FbGVtZW50OnRydWUsU1ZHQ2lyY2xlRWxlbWVudDp0cnVlLFNWR0NsaXBQYXRoRWxlbWVu
-dDp0cnVlLFNWR0RlZnNFbGVtZW50OnRydWUsU1ZHRGVzY0VsZW1lbnQ6dHJ1ZSxTVkdEaXNjYXJkRWxl
-bWVudDp0cnVlLFNWR0VsbGlwc2VFbGVtZW50OnRydWUsU1ZHRkVCbGVuZEVsZW1lbnQ6dHJ1ZSxTVkdG
-RUNvbG9yTWF0cml4RWxlbWVudDp0cnVlLFNWR0ZFQ29tcG9uZW50VHJhbnNmZXJFbGVtZW50OnRydWUs
-U1ZHRkVDb21wb3NpdGVFbGVtZW50OnRydWUsU1ZHRkVDb252b2x2ZU1hdHJpeEVsZW1lbnQ6dHJ1ZSxT
-VkdGRURpZmZ1c2VMaWdodGluZ0VsZW1lbnQ6dHJ1ZSxTVkdGRURpc3BsYWNlbWVudE1hcEVsZW1lbnQ6
-dHJ1ZSxTVkdGRURpc3RhbnRMaWdodEVsZW1lbnQ6dHJ1ZSxTVkdGRUZsb29kRWxlbWVudDp0cnVlLFNW
-R0ZFRnVuY0FFbGVtZW50OnRydWUsU1ZHRkVGdW5jQkVsZW1lbnQ6dHJ1ZSxTVkdGRUZ1bmNHRWxlbWVu
-dDp0cnVlLFNWR0ZFRnVuY1JFbGVtZW50OnRydWUsU1ZHRkVHYXVzc2lhbkJsdXJFbGVtZW50OnRydWUs
-U1ZHRkVJbWFnZUVsZW1lbnQ6dHJ1ZSxTVkdGRU1lcmdlRWxlbWVudDp0cnVlLFNWR0ZFTWVyZ2VOb2Rl
-RWxlbWVudDp0cnVlLFNWR0ZFTW9ycGhvbG9neUVsZW1lbnQ6dHJ1ZSxTVkdGRU9mZnNldEVsZW1lbnQ6
-dHJ1ZSxTVkdGRVBvaW50TGlnaHRFbGVtZW50OnRydWUsU1ZHRkVTcGVjdWxhckxpZ2h0aW5nRWxlbWVu
-dDp0cnVlLFNWR0ZFU3BvdExpZ2h0RWxlbWVudDp0cnVlLFNWR0ZFVGlsZUVsZW1lbnQ6dHJ1ZSxTVkdG
-RVR1cmJ1bGVuY2VFbGVtZW50OnRydWUsU1ZHRmlsdGVyRWxlbWVudDp0cnVlLFNWR0ZvcmVpZ25PYmpl
-Y3RFbGVtZW50OnRydWUsU1ZHR0VsZW1lbnQ6dHJ1ZSxTVkdHZW9tZXRyeUVsZW1lbnQ6dHJ1ZSxTVkdH
-cmFwaGljc0VsZW1lbnQ6dHJ1ZSxTVkdJbWFnZUVsZW1lbnQ6dHJ1ZSxTVkdMaW5lRWxlbWVudDp0cnVl
-LFNWR0xpbmVhckdyYWRpZW50RWxlbWVudDp0cnVlLFNWR01hcmtlckVsZW1lbnQ6dHJ1ZSxTVkdNYXNr
-RWxlbWVudDp0cnVlLFNWR01ldGFkYXRhRWxlbWVudDp0cnVlLFNWR1BhdGhFbGVtZW50OnRydWUsU1ZH
-UGF0dGVybkVsZW1lbnQ6dHJ1ZSxTVkdQb2x5Z29uRWxlbWVudDp0cnVlLFNWR1BvbHlsaW5lRWxlbWVu
-dDp0cnVlLFNWR1JhZGlhbEdyYWRpZW50RWxlbWVudDp0cnVlLFNWR1JlY3RFbGVtZW50OnRydWUsU1ZH
-U2V0RWxlbWVudDp0cnVlLFNWR1N0b3BFbGVtZW50OnRydWUsU1ZHU3R5bGVFbGVtZW50OnRydWUsU1ZH
-U1ZHRWxlbWVudDp0cnVlLFNWR1N3aXRjaEVsZW1lbnQ6dHJ1ZSxTVkdTeW1ib2xFbGVtZW50OnRydWUs
-U1ZHVFNwYW5FbGVtZW50OnRydWUsU1ZHVGV4dENvbnRlbnRFbGVtZW50OnRydWUsU1ZHVGV4dEVsZW1l
-bnQ6dHJ1ZSxTVkdUZXh0UGF0aEVsZW1lbnQ6dHJ1ZSxTVkdUZXh0UG9zaXRpb25pbmdFbGVtZW50OnRy
-dWUsU1ZHVGl0bGVFbGVtZW50OnRydWUsU1ZHVXNlRWxlbWVudDp0cnVlLFNWR1ZpZXdFbGVtZW50OnRy
-dWUsU1ZHR3JhZGllbnRFbGVtZW50OnRydWUsU1ZHQ29tcG9uZW50VHJhbnNmZXJGdW5jdGlvbkVsZW1l
-bnQ6dHJ1ZSxTVkdGRURyb3BTaGFkb3dFbGVtZW50OnRydWUsU1ZHTVBhdGhFbGVtZW50OnRydWUsU1ZH
-RWxlbWVudDpmYWxzZX0pCkguTFouJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVmZmVyVmlldyIK
-SC5SRy4kbmF0aXZlU3VwZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILlZQLiRuYXRpdmVTdXBl
-cmNsYXNzVGFnPSJBcnJheUJ1ZmZlclZpZXciCkguRGcuJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5
-QnVmZmVyVmlldyIKSC5XQi4kbmF0aXZlU3VwZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILlpH
-LiRuYXRpdmVTdXBlcmNsYXNzVGFnPSJBcnJheUJ1ZmZlclZpZXciCkguUGcuJG5hdGl2ZVN1cGVyY2xh
-c3NUYWc9IkFycmF5QnVmZmVyVmlldyJ9KSgpCmNvbnZlcnRBbGxUb0Zhc3RPYmplY3QodykKY29udmVy
-dFRvRmFzdE9iamVjdCgkKTsoZnVuY3Rpb24oYSl7aWYodHlwZW9mIGRvY3VtZW50PT09InVuZGVmaW5l
-ZCIpe2EobnVsbCkKcmV0dXJufWlmKHR5cGVvZiBkb2N1bWVudC5jdXJyZW50U2NyaXB0IT0ndW5kZWZp
-bmVkJyl7YShkb2N1bWVudC5jdXJyZW50U2NyaXB0KQpyZXR1cm59dmFyIHQ9ZG9jdW1lbnQuc2NyaXB0
-cwpmdW5jdGlvbiBvbkxvYWQoYil7Zm9yKHZhciByPTA7cjx0Lmxlbmd0aDsrK3IpdFtyXS5yZW1vdmVF
-dmVudExpc3RlbmVyKCJsb2FkIixvbkxvYWQsZmFsc2UpCmEoYi50YXJnZXQpfWZvcih2YXIgcz0wO3M8
-dC5sZW5ndGg7KytzKXRbc10uYWRkRXZlbnRMaXN0ZW5lcigibG9hZCIsb25Mb2FkLGZhbHNlKX0pKGZ1
-bmN0aW9uKGEpe3YuY3VycmVudFNjcmlwdD1hCmlmKHR5cGVvZiBkYXJ0TWFpblJ1bm5lcj09PSJmdW5j
-dGlvbiIpZGFydE1haW5SdW5uZXIoTC5JcSxbXSkKZWxzZSBMLklxKFtdKX0pfSkoKQovLyMgc291cmNl
-TWFwcGluZ1VSTD1taWdyYXRpb24uanMubWFwCg==
+cm4gSC5rKGEsYikKcmV0dXJuIGFbYl19LAokaWJROjEsCiRpWGo6MSwKJGljWDoxLAokaXpNOjF9Clcu
+U04ucHJvdG90eXBlPXt9ClcuZXcucHJvdG90eXBlPXskaWV3OjF9ClcubHAucHJvdG90eXBlPXsKZ0E6
+ZnVuY3Rpb24oYSl7cmV0dXJuIGEubGVuZ3RofX0KVy5UYi5wcm90b3R5cGU9ewpyNjpmdW5jdGlvbihh
+LGIsYyxkKXt2YXIgdCxzCmlmKCJjcmVhdGVDb250ZXh0dWFsRnJhZ21lbnQiIGluIHdpbmRvdy5SYW5n
+ZS5wcm90b3R5cGUpcmV0dXJuIHRoaXMuRFcoYSxiLGMsZCkKdD1XLlU5KCI8dGFibGU+IitILmQoYikr
+IjwvdGFibGU+IixjLGQpCnM9ZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpCnMudG9TdHJp
+bmcKdC50b1N0cmluZwpuZXcgVy5lNyhzKS5GVigwLG5ldyBXLmU3KHQpKQpyZXR1cm4gc319ClcuSXYu
+cHJvdG90eXBlPXsKcjY6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQscyxyLHEKaWYoImNyZWF0ZUNvbnRl
+eHR1YWxGcmFnbWVudCIgaW4gd2luZG93LlJhbmdlLnByb3RvdHlwZSlyZXR1cm4gdGhpcy5EVyhhLGIs
+YyxkKQp0PWRvY3VtZW50CnM9dC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCkKdD1DLkllLnI2KHQuY3Jl
+YXRlRWxlbWVudCgidGFibGUiKSxiLGMsZCkKdC50b1N0cmluZwp0PW5ldyBXLmU3KHQpCnI9dC5ncjgo
+dCkKci50b1N0cmluZwp0PW5ldyBXLmU3KHIpCnE9dC5ncjgodCkKcy50b1N0cmluZwpxLnRvU3RyaW5n
+Cm5ldyBXLmU3KHMpLkZWKDAsbmV3IFcuZTcocSkpCnJldHVybiBzfX0KVy5XUC5wcm90b3R5cGU9ewpy
+NjpmdW5jdGlvbihhLGIsYyxkKXt2YXIgdCxzLHIKaWYoImNyZWF0ZUNvbnRleHR1YWxGcmFnbWVudCIg
+aW4gd2luZG93LlJhbmdlLnByb3RvdHlwZSlyZXR1cm4gdGhpcy5EVyhhLGIsYyxkKQp0PWRvY3VtZW50
+CnM9dC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCkKdD1DLkllLnI2KHQuY3JlYXRlRWxlbWVudCgidGFi
+bGUiKSxiLGMsZCkKdC50b1N0cmluZwp0PW5ldyBXLmU3KHQpCnI9dC5ncjgodCkKcy50b1N0cmluZwpy
+LnRvU3RyaW5nCm5ldyBXLmU3KHMpLkZWKDAsbmV3IFcuZTcocikpCnJldHVybiBzfX0KVy55WS5wcm90
+b3R5cGU9ewpwazpmdW5jdGlvbihhLGIsYyl7dmFyIHQscwphLnRleHRDb250ZW50PW51bGwKdD1hLmNv
+bnRlbnQKdC50b1N0cmluZwpKLmJUKHQpCnM9dGhpcy5yNihhLGIsbnVsbCxjKQphLmNvbnRlbnQuYXBw
+ZW5kQ2hpbGQocyl9LApZQzpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnBrKGEsYixudWxsKX0sCiRp
+eVk6MX0KVy53Ni5wcm90b3R5cGU9e30KVy5LNS5wcm90b3R5cGU9ewpQbzpmdW5jdGlvbihhLGIsYyl7
+dmFyIHQ9Vy5QMShhLm9wZW4oYixjKSkKcmV0dXJuIHR9LApnbVc6ZnVuY3Rpb24oYSl7cmV0dXJuIGEu
+bG9jYXRpb259LAokaUs1OjEsCiRpdjY6MX0KVy5DbS5wcm90b3R5cGU9eyRpQ206MX0KVy5DUS5wcm90
+b3R5cGU9eyRpQ1E6MX0KVy53NC5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3JldHVybiJSZWN0YW5n
+bGUgKCIrSC5kKGEubGVmdCkrIiwgIitILmQoYS50b3ApKyIpICIrSC5kKGEud2lkdGgpKyIgeCAiK0gu
+ZChhLmhlaWdodCl9LApETjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0dXJuITEKcmV0dXJuIHUu
+cS5iKGIpJiZhLmxlZnQ9PWIubGVmdCYmYS50b3A9PWIudG9wJiZhLndpZHRoPT1iLndpZHRoJiZhLmhl
+aWdodD09Yi5oZWlnaHR9LApnaU86ZnVuY3Rpb24oYSl7cmV0dXJuIFcuckUoSi5oZihhLmxlZnQpLEou
+aGYoYS50b3ApLEouaGYoYS53aWR0aCksSi5oZihhLmhlaWdodCkpfX0KVy5yaC5wcm90b3R5cGU9ewpn
+QTpmdW5jdGlvbihhKXtyZXR1cm4gYS5sZW5ndGh9LApxOmZ1bmN0aW9uKGEsYil7SC5XWShiKQppZihi
+Pj4+MCE9PWJ8fGI+PWEubGVuZ3RoKXRocm93IEguYihQLnQoYixhLG51bGwsbnVsbCxudWxsKSkKcmV0
+dXJuIGFbYl19LApZOmZ1bmN0aW9uKGEsYixjKXt1LkEuYShjKQp0aHJvdyBILmIoUC5MNCgiQ2Fubm90
+IGFzc2lnbiBlbGVtZW50IG9mIGltbXV0YWJsZSBMaXN0LiIpKX0sCkU6ZnVuY3Rpb24oYSxiKXtpZihi
+PDB8fGI+PWEubGVuZ3RoKXJldHVybiBILmsoYSxiKQpyZXR1cm4gYVtiXX0sCiRpYlE6MSwKJGlYajox
+LAokaWNYOjEsCiRpek06MX0KVy5jZi5wcm90b3R5cGU9ewpLOmZ1bmN0aW9uKGEsYil7dmFyIHQscyxy
+LHEscAp1LmVBLmEoYikKZm9yKHQ9dGhpcy5nVigpLHM9dC5sZW5ndGgscj10aGlzLmEscT0wO3E8dC5s
+ZW5ndGg7dC5sZW5ndGg9PT1zfHwoMCxILmxrKSh0KSwrK3Epe3A9dFtxXQpiLiQyKHAsci5nZXRBdHRy
+aWJ1dGUocCkpfX0sCmdWOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10aGlzLmEuYXR0cmlidXRlcyxv
+PUguVk0oW10sdS5zKQpmb3IodD1wLmxlbmd0aCxzPXUuaDkscj0wO3I8dDsrK3Ipe2lmKHI+PXAubGVu
+Z3RoKXJldHVybiBILmsocCxyKQpxPXMuYShwW3JdKQppZihxLm5hbWVzcGFjZVVSST09bnVsbClDLk5t
+LmkobyxxLm5hbWUpfXJldHVybiBvfSwKZ2wwOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmdWKCkubGVu
+Z3RoPT09MH19ClcuaTcucHJvdG90eXBlPXsKeDQ6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuYS5oYXNB
+dHRyaWJ1dGUoYSl9LApxOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuYS5nZXRBdHRyaWJ1dGUoSC5j
+KGIpKX0sClk6ZnVuY3Rpb24oYSxiLGMpe3RoaXMuYS5zZXRBdHRyaWJ1dGUoYixjKX0sCmdBOmZ1bmN0
+aW9uKGEpe3JldHVybiB0aGlzLmdWKCkubGVuZ3RofX0KVy5TeS5wcm90b3R5cGU9ewp4NDpmdW5jdGlv
+bihhKXtyZXR1cm4gdGhpcy5hLmEuaGFzQXR0cmlidXRlKCJkYXRhLSIrdGhpcy5PKGEpKX0sCnE6ZnVu
+Y3Rpb24oYSxiKXtyZXR1cm4gdGhpcy5hLmEuZ2V0QXR0cmlidXRlKCJkYXRhLSIrdGhpcy5PKEguYyhi
+KSkpfSwKWTpmdW5jdGlvbihhLGIsYyl7dGhpcy5hLmEuc2V0QXR0cmlidXRlKCJkYXRhLSIrdGhpcy5P
+KGIpLGMpfSwKSzpmdW5jdGlvbihhLGIpe3RoaXMuYS5LKDAsbmV3IFcuS1ModGhpcyx1LmVBLmEoYikp
+KX0sCmdWOmZ1bmN0aW9uKCl7dmFyIHQ9SC5WTShbXSx1LnMpCnRoaXMuYS5LKDAsbmV3IFcuQTModGhp
+cyx0KSkKcmV0dXJuIHR9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nVigpLmxlbmd0aH0sCmds
+MDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5nVigpLmxlbmd0aD09PTB9LAprOmZ1bmN0aW9uKGEpe3Zh
+ciB0LHMscj1ILlZNKGEuc3BsaXQoIi0iKSx1LnMpCmZvcih0PTE7dDxyLmxlbmd0aDsrK3Qpe3M9clt0
+XQppZihzLmxlbmd0aD4wKUMuTm0uWShyLHQsc1swXS50b1VwcGVyQ2FzZSgpK0ouS1YocywxKSl9cmV0
+dXJuIEMuTm0uSChyLCIiKX0sCk86ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHEscApmb3IodD1hLmxlbmd0
+aCxzPTAscj0iIjtzPHQ7KytzKXtxPWFbc10KcD1xLnRvTG93ZXJDYXNlKCkKcj0ocSE9PXAmJnM+MD9y
+KyItIjpyKStwfXJldHVybiByLmNoYXJDb2RlQXQoMCk9PTA/cjpyfX0KVy5LUy5wcm90b3R5cGU9ewok
+MjpmdW5jdGlvbihhLGIpe2lmKEouclkoYSkubihhLCJkYXRhLSIpKXRoaXMuYi4kMih0aGlzLmEuayhD
+LnhCLkcoYSw1KSksYil9LAokUzoxNH0KVy5BMy5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe2lm
+KEouclkoYSkubihhLCJkYXRhLSIpKUMuTm0uaSh0aGlzLmIsdGhpcy5hLmsoQy54Qi5HKGEsNSkpKX0s
+CiRTOjE0fQpXLkk0LnByb3RvdHlwZT17Cnc6ZnVuY3Rpb24oKXt2YXIgdCxzLHIscSxwPVAuTHModS5O
+KQpmb3IodD10aGlzLmEuY2xhc3NOYW1lLnNwbGl0KCIgIikscz10Lmxlbmd0aCxyPTA7cjxzOysrcil7
+cT1KLlQwKHRbcl0pCmlmKHEubGVuZ3RoIT09MClwLmkoMCxxKX1yZXR1cm4gcH0sClg6ZnVuY3Rpb24o
+YSl7dGhpcy5hLmNsYXNzTmFtZT11LkMuYShhKS5IKDAsIiAiKX0sCmdBOmZ1bmN0aW9uKGEpe3JldHVy
+biB0aGlzLmEuY2xhc3NMaXN0Lmxlbmd0aH0sClYxOmZ1bmN0aW9uKGEpe3RoaXMuYS5jbGFzc05hbWU9
+IiJ9LAp0ZzpmdW5jdGlvbihhLGIpe3ZhciB0PXRoaXMuYS5jbGFzc0xpc3QuY29udGFpbnMoYikKcmV0
+dXJuIHR9LAppOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcy5hLmNsYXNzTGlzdCxzPXQuY29udGFpbnMo
+YikKdC5hZGQoYikKcmV0dXJuIXN9LApSOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcy5hLmNsYXNzTGlz
+dCxzPXQuY29udGFpbnMoYikKdC5yZW1vdmUoYikKcmV0dXJuIHN9LApGVjpmdW5jdGlvbihhLGIpe1cu
+VE4odGhpcy5hLHUuWC5hKGIpKX19ClcuRmsucHJvdG90eXBlPXt9ClcuUk8ucHJvdG90eXBlPXt9Clcu
+ZXUucHJvdG90eXBlPXt9ClcueEMucHJvdG90eXBlPXt9Clcudk4ucHJvdG90eXBlPXsKJDE6ZnVuY3Rp
+b24oYSl7cmV0dXJuIHRoaXMuYS4kMSh1LkIuYShhKSl9LAokUzoyN30KVy5KUS5wcm90b3R5cGU9ewpD
+WTpmdW5jdGlvbihhKXt2YXIgdAppZigkLm9yLmE9PT0wKXtmb3IodD0wO3Q8MjYyOysrdCkkLm9yLlko
+MCxDLmNtW3RdLFcucFMoKSkKZm9yKHQ9MDt0PDEyOysrdCkkLm9yLlkoMCxDLkJJW3RdLFcuVjQoKSl9
+fSwKaTA6ZnVuY3Rpb24oYSl7cmV0dXJuICQuQU4oKS50ZygwLFcuclMoYSkpfSwKRWI6ZnVuY3Rpb24o
+YSxiLGMpe3ZhciB0PSQub3IucSgwLEguZChXLnJTKGEpKSsiOjoiK2IpCmlmKHQ9PW51bGwpdD0kLm9y
+LnEoMCwiKjo6IitiKQppZih0PT1udWxsKXJldHVybiExCnJldHVybiBILkU5KHQuJDQoYSxiLGMsdGhp
+cykpfSwKJGlrRjoxfQpXLkdtLnByb3RvdHlwZT17CmdrejpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFcu
+VzkoYSx0aGlzLmdBKGEpLEgucShhKS5DKCJXOTxHbS5FPiIpKX19ClcudkQucHJvdG90eXBlPXsKaTA6
+ZnVuY3Rpb24oYSl7cmV0dXJuIEMuTm0uVnIodGhpcy5hLG5ldyBXLlV2KGEpKX0sCkViOmZ1bmN0aW9u
+KGEsYixjKXtyZXR1cm4gQy5ObS5Wcih0aGlzLmEsbmV3IFcuRWcoYSxiLGMpKX0sCiRpa0Y6MX0KVy5V
+di5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdS5lLmEoYSkuaTAodGhpcy5hKX0sCiRT
+OjE1fQpXLkVnLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB1LmUuYShhKS5FYih0aGlz
+LmEsdGhpcy5iLHRoaXMuYyl9LAokUzoxNX0KVy5tNi5wcm90b3R5cGU9ewpDWTpmdW5jdGlvbihhLGIs
+YyxkKXt2YXIgdCxzLHIKdGhpcy5hLkZWKDAsYykKdD1iLmV2KDAsbmV3IFcuRW8oKSkKcz1iLmV2KDAs
+bmV3IFcuV2soKSkKdGhpcy5iLkZWKDAsdCkKcj10aGlzLmMKci5GVigwLEMueEQpCnIuRlYoMCxzKX0s
+CmkwOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmEudGcoMCxXLnJTKGEpKX0sCkViOmZ1bmN0aW9uKGEs
+YixjKXt2YXIgdD10aGlzLHM9Vy5yUyhhKSxyPXQuYwppZihyLnRnKDAsSC5kKHMpKyI6OiIrYikpcmV0
+dXJuIHQuZC5EdChjKQplbHNlIGlmKHIudGcoMCwiKjo6IitiKSlyZXR1cm4gdC5kLkR0KGMpCmVsc2V7
+cj10LmIKaWYoci50ZygwLEguZChzKSsiOjoiK2IpKXJldHVybiEwCmVsc2UgaWYoci50ZygwLCIqOjoi
+K2IpKXJldHVybiEwCmVsc2UgaWYoci50ZygwLEguZChzKSsiOjoqIikpcmV0dXJuITAKZWxzZSBpZihy
+LnRnKDAsIio6OioiKSlyZXR1cm4hMH1yZXR1cm4hMX0sCiRpa0Y6MX0KVy5Fby5wcm90b3R5cGU9ewok
+MTpmdW5jdGlvbihhKXtyZXR1cm4hQy5ObS50ZyhDLkJJLEguYyhhKSl9LAokUzo3fQpXLldrLnByb3Rv
+dHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiBDLk5tLnRnKEMuQkksSC5jKGEpKX0sCiRTOjd9Clcu
+Y3QucHJvdG90eXBlPXsKRWI6ZnVuY3Rpb24oYSxiLGMpe2lmKHRoaXMuakYoYSxiLGMpKXJldHVybiEw
+CmlmKGI9PT0idGVtcGxhdGUiJiZjPT09IiIpcmV0dXJuITAKaWYoYS5nZXRBdHRyaWJ1dGUoInRlbXBs
+YXRlIik9PT0iIilyZXR1cm4gdGhpcy5lLnRnKDAsYikKcmV0dXJuITF9fQpXLklBLnByb3RvdHlwZT17
+CiQxOmZ1bmN0aW9uKGEpe3JldHVybiJURU1QTEFURTo6IitILmQoSC5jKGEpKX0sCiRTOjV9ClcuT3cu
+cHJvdG90eXBlPXsKaTA6ZnVuY3Rpb24oYSl7dmFyIHQKaWYodS5hTy5iKGEpKXJldHVybiExCnQ9dS5n
+Ny5iKGEpCmlmKHQmJlcuclMoYSk9PT0iZm9yZWlnbk9iamVjdCIpcmV0dXJuITEKaWYodClyZXR1cm4h
+MApyZXR1cm4hMX0sCkViOmZ1bmN0aW9uKGEsYixjKXtpZihiPT09ImlzInx8Qy54Qi5uKGIsIm9uIikp
+cmV0dXJuITEKcmV0dXJuIHRoaXMuaTAoYSl9LAokaWtGOjF9ClcuVzkucHJvdG90eXBlPXsKRjpmdW5j
+dGlvbigpe3ZhciB0PXRoaXMscz10LmMrMSxyPXQuYgppZihzPHIpe3Quc3AoSi54OSh0LmEscykpCnQu
+Yz1zCnJldHVybiEwfXQuc3AobnVsbCkKdC5jPXIKcmV0dXJuITF9LApnbDpmdW5jdGlvbigpe3JldHVy
+biB0aGlzLmR9LApzcDpmdW5jdGlvbihhKXt0aGlzLmQ9dGhpcy4kdGkuYy5hKGEpfSwKJGlBbjoxfQpX
+LmRXLnByb3RvdHlwZT17CmdtVzpmdW5jdGlvbihhKXtyZXR1cm4gVy5ISCh0aGlzLmEubG9jYXRpb24p
+fSwKJGlEMDoxLAokaXY2OjF9ClcuRmIucHJvdG90eXBlPXt9Clcua0YucHJvdG90eXBlPXt9ClcubWsu
+cHJvdG90eXBlPXskaXkwOjF9ClcuS28ucHJvdG90eXBlPXsKUG46ZnVuY3Rpb24oYSl7dmFyIHQ9dGhp
+cyxzPW5ldyBXLmZtKHQpCnQuYj0hMQpzLiQyKGEsbnVsbCkKZm9yKDt0LmI7KXt0LmI9ITEKcy4kMihh
+LG51bGwpfX0sCkVQOmZ1bmN0aW9uKGEsYil7dmFyIHQ9dGhpcy5iPSEwCmlmKGIhPW51bGw/YiE9PWEu
+cGFyZW50Tm9kZTp0KUouTHQoYSkKZWxzZSBiLnJlbW92ZUNoaWxkKGEpfSwKSTQ6ZnVuY3Rpb24oYSxi
+KXt2YXIgdCxzLHIscSxwLG89ITAsbj1udWxsLG09bnVsbAp0cnl7bj1KLmlnKGEpCm09bi5hLmdldEF0
+dHJpYnV0ZSgiaXMiKQp1LmguYShhKQp0PWZ1bmN0aW9uKGMpe2lmKCEoYy5hdHRyaWJ1dGVzIGluc3Rh
+bmNlb2YgTmFtZWROb2RlTWFwKSlyZXR1cm4gdHJ1ZQppZihjLmlkPT0nbGFzdENoaWxkJ3x8Yy5uYW1l
+PT0nbGFzdENoaWxkJ3x8Yy5pZD09J3ByZXZpb3VzU2libGluZyd8fGMubmFtZT09J3ByZXZpb3VzU2li
+bGluZyd8fGMuaWQ9PSdjaGlsZHJlbid8fGMubmFtZT09J2NoaWxkcmVuJylyZXR1cm4gdHJ1ZQp2YXIg
+bD1jLmNoaWxkTm9kZXMKaWYoYy5sYXN0Q2hpbGQmJmMubGFzdENoaWxkIT09bFtsLmxlbmd0aC0xXSly
+ZXR1cm4gdHJ1ZQppZihjLmNoaWxkcmVuKWlmKCEoYy5jaGlsZHJlbiBpbnN0YW5jZW9mIEhUTUxDb2xs
+ZWN0aW9ufHxjLmNoaWxkcmVuIGluc3RhbmNlb2YgTm9kZUxpc3QpKXJldHVybiB0cnVlCnZhciBrPTAK
+aWYoYy5jaGlsZHJlbilrPWMuY2hpbGRyZW4ubGVuZ3RoCmZvcih2YXIgaj0wO2o8aztqKyspe3ZhciBp
+PWMuY2hpbGRyZW5bal0KaWYoaS5pZD09J2F0dHJpYnV0ZXMnfHxpLm5hbWU9PSdhdHRyaWJ1dGVzJ3x8
+aS5pZD09J2xhc3RDaGlsZCd8fGkubmFtZT09J2xhc3RDaGlsZCd8fGkuaWQ9PSdwcmV2aW91c1NpYmxp
+bmcnfHxpLm5hbWU9PSdwcmV2aW91c1NpYmxpbmcnfHxpLmlkPT0nY2hpbGRyZW4nfHxpLm5hbWU9PSdj
+aGlsZHJlbicpcmV0dXJuIHRydWV9cmV0dXJuIGZhbHNlfShhKQpvPUgub1QodCk/ITA6IShhLmF0dHJp
+YnV0ZXMgaW5zdGFuY2VvZiBOYW1lZE5vZGVNYXApfWNhdGNoKHEpe0guUnUocSl9cz0iZWxlbWVudCB1
+bnByaW50YWJsZSIKdHJ5e3M9Si5BYyhhKX1jYXRjaChxKXtILlJ1KHEpfXRyeXtyPVcuclMoYSkKdGhp
+cy5rUih1LmguYShhKSxiLG8scyxyLHUuRy5hKG4pLEguYyhtKSl9Y2F0Y2gocSl7aWYoSC5SdShxKSBp
+bnN0YW5jZW9mIFAuQVQpdGhyb3cgcQplbHNle3RoaXMuRVAoYSxiKQp3aW5kb3cKcD0iUmVtb3Zpbmcg
+Y29ycnVwdGVkIGVsZW1lbnQgIitILmQocykKaWYodHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdp
+bmRvdy5jb25zb2xlLndhcm4ocCl9fX0sCmtSOmZ1bmN0aW9uKGEsYixjLGQsZSxmLGcpe3ZhciB0LHMs
+cixxLHAsbyxuPXRoaXMKaWYoYyl7bi5FUChhLGIpCndpbmRvdwp0PSJSZW1vdmluZyBlbGVtZW50IGR1
+ZSB0byBjb3JydXB0ZWQgYXR0cmlidXRlcyBvbiA8IitkKyI+IgppZih0eXBlb2YgY29uc29sZSE9InVu
+ZGVmaW5lZCIpd2luZG93LmNvbnNvbGUud2Fybih0KQpyZXR1cm59aWYoIW4uYS5pMChhKSl7bi5FUChh
+LGIpCndpbmRvdwp0PSJSZW1vdmluZyBkaXNhbGxvd2VkIGVsZW1lbnQgPCIrSC5kKGUpKyI+IGZyb20g
+IitILmQoYikKaWYodHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLndhcm4o
+dCkKcmV0dXJufWlmKGchPW51bGwpaWYoIW4uYS5FYihhLCJpcyIsZykpe24uRVAoYSxiKQp3aW5kb3cK
+dD0iUmVtb3ZpbmcgZGlzYWxsb3dlZCB0eXBlIGV4dGVuc2lvbiA8IitILmQoZSkrJyBpcz0iJytnKyci
+PicKaWYodHlwZW9mIGNvbnNvbGUhPSJ1bmRlZmluZWQiKXdpbmRvdy5jb25zb2xlLndhcm4odCkKcmV0
+dXJufXQ9Zi5nVigpCnM9SC5WTSh0LnNsaWNlKDApLEgudDYodCkuQygiamQ8MT4iKSkKZm9yKHI9Zi5n
+VigpLmxlbmd0aC0xLHQ9Zi5hO3I+PTA7LS1yKXtpZihyPj1zLmxlbmd0aClyZXR1cm4gSC5rKHMscikK
+cT1zW3JdCnA9bi5hCm89Si5jSChxKQpILmMocSkKaWYoIXAuRWIoYSxvLHQuZ2V0QXR0cmlidXRlKHEp
+KSl7d2luZG93CnA9IlJlbW92aW5nIGRpc2FsbG93ZWQgYXR0cmlidXRlIDwiK0guZChlKSsiICIrcSsn
+PSInK0guZCh0LmdldEF0dHJpYnV0ZShxKSkrJyI+JwppZih0eXBlb2YgY29uc29sZSE9InVuZGVmaW5l
+ZCIpd2luZG93LmNvbnNvbGUud2FybihwKQp0LnJlbW92ZUF0dHJpYnV0ZShxKX19aWYodS5hVy5iKGEp
+KW4uUG4oYS5jb250ZW50KX0sCiRpb246MX0KVy5mbS5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIp
+e3ZhciB0LHMscixxLHAsbyxuPXRoaXMuYQpzd2l0Y2goYS5ub2RlVHlwZSl7Y2FzZSAxOm4uSTQoYSxi
+KQpicmVhawpjYXNlIDg6Y2FzZSAxMTpjYXNlIDM6Y2FzZSA0OmJyZWFrCmRlZmF1bHQ6bi5FUChhLGIp
+fXQ9YS5sYXN0Q2hpbGQKZm9yKHI9dS5BO251bGwhPXQ7KXtzPW51bGwKdHJ5e3M9dC5wcmV2aW91c1Np
+YmxpbmcKaWYocyE9bnVsbCl7cT1zLm5leHRTaWJsaW5nCnA9dApwPXE9PW51bGw/cCE9bnVsbDpxIT09
+cApxPXB9ZWxzZSBxPSExCmlmKHEpe3E9UC5QVigiQ29ycnVwdCBIVE1MIikKdGhyb3cgSC5iKHEpfX1j
+YXRjaChvKXtILlJ1KG8pCnE9ci5hKHQpCm4uYj0hMApwPXEucGFyZW50Tm9kZQpwPWE9PW51bGw/cCE9
+bnVsbDphIT09cAppZihwKXtwPXEucGFyZW50Tm9kZQppZihwIT1udWxsKXAucmVtb3ZlQ2hpbGQocSl9
+ZWxzZSBhLnJlbW92ZUNoaWxkKHEpCnQ9bnVsbApzPWEubGFzdENoaWxkfWlmKHQhPW51bGwpdGhpcy4k
+Mih0LGEpCnQ9c319LAokUzozMH0KVy5MZS5wcm90b3R5cGU9e30KVy5LNy5wcm90b3R5cGU9e30KVy5y
+Qi5wcm90b3R5cGU9e30KVy5YVy5wcm90b3R5cGU9e30KVy5vYS5wcm90b3R5cGU9e30KUC5pSi5wcm90
+b3R5cGU9ewpWSDpmdW5jdGlvbihhKXt2YXIgdCxzPXRoaXMuYSxyPXMubGVuZ3RoCmZvcih0PTA7dDxy
+OysrdClpZihzW3RdPT09YSlyZXR1cm4gdApDLk5tLmkocyxhKQpDLk5tLmkodGhpcy5iLG51bGwpCnJl
+dHVybiByfSwKUHY6ZnVuY3Rpb24oYSl7dmFyIHQscyxyLHE9dGhpcyxwPXt9CmlmKGE9PW51bGwpcmV0
+dXJuIGEKaWYoSC5yUShhKSlyZXR1cm4gYQppZih0eXBlb2YgYT09Im51bWJlciIpcmV0dXJuIGEKaWYo
+dHlwZW9mIGE9PSJzdHJpbmciKXJldHVybiBhCmlmKGEgaW5zdGFuY2VvZiBQLmlQKXJldHVybiBuZXcg
+RGF0ZShhLmEpCmlmKHUuZnYuYihhKSl0aHJvdyBILmIoUC5uKCJzdHJ1Y3R1cmVkIGNsb25lIG9mIFJl
+Z0V4cCIpKQppZih1LmM4LmIoYSkpcmV0dXJuIGEKaWYodS5kLmIoYSkpcmV0dXJuIGEKaWYodS5JLmIo
+YSkpcmV0dXJuIGEKdD11LmRELmIoYSl8fCExCmlmKHQpcmV0dXJuIGEKaWYodS5HLmIoYSkpe3M9cS5W
+SChhKQp0PXEuYgppZihzPj10Lmxlbmd0aClyZXR1cm4gSC5rKHQscykKcj1wLmE9dFtzXQppZihyIT1u
+dWxsKXJldHVybiByCnI9e30KcC5hPXIKQy5ObS5ZKHQscyxyKQphLksoMCxuZXcgUC5qZyhwLHEpKQpy
+ZXR1cm4gcC5hfWlmKHUuai5iKGEpKXtzPXEuVkgoYSkKcD1xLmIKaWYocz49cC5sZW5ndGgpcmV0dXJu
+IEguayhwLHMpCnI9cFtzXQppZihyIT1udWxsKXJldHVybiByCnJldHVybiBxLmVrKGEscyl9aWYodS5l
+SC5iKGEpKXtzPXEuVkgoYSkKdD1xLmIKaWYocz49dC5sZW5ndGgpcmV0dXJuIEguayh0LHMpCnI9cC5i
+PXRbc10KaWYociE9bnVsbClyZXR1cm4gcgpyPXt9CnAuYj1yCkMuTm0uWSh0LHMscikKcS5pbShhLG5l
+dyBQLlRhKHAscSkpCnJldHVybiBwLmJ9dGhyb3cgSC5iKFAubigic3RydWN0dXJlZCBjbG9uZSBvZiBv
+dGhlciB0eXBlIikpfSwKZWs6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPUouVTYoYSkscj1zLmdBKGEpLHE9
+bmV3IEFycmF5KHIpCkMuTm0uWSh0aGlzLmIsYixxKQpmb3IodD0wO3Q8cjsrK3QpQy5ObS5ZKHEsdCx0
+aGlzLlB2KHMucShhLHQpKSkKcmV0dXJuIHF9fQpQLmpnLnByb3RvdHlwZT17CiQyOmZ1bmN0aW9uKGEs
+Yil7dGhpcy5hLmFbYV09dGhpcy5iLlB2KGIpfSwKJFM6NH0KUC5UYS5wcm90b3R5cGU9ewokMjpmdW5j
+dGlvbihhLGIpe3RoaXMuYS5iW2FdPXRoaXMuYi5QdihiKX0sCiRTOjR9ClAuQmYucHJvdG90eXBlPXsK
+aW06ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscQp1LmI4LmEoYikKZm9yKHQ9T2JqZWN0LmtleXMoYSks
+cz10Lmxlbmd0aCxyPTA7cjxzOysrcil7cT10W3JdCmIuJDIocSxhW3FdKX19fQpQLkFzLnByb3RvdHlw
+ZT17ClQ6ZnVuY3Rpb24oYSl7dmFyIHQKSC5jKGEpCnQ9JC5oRygpLmIKaWYodHlwZW9mIGEhPSJzdHJp
+bmciKUgudmgoSC5JKGEpKQppZih0LnRlc3QoYSkpcmV0dXJuIGEKdGhyb3cgSC5iKFAuTDMoYSwidmFs
+dWUiLCJOb3QgYSB2YWxpZCBjbGFzcyB0b2tlbiIpKX0sClo6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMu
+dygpLkgoMCwiICIpfSwKZ2t6OmZ1bmN0aW9uKGEpe3ZhciB0PXRoaXMudygpCnJldHVybiBQLnJqKHQs
+dC5yLEguTGgodCkuYyl9LApnQTpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy53KCkuYX0sCnRnOmZ1bmN0
+aW9uKGEsYil7dGhpcy5UKGIpCnJldHVybiB0aGlzLncoKS50ZygwLGIpfSwKaTpmdW5jdGlvbihhLGIp
+e3RoaXMuVChiKQpyZXR1cm4gSC5FOSh0aGlzLk9TKG5ldyBQLkdFKGIpKSl9LApSOmZ1bmN0aW9uKGEs
+Yil7dmFyIHQscwp0aGlzLlQoYikKdD10aGlzLncoKQpzPXQuUigwLGIpCnRoaXMuWCh0KQpyZXR1cm4g
+c30sCkZWOmZ1bmN0aW9uKGEsYil7dGhpcy5PUyhuZXcgUC5ONyh0aGlzLHUuWC5hKGIpKSl9LApWMTpm
+dW5jdGlvbihhKXt0aGlzLk9TKG5ldyBQLnVRKCkpfSwKT1M6ZnVuY3Rpb24oYSl7dmFyIHQscwp1LmJV
+LmEoYSkKdD10aGlzLncoKQpzPWEuJDEodCkKdGhpcy5YKHQpCnJldHVybiBzfX0KUC5HRS5wcm90b3R5
+cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdS5DLmEoYSkuaSgwLHRoaXMuYSl9LAokUzozMX0KUC5O
+Ny5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdD10aGlzLmIscz1ILnQ2KHQpCnJldHVybiB1
+LkMuYShhKS5GVigwLG5ldyBILmxKKHQscy5DKCJxVSgxKSIpLmEodGhpcy5hLmd1TSgpKSxzLkMoImxK
+PDEscVU+IikpKX0sCiRTOjExfQpQLnVRLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3UuQy5hKGEp
+CmlmKGEuYT4wKXthLmI9YS5jPWEuZD1hLmU9YS5mPW51bGwKYS5hPTAKYS5TKCl9cmV0dXJuIG51bGx9
+LAokUzoxMX0KUC5oRi5wcm90b3R5cGU9eyRpaEY6MX0KUC5QQy5wcm90b3R5cGU9ewokMTpmdW5jdGlv
+bihhKXt2YXIgdAp1LlouYShhKQp0PWZ1bmN0aW9uKGIsYyxkKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1
+cm4gYihjLGQsdGhpcyxBcnJheS5wcm90b3R5cGUuc2xpY2UuYXBwbHkoYXJndW1lbnRzKSl9fShQLlI0
+LGEsITEpClAuRG0odCwkLndRKCksYSkKcmV0dXJuIHR9LAokUzoxfQpQLm10LnByb3RvdHlwZT17CiQx
+OmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgdGhpcy5hKGEpfSwKJFM6MX0KUC5Oei5wcm90b3R5cGU9ewok
+MTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAucjcoYSl9LAokUzozM30KUC5RUy5wcm90b3R5cGU9ewok
+MTpmdW5jdGlvbihhKXtyZXR1cm4gbmV3IFAuVHooYSx1LmFtKX0sCiRTOjM0fQpQLm5wLnByb3RvdHlw
+ZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiBuZXcgUC5FNChhKX0sCiRTOjM1fQpQLkU0LnByb3RvdHlw
+ZT17CnE6ZnVuY3Rpb24oYSxiKXtpZih0eXBlb2YgYiE9InN0cmluZyImJnR5cGVvZiBiIT0ibnVtYmVy
+Iil0aHJvdyBILmIoUC54WSgicHJvcGVydHkgaXMgbm90IGEgU3RyaW5nIG9yIG51bSIpKQpyZXR1cm4g
+UC5MNyh0aGlzLmFbYl0pfSwKWTpmdW5jdGlvbihhLGIsYyl7aWYodHlwZW9mIGIhPSJzdHJpbmciJiZ0
+eXBlb2YgYiE9Im51bWJlciIpdGhyb3cgSC5iKFAueFkoInByb3BlcnR5IGlzIG5vdCBhIFN0cmluZyBv
+ciBudW0iKSkKdGhpcy5hW2JdPVAud1koYyl9LApETjpmdW5jdGlvbihhLGIpe2lmKGI9PW51bGwpcmV0
+dXJuITEKcmV0dXJuIGIgaW5zdGFuY2VvZiBQLkU0JiZ0aGlzLmE9PT1iLmF9LApaOmZ1bmN0aW9uKGEp
+e3ZhciB0LHMKdHJ5e3Q9U3RyaW5nKHRoaXMuYSkKcmV0dXJuIHR9Y2F0Y2gocyl7SC5SdShzKQp0PXRo
+aXMueGIoMCkKcmV0dXJuIHR9fSwKVjc6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzPXRoaXMuYQppZihiPT1u
+dWxsKXQ9bnVsbAplbHNle3Q9SC50NihiKQp0PVAuQ0gobmV3IEgubEooYix0LkMoIkAoMSkiKS5hKFAu
+aUcoKSksdC5DKCJsSjwxLEA+IikpLCEwLHUueil9cmV0dXJuIFAuTDcoc1thXS5hcHBseShzLHQpKX0s
+CmdpTzpmdW5jdGlvbihhKXtyZXR1cm4gMH19ClAucjcucHJvdG90eXBlPXt9ClAuVHoucHJvdG90eXBl
+PXsKY1A6ZnVuY3Rpb24oYSl7dmFyIHQ9dGhpcyxzPWE8MHx8YT49dC5nQSh0KQppZihzKXRocm93IEgu
+YihQLlRFKGEsMCx0LmdBKHQpLG51bGwsbnVsbCkpfSwKcTpmdW5jdGlvbihhLGIpe2lmKHR5cGVvZiBi
+PT0ibnVtYmVyIiYmYj09PUMuam4ueXUoYikpdGhpcy5jUChILldZKGIpKQpyZXR1cm4gdGhpcy4kdGku
+Yy5hKHRoaXMuVXIoMCxiKSl9LApZOmZ1bmN0aW9uKGEsYixjKXt2YXIgdAp0aGlzLiR0aS5jLmEoYykK
+dD1DLmpuLnl1KGIpCmlmKGI9PT10KXRoaXMuY1AoYikKdGhpcy5lNCgwLGIsYyl9LApnQTpmdW5jdGlv
+bihhKXt2YXIgdD10aGlzLmEubGVuZ3RoCmlmKHR5cGVvZiB0PT09Im51bWJlciImJnQ+Pj4wPT09dCly
+ZXR1cm4gdAp0aHJvdyBILmIoUC5QVigiQmFkIEpzQXJyYXkgbGVuZ3RoIikpfSwKJGliUToxLAokaWNY
+OjEsCiRpek06MX0KUC5jby5wcm90b3R5cGU9e30KUC5uZC5wcm90b3R5cGU9eyRpbmQ6MX0KUC5LZS5w
+cm90b3R5cGU9ewp3OmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10aGlzLmEuZ2V0QXR0cmlidXRlKCJj
+bGFzcyIpLG89UC5Mcyh1Lk4pCmlmKHA9PW51bGwpcmV0dXJuIG8KZm9yKHQ9cC5zcGxpdCgiICIpLHM9
+dC5sZW5ndGgscj0wO3I8czsrK3Ipe3E9Si5UMCh0W3JdKQppZihxLmxlbmd0aCE9PTApby5pKDAscSl9
+cmV0dXJuIG99LApYOmZ1bmN0aW9uKGEpe3RoaXMuYS5zZXRBdHRyaWJ1dGUoImNsYXNzIixhLkgoMCwi
+ICIpKX19ClAuZDUucHJvdG90eXBlPXsKZ1A6ZnVuY3Rpb24oYSl7cmV0dXJuIG5ldyBQLktlKGEpfSwK
+c2hmOmZ1bmN0aW9uKGEsYil7dGhpcy5ZQyhhLGIpfSwKcjY6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIHQs
+cyxyLHEscCxvCmlmKGQ9PW51bGwpe3Q9SC5WTShbXSx1LmkpCmQ9bmV3IFcudkQodCkKQy5ObS5pKHQs
+Vy5UdyhudWxsKSkKQy5ObS5pKHQsVy5CbCgpKQpDLk5tLmkodCxuZXcgVy5PdygpKX1jPW5ldyBXLktv
+KGQpCnM9JzxzdmcgdmVyc2lvbj0iMS4xIj4nK0guZChiKSsiPC9zdmc+Igp0PWRvY3VtZW50CnI9dC5i
+b2R5CnE9KHImJkMuUlkpLkFIKHIscyxjKQpwPXQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpCnEudG9T
+dHJpbmcKdD1uZXcgVy5lNyhxKQpvPXQuZ3I4KHQpCmZvcig7dD1vLmZpcnN0Q2hpbGQsdCE9bnVsbDsp
+cC5hcHBlbmRDaGlsZCh0KQpyZXR1cm4gcH0sCm56OmZ1bmN0aW9uKGEsYixjLGQsZSl7dGhyb3cgSC5i
+KFAuTDQoIkNhbm5vdCBpbnZva2UgaW5zZXJ0QWRqYWNlbnRIdG1sIG9uIFNWRy4iKSl9LApnVmw6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIG5ldyBXLmV1KGEsImNsaWNrIiwhMSx1LlEpfSwKJGlkNToxfQpQLm42LnBy
+b3RvdHlwZT17JGliUToxLCRpY1g6MSwkaXpNOjEsJGllcToxfQpNLkg3LnByb3RvdHlwZT17Clo6ZnVu
+Y3Rpb24oYSl7cmV0dXJuIHRoaXMuYn19ClUuTEwucHJvdG90eXBlPXsKTHQ6ZnVuY3Rpb24oKXtyZXR1
+cm4gUC5FRihbIm5vZGVJZCIsdGhpcy5iLCJraW5kIix0aGlzLmEuYV0sdS5OLHUuSyl9fQpVLk1ELnBy
+b3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB1LmdwLmEoYSkuYT09PXRoaXMuYS5xKDAsImtp
+bmQiKX0sCiRTOjM2fQpVLmQyLnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscD10
+aGlzLG89dS5OLG49dS5LLG09UC5GbChvLG4pLGw9cC5hCmlmKGwhPW51bGwpe3Q9SC5WTShbXSx1Lkop
+CmZvcihzPWwubGVuZ3RoLHI9MDtyPGwubGVuZ3RoO2wubGVuZ3RoPT09c3x8KDAsSC5saykobCksKyty
+KXtxPWxbcl0KQy5ObS5pKHQsUC5FRihbImRlc2NyaXB0aW9uIixxLmEsImhyZWYiLHEuYl0sbyxuKSl9
+bS5ZKDAsImVkaXRzIix0KX1tLlkoMCwiZXhwbGFuYXRpb24iLHAuYikKbS5ZKDAsImxpbmUiLHAuYykK
+bS5ZKDAsImRpc3BsYXlQYXRoIixwLmQpCm0uWSgwLCJ1cmlQYXRoIixwLmUpCm89cC5mCmlmKG8hPW51
+bGwpe249SC5WTShbXSx1LkopCmZvcihsPW8ubGVuZ3RoLHI9MDtyPG8ubGVuZ3RoO28ubGVuZ3RoPT09
+bHx8KDAsSC5saykobyksKytyKUMuTm0uaShuLG9bcl0uTHQoKSkKbS5ZKDAsInRyYWNlcyIsbil9cmV0
+dXJuIG19fQpVLlNlLnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7cmV0dXJuIFAuRUYoWyJkZXNjcmlw
+dGlvbiIsdGhpcy5hLCJocmVmIix0aGlzLmJdLHUuTix1LkspfX0KVS5NbC5wcm90b3R5cGU9ewpMdDpm
+dW5jdGlvbigpe3JldHVybiBQLkVGKFsiaHJlZiIsdGhpcy5hLCJsaW5lIix0aGlzLmIsInBhdGgiLHRo
+aXMuY10sdS5OLHUuSyl9fQpVLnlELnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7dmFyIHQscyxyLHE9
+SC5WTShbXSx1LkopCmZvcih0PXRoaXMuYixzPXQubGVuZ3RoLHI9MDtyPHQubGVuZ3RoO3QubGVuZ3Ro
+PT09c3x8KDAsSC5saykodCksKytyKUMuTm0uaShxLHRbcl0uTHQoKSkKcmV0dXJuIFAuRUYoWyJkZXNj
+cmlwdGlvbiIsdGhpcy5hLCJlbnRyaWVzIixxXSx1Lk4sdS5LKX19ClUud2IucHJvdG90eXBlPXsKTHQ6
+ZnVuY3Rpb24oKXt2YXIgdCxzLHI9dGhpcyxxPVAuRmwodS5OLHUuSykKcS5ZKDAsImRlc2NyaXB0aW9u
+IixyLmEpCnQ9ci5iCmlmKHQhPW51bGwpcS5ZKDAsImZ1bmN0aW9uIix0KQp0PXIuYwppZih0IT1udWxs
+KXEuWSgwLCJsaW5rIix0Lkx0KCkpCnQ9ci5kCmlmKHQubGVuZ3RoIT09MCl7cz1ILnQ2KHQpCnEuWSgw
+LCJoaW50QWN0aW9ucyIsbmV3IEgubEoodCxzLkMoIlowPHFVLE1oPigxKSIpLmEobmV3IFUuYjAoKSks
+cy5DKCJsSjwxLFowPHFVLE1oPj4iKSkuYnIoMCkpfXJldHVybiBxfX0KVS5hTi5wcm90b3R5cGU9ewok
+MTpmdW5jdGlvbihhKXtyZXR1cm4gVS5ueih1LlMuYShhKSl9LAokUzozN30KVS5iMC5wcm90b3R5cGU9
+ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gdS5FLmEoYSkuTHQoKX0sCiRTOjM4fQpCLmo4LnByb3RvdHlw
+ZT17Ckx0OmZ1bmN0aW9uKCl7cmV0dXJuIFAuRUYoWyJsaW5lIix0aGlzLmEsImV4cGxhbmF0aW9uIix0
+aGlzLmIsIm9mZnNldCIsdGhpcy5jXSx1Lk4sdS5LKX19CkIucXAucHJvdG90eXBlPXsKTHQ6ZnVuY3Rp
+b24oKXt2YXIgdCxzLHIscSxwLG8sbixtPXRoaXMsbD11Lk4saz1QLkZsKGwsdS5kMykKZm9yKHQ9bS5k
+LHQ9dC5nUHUodCksdD10Lmdreih0KSxzPXUuSyxyPXUuSjt0LkYoKTspe3E9dC5nbCgpCnA9cS5hCm89
+SC5WTShbXSxyKQpmb3IocT1KLklUKHEuYik7cS5GKCk7KXtuPXEuZ2woKQpDLk5tLmkobyxQLkVGKFsi
+bGluZSIsbi5hLCJleHBsYW5hdGlvbiIsbi5iLCJvZmZzZXQiLG4uY10sbCxzKSl9ay5ZKDAscCxvKX1y
+ZXR1cm4gUC5FRihbInJlZ2lvbnMiLG0uYSwibmF2aWdhdGlvbkNvbnRlbnQiLG0uYiwic291cmNlQ29k
+ZSIsbS5jLCJlZGl0cyIsa10sbCxzKX19ClQubVEucHJvdG90eXBlPXt9CkwuZS5wcm90b3R5cGU9ewok
+MTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscSxwLG8sbgp1LkIuYShhKQp0PXdpbmRvdy5sb2NhdGlvbi5w
+YXRobmFtZQpzPUwuRzYod2luZG93LmxvY2F0aW9uLmhyZWYpCnI9TC5hSyh3aW5kb3cubG9jYXRpb24u
+aHJlZikKTC5HZSgpCmlmKHQhPT0iLyImJnQhPT1KLlQwKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoIi5y
+b290IikudGV4dENvbnRlbnQpKUwuRzcodCxzLHIsITAsbmV3IEwuVlcodCxzLHIpKQpxPWRvY3VtZW50
+CnA9Si5xRihxLnF1ZXJ5U2VsZWN0b3IoIi5hcHBseS1taWdyYXRpb24iKSkKbz1wLiR0aQpuPW8uQygi
+figxKSIpLmEobmV3IEwub1ooKSkKdS5NLmEobnVsbCkKVy5KRShwLmEscC5iLG4sITEsby5jKQpvPUou
+cUYocS5xdWVyeVNlbGVjdG9yKCIucmVydW4tbWlncmF0aW9uIikpCm49by4kdGkKVy5KRShvLmEsby5i
+LG4uQygifigxKSIpLmEobmV3IEwueTgoKSksITEsbi5jKQpuPUoucUYocS5xdWVyeVNlbGVjdG9yKCIu
+cmVwb3J0LXByb2JsZW0iKSkKbz1uLiR0aQpXLkpFKG4uYSxuLmIsby5DKCJ+KDEpIikuYShuZXcgTC5I
+aSgpKSwhMSxvLmMpCnE9Si5xRihxLnF1ZXJ5U2VsZWN0b3IoIi5wb3B1cC1wYW5lIC5jbG9zZSIpKQpv
+PXEuJHRpClcuSkUocS5hLHEuYixvLkMoIn4oMSkiKS5hKG5ldyBMLkJUKCkpLCExLG8uYyl9LAokUzox
+Nn0KTC5WVy5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuRnIodGhpcy5hLHRoaXMuYix0aGlzLmMp
+fSwKJFM6MH0KTC5vWi5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscQp1LlYuYShh
+KQppZihILm9UKHdpbmRvdy5jb25maXJtKCJUaGlzIHdpbGwgYXBwbHkgdGhlIGNoYW5nZXMgeW91J3Zl
+IHByZXZpZXdlZCB0byB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5LiBJdCBpcyByZWNvbW1lbmRlZCB5b3Ug
+Y29tbWl0IGFueSBjaGFuZ2VzIHlvdSBtYWRlIGJlZm9yZSBkb2luZyB0aGlzLiIpKSl7dD1MLnR5KCIv
+YXBwbHktbWlncmF0aW9uIixudWxsKS5XNyhuZXcgTC5qcigpLHUuUCkKcz1uZXcgTC5xbCgpCnUuYmYu
+YShudWxsKQpyPXQuJHRpCnE9JC5YMwppZihxIT09Qy5OVSlzPVAuVkgocyxxKQp0LnhmKG5ldyBQLkZl
+KG5ldyBQLnZzKHEsciksMixudWxsLHMsci5DKCJAPDE+IikuS3Eoci5jKS5DKCJGZTwxLDI+IikpKX19
+LAokUzozfQpMLmpyLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0CnUuUy5hKGEpCnQ9ZG9j
+dW1lbnQuYm9keQp0LmNsYXNzTGlzdC5yZW1vdmUoInByb3Bvc2VkIikKdC5jbGFzc0xpc3QuYWRkKCJh
+cHBsaWVkIil9LAokUzo0MX0KTC5xbC5wcm90b3R5cGU9ewokMjpmdW5jdGlvbihhLGIpe0wuQzIoIkNv
+dWxkIG5vdCBhcHBseSBtaWdyYXRpb24iLGEsYil9LAokQzoiJDIiLAokUjoyLAokUzo0fQpMLnk4LnBy
+b3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnhuKHUuVi5hKGEpKX0sCnhuOmZ1bmN0
+aW9uKGEpe3ZhciB0PTAscz1QLkZYKHUuUCkscj0xLHEscD1bXSxvLG4sbSxsCnZhciAkYXN5bmMkJDE9
+UC5seihmdW5jdGlvbihiLGMpe2lmKGI9PT0xKXtxPWMKdD1yfXdoaWxlKHRydWUpc3dpdGNoKHQpe2Nh
+c2UgMDpyPTMKZG9jdW1lbnQuYm9keS5jbGFzc0xpc3QuYWRkKCJyZXJ1bm5pbmciKQp0PTYKcmV0dXJu
+IFAualEoTC50eSgiL3JlcnVuLW1pZ3JhdGlvbiIsbnVsbCksJGFzeW5jJCQxKQpjYXNlIDY6d2luZG93
+LmxvY2F0aW9uLnJlbG9hZCgpCnAucHVzaCg1KQp0PTQKYnJlYWsKY2FzZSAzOnI9MgpsPXEKbz1ILlJ1
+KGwpCm49SC50cyhsKQpMLkMyKCJGYWlsZWQgdG8gcmVydW4gbWlncmF0aW9uIixvLG4pCnAucHVzaCg1
+KQp0PTQKYnJlYWsKY2FzZSAyOnA9WzFdCmNhc2UgNDpyPTEKZG9jdW1lbnQuYm9keS5jbGFzc0xpc3Qu
+cmVtb3ZlKCJyZXJ1bm5pbmciKQp0PXAucG9wKCkKYnJlYWsKY2FzZSA1OnJldHVybiBQLnlDKG51bGws
+cykKY2FzZSAxOnJldHVybiBQLmYzKHEscyl9fSkKcmV0dXJuIFAuREkoJGFzeW5jJCQxLHMpfSwKJFM6
+MTd9CkwuSGkucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQKdS5WLmEoYSkKdD11Lk4KQy5v
+bC5Qbyh3aW5kb3csUC5YZCgiaHR0cHMiLCJnaXRodWIuY29tIiwiZGFydC1sYW5nL3Nkay9pc3N1ZXMv
+bmV3IixQLkVGKFsidGl0bGUiLCJDdXN0b21lci1yZXBvcnRlZCBpc3N1ZSB3aXRoIE5OQkQgbWlncmF0
+aW9uIHRvb2wiLCJsYWJlbHMiLCJhcmVhLWFuYWx5emVyLGFuYWx5emVyLW5uYmQtbWlncmF0aW9uLHR5
+cGUtYnVnIiwiYm9keSIsIiMjIyMgU3RlcHMgdG8gcmVwcm9kdWNlXG5cbiMjIyMgV2hhdCBkaWQgeW91
+IGV4cGVjdCB0byBoYXBwZW4/XG5cbiMjIyMgV2hhdCBhY3R1YWxseSBoYXBwZW5lZD9cblxuX1NjcmVl
+bnNob3RzIGFyZSBhcHByZWNpYXRlZF9cblxuKipEYXJ0IFNESyB2ZXJzaW9uKio6ICIrSC5kKGRvY3Vt
+ZW50LmdldEVsZW1lbnRCeUlkKCJzZGstdmVyc2lvbiIpLnRleHRDb250ZW50KSsiXG5cblRoYW5rcyBm
+b3IgZmlsaW5nIVxuIl0sdCx0KSkuWigwKSwicmVwb3J0LXByb2JsZW0iKX0sCiRTOjN9CkwuQlQucHJv
+dG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dmFyIHQKdS5WLmEoYSkKdD1kb2N1bWVudC5xdWVyeVNlbGVj
+dG9yKCIucG9wdXAtcGFuZSIpLnN0eWxlCnQuZGlzcGxheT0ibm9uZSIKcmV0dXJuIm5vbmUifSwKJFM6
+NDN9CkwuTC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIKdS5CLmEoYSkKdD13aW5k
+b3cubG9jYXRpb24ucGF0aG5hbWUKcz1MLkc2KHdpbmRvdy5sb2NhdGlvbi5ocmVmKQpyPUwuYUsod2lu
+ZG93LmxvY2F0aW9uLmhyZWYpCmlmKHQubGVuZ3RoPjEpTC5HNyh0LHMsciwhMSxudWxsKQplbHNle0wu
+QkUodCxuZXcgQi5xcCgiIiwiIiwiIixDLkNNKSwhMCkKTC5CWCgiJm5ic3A7IixudWxsKX19LAokUzox
+Nn0KTC5XeC5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzLHIscT0iY29sbGFwc2VkIgp1
+LlYuYShhKQp0PXRoaXMuYQpzPUouUkUodCkKcj10aGlzLmIKaWYoIXMuZ1AodCkudGcoMCxxKSl7cy5n
+UCh0KS5pKDAscSkKSi5kUihyKS5pKDAscSl9ZWxzZXtzLmdQKHQpLlIoMCxxKQpKLmRSKHIpLlIoMCxx
+KX19LAokUzozfQpMLkFPLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0PUoucUYodS5oLmEo
+YSkpLHM9dC4kdGkscj1zLkMoIn4oMSkiKS5hKG5ldyBMLmROKHRoaXMuYSkpCnUuTS5hKG51bGwpClcu
+SkUodC5hLHQuYixyLCExLHMuYyl9LAokUzo2fQpMLmROLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEp
+e3ZhciB0CnUuVi5hKGEpCnQ9ZG9jdW1lbnQucXVlcnlTZWxlY3RvcigidGFibGVbZGF0YS1wYXRoXSIp
+CnQudG9TdHJpbmcKTC50MihhLHRoaXMuYSx0LmdldEF0dHJpYnV0ZSgiZGF0YS0iK25ldyBXLlN5KG5l
+dyBXLmk3KHQpKS5PKCJwYXRoIikpKX0sCiRTOjN9CkwuSG8ucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24o
+YSl7dmFyIHQscyxyCnUuaC5hKGEpCnQ9Si5xRihhKQpzPXQuJHRpCnI9cy5DKCJ+KDEpIikuYShuZXcg
+TC54eihhLHRoaXMuYSkpCnUuTS5hKG51bGwpClcuSkUodC5hLHQuYixyLCExLHMuYyl9LAokUzo2fQpM
+Lnh6LnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe3ZhciB0LHM9bnVsbAp1LlYuYShhKQp0PXRoaXMu
+YQpMLmhYKHRoaXMuYixQLlFBKHQuZ2V0QXR0cmlidXRlKCJkYXRhLSIrbmV3IFcuU3kobmV3IFcuaTco
+dCkpLk8oIm9mZnNldCIpKSxzLHMpLFAuUUEodC5nZXRBdHRyaWJ1dGUoImRhdGEtIituZXcgVy5TeShu
+ZXcgVy5pNyh0KSkuTygibGluZSIpKSxzLHMpKX0sCiRTOjN9CkwuSUMucHJvdG90eXBlPXsKJDE6ZnVu
+Y3Rpb24oYSl7dmFyIHQ9Si5xRih1LmguYShhKSkscz10LiR0aQpzLkMoIn4oMSkiKS5hKEwuaVMoKSkK
+dS5NLmEobnVsbCkKVy5KRSh0LmEsdC5iLEwuaVMoKSwhMSxzLmMpfSwKJFM6Nn0KTC5mQy5wcm90b3R5
+cGU9ewokMTpmdW5jdGlvbihhKXt1LkYuYShhKQp0aGlzLmEuYU0oMCx0aGlzLmIpfSwKJFM6NDV9Ckwu
+blQucHJvdG90eXBlPXsKJDA6ZnVuY3Rpb24oKXtMLkZyKHRoaXMuYS5hLHRoaXMuYix0aGlzLmMpfSwK
+JFM6MH0KTC5CWi5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigpe0wuRnIodGhpcy5hLmEsbnVsbCxudWxs
+KX0sCiRTOjB9CkwuR0gucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7dS5oLmEoYSkKJC56QigpLnRv
+U3RyaW5nCnUubS5hKCQub3coKS5xKDAsImhsanMiKSkuVjcoImhpZ2hsaWdodEJsb2NrIixbYV0pfSwK
+JFM6Nn0KTC5FRS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzCnUuVi5hKGEpCnQ9dGhp
+cy5hCnM9dGhpcy5iCkwuYWYod2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLHQscywhMCxuZXcgTC5RTCh0
+LHMpKQpMLmhYKHRoaXMuYyx0LHMpfSwKJFM6M30KTC5RTC5wcm90b3R5cGU9ewokMDpmdW5jdGlvbigp
+e0wuRnIod2luZG93LmxvY2F0aW9uLnBhdGhuYW1lLHRoaXMuYSx0aGlzLmIpfSwKJFM6MH0KTC5WUy5w
+cm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXt2YXIgdCxzPSJzZWxlY3RlZC1maWxlIgp1LmguYShhKQph
+LnRvU3RyaW5nCnQ9Si5SRShhKQppZihhLmdldEF0dHJpYnV0ZSgiZGF0YS0iK25ldyBXLlN5KG5ldyBX
+Lmk3KGEpKS5PKCJuYW1lIikpPT09dGhpcy5hLmEpdC5nUChhKS5pKDAscykKZWxzZSB0LmdQKGEpLlIo
+MCxzKX0sCiRTOjZ9CkwuVEQucHJvdG90eXBlPXsKJDE6ZnVuY3Rpb24oYSl7cmV0dXJuIEwudDIodS5W
+LmEoYSksITAsbnVsbCl9LAokUzoxOH0KTC5BUy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1
+cm4gdGhpcy5QTCh1LlYuYShhKSl9LApQTDpmdW5jdGlvbihhKXt2YXIgdD0wLHM9UC5GWCh1LlApLHI9
+MSxxLHA9W10sbz10aGlzLG4sbSxsLGssagp2YXIgJGFzeW5jJCQxPVAubHooZnVuY3Rpb24oYixjKXtp
+ZihiPT09MSl7cT1jCnQ9cn13aGlsZSh0cnVlKXN3aXRjaCh0KXtjYXNlIDA6cj0zCmw9dS5OCnQ9Ngpy
+ZXR1cm4gUC5qUShMLnR5KEwuUTQoIi9hcHBseS1oaW50IixQLkZsKGwsbCkpLG8uYS5MdCgpKSwkYXN5
+bmMkJDEpCmNhc2UgNjpsPW8uYgpMLkc3KGwuYyxudWxsLGwuYiwhMSxudWxsKQpkb2N1bWVudC5ib2R5
+LmNsYXNzTGlzdC5hZGQoIm5lZWRzLXJlcnVuIikKcj0xCnQ9NQpicmVhawpjYXNlIDM6cj0yCmo9cQpu
+PUguUnUoaikKbT1ILnRzKGopCkwuQzIoIkNvdWxkIG5vdCBhcHBseSBoaW50IixuLG0pCnQ9NQpicmVh
+awpjYXNlIDI6dD0xCmJyZWFrCmNhc2UgNTpyZXR1cm4gUC55QyhudWxsLHMpCmNhc2UgMTpyZXR1cm4g
+UC5mMyhxLHMpfX0pCnJldHVybiBQLkRJKCRhc3luYyQkMSxzKX0sCiRTOjE3fQpMLlhBLnByb3RvdHlw
+ZT17CkViOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4hMH0sCmkwOmZ1bmN0aW9uKGEpe3JldHVybiEwfSwK
+JGlrRjoxfQpMLlpaLnByb3RvdHlwZT17Ckx0OmZ1bmN0aW9uKCl7dmFyIHQscz10aGlzLHI9UC5GbCh1
+Lk4sdS5LKQpyLlkoMCwidHlwZSIsTC52eShzLmEpKQpyLlkoMCwibmFtZSIscy5iKQp0PXMuYwppZih0
+IT1udWxsKXIuWSgwLCJzdWJ0cmVlIixMLlZEKHQpKQp0PXMuZAppZih0IT1udWxsKXIuWSgwLCJwYXRo
+Iix0KQp0PXMuZQppZih0IT1udWxsKXIuWSgwLCJocmVmIix0KQp0PXMuZgppZih0IT1udWxsKXIuWSgw
+LCJlZGl0Q291bnQiLHQpCnJldHVybiByfX0KTC5POS5wcm90b3R5cGU9ewpaOmZ1bmN0aW9uKGEpe3Jl
+dHVybiB0aGlzLmJ9fQpNLmxJLnByb3RvdHlwZT17CldPOmZ1bmN0aW9uKGEsYil7dmFyIHQscz1udWxs
+Ck0uWUYoImFic29sdXRlIixILlZNKFtiLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsXSx1LnMp
+KQp0PXRoaXMuYQp0PXQuWXIoYik+MCYmIXQuaEsoYikKaWYodClyZXR1cm4gYgp0PUQuUlgoKQpyZXR1
+cm4gdGhpcy5xNygwLHQsYixzLHMscyxzLHMscyl9LAp6ZjpmdW5jdGlvbihhKXt2YXIgdCxzLHI9WC5D
+TChhLHRoaXMuYSkKci5JVigpCnQ9ci5kCnM9dC5sZW5ndGgKaWYocz09PTApe3Q9ci5iCnJldHVybiB0
+PT1udWxsPyIuIjp0fWlmKHM9PT0xKXt0PXIuYgpyZXR1cm4gdD09bnVsbD8iLiI6dH1pZigwPj1zKXJl
+dHVybiBILmsodCwtMSkKdC5wb3AoKQpDLk5tLm12KHIuZSkKci5JVigpCnJldHVybiByLlooMCl9LApx
+NzpmdW5jdGlvbihhLGIsYyxkLGUsZixnLGgsaSl7dmFyIHQ9SC5WTShbYixjLGQsZSxmLGcsaCxpXSx1
+LnMpCk0uWUYoImpvaW4iLHQpCnJldHVybiB0aGlzLklQKG5ldyBILlU1KHQsdS5iQi5hKG5ldyBNLk1p
+KCkpLHUuY2MpKX0sCklQOmZ1bmN0aW9uKGEpe3ZhciB0LHMscixxLHAsbyxuLG0sbCxrCnUuWC5hKGEp
+CmZvcih0PWEuJHRpLHM9dC5DKCJhMihjWC5FKSIpLmEobmV3IE0ucTcoKSkscj1hLmdreihhKSx0PW5l
+dyBILnZHKHIscyx0LkMoInZHPGNYLkU+IikpLHM9dGhpcy5hLHE9ITEscD0hMSxvPSIiO3QuRigpOyl7
+bj1yLmdsKCkKaWYocy5oSyhuKSYmcCl7bT1YLkNMKG4scykKbD1vLmNoYXJDb2RlQXQoMCk9PTA/bzpv
+Cm89Qy54Qi5OaihsLDAscy5TcChsLCEwKSkKbS5iPW8KaWYocy5kcyhvKSlDLk5tLlkobS5lLDAscy5n
+bUkoKSkKbz1tLlooMCl9ZWxzZSBpZihzLllyKG4pPjApe3A9IXMuaEsobikKbz1ILmQobil9ZWxzZXtr
+PW4ubGVuZ3RoCmlmKGshPT0wKXtpZigwPj1rKXJldHVybiBILmsobiwwKQprPXMuVWQoblswXSl9ZWxz
+ZSBrPSExCmlmKCFrKWlmKHEpbys9cy5nbUkoKQpvKz1ufXE9cy5kcyhuKX1yZXR1cm4gby5jaGFyQ29k
+ZUF0KDApPT0wP286b30sCm81OmZ1bmN0aW9uKGEpe3ZhciB0CmlmKCF0aGlzLnkzKGEpKXJldHVybiBh
+CnQ9WC5DTChhLHRoaXMuYSkKdC5yUigpCnJldHVybiB0LlooMCl9LAp5MzpmdW5jdGlvbihhKXt2YXIg
+dCxzLHIscSxwLG8sbixtLGwsawphLnRvU3RyaW5nCnQ9dGhpcy5hCnM9dC5ZcihhKQppZihzIT09MCl7
+aWYodD09PSQuS2soKSlmb3Iocj0wO3I8czsrK3IpaWYoQy54Qi5XKGEscik9PT00NylyZXR1cm4hMApx
+PXMKcD00N31lbHNle3E9MApwPW51bGx9Zm9yKG89bmV3IEgucWooYSkuYSxuPW8ubGVuZ3RoLHI9cSxt
+PW51bGw7cjxuOysrcixtPXAscD1sKXtsPUMueEIubShvLHIpCmlmKHQucjQobCkpe2lmKHQ9PT0kLktr
+KCkmJmw9PT00NylyZXR1cm4hMAppZihwIT1udWxsJiZ0LnI0KHApKXJldHVybiEwCmlmKHA9PT00Nilr
+PW09PW51bGx8fG09PT00Nnx8dC5yNChtKQplbHNlIGs9ITEKaWYoaylyZXR1cm4hMH19aWYocD09bnVs
+bClyZXR1cm4hMAppZih0LnI0KHApKXJldHVybiEwCmlmKHA9PT00Nil0PW09PW51bGx8fHQucjQobSl8
+fG09PT00NgplbHNlIHQ9ITEKaWYodClyZXR1cm4hMApyZXR1cm4hMX0sCkhQOmZ1bmN0aW9uKGEsYil7
+dmFyIHQscyxyLHEscCxvLG4sbT10aGlzLGw9J1VuYWJsZSB0byBmaW5kIGEgcGF0aCB0byAiJwpiPW0u
+V08oMCxiKQp0PW0uYQppZih0LllyKGIpPD0wJiZ0LllyKGEpPjApcmV0dXJuIG0ubzUoYSkKaWYodC5Z
+cihhKTw9MHx8dC5oSyhhKSlhPW0uV08oMCxhKQppZih0LllyKGEpPD0wJiZ0LllyKGIpPjApdGhyb3cg
+SC5iKFguSTcobCtILmQoYSkrJyIgZnJvbSAiJytILmQoYikrJyIuJykpCnM9WC5DTChiLHQpCnMuclIo
+KQpyPVguQ0woYSx0KQpyLnJSKCkKcT1zLmQKcD1xLmxlbmd0aAppZihwIT09MCl7aWYoMD49cClyZXR1
+cm4gSC5rKHEsMCkKcT1KLlJNKHFbMF0sIi4iKX1lbHNlIHE9ITEKaWYocSlyZXR1cm4gci5aKDApCnE9
+cy5iCnA9ci5iCmlmKHEhPXApcT1xPT1udWxsfHxwPT1udWxsfHwhdC5OYyhxLHApCmVsc2UgcT0hMQpp
+ZihxKXJldHVybiByLlooMCkKd2hpbGUoITApe3E9cy5kCnA9cS5sZW5ndGgKaWYocCE9PTApe289ci5k
+Cm49by5sZW5ndGgKaWYobiE9PTApe2lmKDA+PXApcmV0dXJuIEguayhxLDApCnE9cVswXQppZigwPj1u
+KXJldHVybiBILmsobywwKQpvPXQuTmMocSxvWzBdKQpxPW99ZWxzZSBxPSExfWVsc2UgcT0hMQppZigh
+cSlicmVhawpDLk5tLlc0KHMuZCwwKQpDLk5tLlc0KHMuZSwxKQpDLk5tLlc0KHIuZCwwKQpDLk5tLlc0
+KHIuZSwxKX1xPXMuZApwPXEubGVuZ3RoCmlmKHAhPT0wKXtpZigwPj1wKXJldHVybiBILmsocSwwKQpx
+PUouUk0ocVswXSwiLi4iKX1lbHNlIHE9ITEKaWYocSl0aHJvdyBILmIoWC5JNyhsK0guZChhKSsnIiBm
+cm9tICInK0guZChiKSsnIi4nKSkKcT11Lk4KQy5ObS5VRyhyLmQsMCxQLk84KHMuZC5sZW5ndGgsIi4u
+IiwhMSxxKSkKQy5ObS5ZKHIuZSwwLCIiKQpDLk5tLlVHKHIuZSwxLFAuTzgocy5kLmxlbmd0aCx0Lmdt
+SSgpLCExLHEpKQp0PXIuZApxPXQubGVuZ3RoCmlmKHE9PT0wKXJldHVybiIuIgppZihxPjEmJkouUk0o
+Qy5ObS5ncloodCksIi4iKSl7dD1yLmQKaWYoMD49dC5sZW5ndGgpcmV0dXJuIEguayh0LC0xKQp0LnBv
+cCgpCnQ9ci5lCkMuTm0ubXYodCkKQy5ObS5tdih0KQpDLk5tLmkodCwiIil9ci5iPSIiCnIuSVYoKQpy
+ZXR1cm4gci5aKDApfX0KTS5NaS5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gSC5jKGEp
+IT1udWxsfSwKJFM6N30KTS5xNy5wcm90b3R5cGU9ewokMTpmdW5jdGlvbihhKXtyZXR1cm4gSC5jKGEp
+IT09IiJ9LAokUzo3fQpNLk5vLnByb3RvdHlwZT17CiQxOmZ1bmN0aW9uKGEpe0guYyhhKQpyZXR1cm4g
+YT09bnVsbD8ibnVsbCI6JyInK2ErJyInfSwKJFM6NX0KQi5mdi5wcm90b3R5cGU9ewp4WjpmdW5jdGlv
+bihhKXt2YXIgdCxzPXRoaXMuWXIoYSkKaWYocz4wKXJldHVybiBKLmxkKGEsMCxzKQppZih0aGlzLmhL
+KGEpKXtpZigwPj1hLmxlbmd0aClyZXR1cm4gSC5rKGEsMCkKdD1hWzBdfWVsc2UgdD1udWxsCnJldHVy
+biB0fSwKTmM6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYT09Yn19ClguV0QucHJvdG90eXBlPXsKSVY6ZnVu
+Y3Rpb24oKXt2YXIgdCxzLHI9dGhpcwp3aGlsZSghMCl7dD1yLmQKaWYoISh0Lmxlbmd0aCE9PTAmJkou
+Uk0oQy5ObS5ncloodCksIiIpKSlicmVhawp0PXIuZAppZigwPj10Lmxlbmd0aClyZXR1cm4gSC5rKHQs
+LTEpCnQucG9wKCkKQy5ObS5tdihyLmUpfXQ9ci5lCnM9dC5sZW5ndGgKaWYocyE9PTApQy5ObS5ZKHQs
+cy0xLCIiKX0sCnJSOmZ1bmN0aW9uKCl7dmFyIHQscyxyLHEscCxvLG49dGhpcyxtPUguVk0oW10sdS5z
+KQpmb3IodD1uLmQscz10Lmxlbmd0aCxyPTAscT0wO3E8dC5sZW5ndGg7dC5sZW5ndGg9PT1zfHwoMCxI
+LmxrKSh0KSwrK3Epe3A9dFtxXQpvPUouaWEocCkKaWYoIShvLkROKHAsIi4iKXx8by5ETihwLCIiKSkp
+aWYoby5ETihwLCIuLiIpKXtvPW0ubGVuZ3RoCmlmKG8hPT0wKXtpZigwPj1vKXJldHVybiBILmsobSwt
+MSkKbS5wb3AoKX1lbHNlICsrcn1lbHNlIEMuTm0uaShtLHApfWlmKG4uYj09bnVsbClDLk5tLlVHKG0s
+MCxQLk84KHIsIi4uIiwhMSx1Lk4pKQppZihtLmxlbmd0aD09PTAmJm4uYj09bnVsbClDLk5tLmkobSwi
+LiIpCm4uc25KKG0pCnQ9bi5hCm4uc1BoKFAuTzgobS5sZW5ndGgrMSx0LmdtSSgpLCEwLHUuTikpCnM9
+bi5iCmlmKHM9PW51bGx8fG0ubGVuZ3RoPT09MHx8IXQuZHMocykpQy5ObS5ZKG4uZSwwLCIiKQpzPW4u
+YgppZihzIT1udWxsJiZ0PT09JC5LaygpKXtzLnRvU3RyaW5nCm4uYj1ILnlzKHMsIi8iLCJcXCIpfW4u
+SVYoKX0sClo6ZnVuY3Rpb24oYSl7dmFyIHQscyxyPXRoaXMscT1yLmIKcT1xIT1udWxsP3E6IiIKZm9y
+KHQ9MDt0PHIuZC5sZW5ndGg7Kyt0KXtzPXIuZQppZih0Pj1zLmxlbmd0aClyZXR1cm4gSC5rKHMsdCkK
+cz1xK0guZChzW3RdKQpxPXIuZAppZih0Pj1xLmxlbmd0aClyZXR1cm4gSC5rKHEsdCkKcT1zK0guZChx
+W3RdKX1xKz1ILmQoQy5ObS5nclooci5lKSkKcmV0dXJuIHEuY2hhckNvZGVBdCgwKT09MD9xOnF9LApz
+bko6ZnVuY3Rpb24oYSl7dGhpcy5kPXUuYS5hKGEpfSwKc1BoOmZ1bmN0aW9uKGEpe3RoaXMuZT11LmEu
+YShhKX19ClguZHYucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4iUGF0aEV4Y2VwdGlvbjog
+Iit0aGlzLmF9LAokaVJ6OjF9Ck8uekwucHJvdG90eXBlPXsKWjpmdW5jdGlvbihhKXtyZXR1cm4gdGhp
+cy5nb2ModGhpcyl9fQpFLk9GLnByb3RvdHlwZT17ClVkOmZ1bmN0aW9uKGEpe3JldHVybiBDLnhCLnRn
+KGEsIi8iKX0sCnI0OmZ1bmN0aW9uKGEpe3JldHVybiBhPT09NDd9LApkczpmdW5jdGlvbihhKXt2YXIg
+dD1hLmxlbmd0aApyZXR1cm4gdCE9PTAmJkMueEIubShhLHQtMSkhPT00N30sClNwOmZ1bmN0aW9uKGEs
+Yil7aWYoYS5sZW5ndGghPT0wJiZDLnhCLlcoYSwwKT09PTQ3KXJldHVybiAxCnJldHVybiAwfSwKWXI6
+ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuU3AoYSwhMSl9LApoSzpmdW5jdGlvbihhKXtyZXR1cm4hMX0s
+CmdvYzpmdW5jdGlvbigpe3JldHVybiJwb3NpeCJ9LApnbUk6ZnVuY3Rpb24oKXtyZXR1cm4iLyJ9fQpG
+LnJ1LnByb3RvdHlwZT17ClVkOmZ1bmN0aW9uKGEpe3JldHVybiBDLnhCLnRnKGEsIi8iKX0sCnI0OmZ1
+bmN0aW9uKGEpe3JldHVybiBhPT09NDd9LApkczpmdW5jdGlvbihhKXt2YXIgdD1hLmxlbmd0aAppZih0
+PT09MClyZXR1cm4hMQppZihDLnhCLm0oYSx0LTEpIT09NDcpcmV0dXJuITAKcmV0dXJuIEMueEIuVGMo
+YSwiOi8vIikmJnRoaXMuWXIoYSk9PT10fSwKU3A6ZnVuY3Rpb24oYSxiKXt2YXIgdCxzLHIscSxwPWEu
+bGVuZ3RoCmlmKHA9PT0wKXJldHVybiAwCmlmKEMueEIuVyhhLDApPT09NDcpcmV0dXJuIDEKZm9yKHQ9
+MDt0PHA7Kyt0KXtzPUMueEIuVyhhLHQpCmlmKHM9PT00NylyZXR1cm4gMAppZihzPT09NTgpe2lmKHQ9
+PT0wKXJldHVybiAwCnI9Qy54Qi5YVShhLCIvIixDLnhCLlFpKGEsIi8vIix0KzEpP3QrMzp0KQppZihy
+PD0wKXJldHVybiBwCmlmKCFifHxwPHIrMylyZXR1cm4gcgppZighQy54Qi5uKGEsImZpbGU6Ly8iKSly
+ZXR1cm4gcgppZighQi5ZdShhLHIrMSkpcmV0dXJuIHIKcT1yKzMKcmV0dXJuIHA9PT1xP3E6cis0fX1y
+ZXR1cm4gMH0sCllyOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLlNwKGEsITEpfSwKaEs6ZnVuY3Rpb24o
+YSl7cmV0dXJuIGEubGVuZ3RoIT09MCYmQy54Qi5XKGEsMCk9PT00N30sCmdvYzpmdW5jdGlvbigpe3Jl
+dHVybiJ1cmwifSwKZ21JOmZ1bmN0aW9uKCl7cmV0dXJuIi8ifX0KTC5JVi5wcm90b3R5cGU9ewpVZDpm
+dW5jdGlvbihhKXtyZXR1cm4gQy54Qi50ZyhhLCIvIil9LApyNDpmdW5jdGlvbihhKXtyZXR1cm4gYT09
+PTQ3fHxhPT09OTJ9LApkczpmdW5jdGlvbihhKXt2YXIgdD1hLmxlbmd0aAppZih0PT09MClyZXR1cm4h
+MQp0PUMueEIubShhLHQtMSkKcmV0dXJuISh0PT09NDd8fHQ9PT05Mil9LApTcDpmdW5jdGlvbihhLGIp
+e3ZhciB0LHMscj1hLmxlbmd0aAppZihyPT09MClyZXR1cm4gMAp0PUMueEIuVyhhLDApCmlmKHQ9PT00
+NylyZXR1cm4gMQppZih0PT09OTIpe2lmKHI8Mnx8Qy54Qi5XKGEsMSkhPT05MilyZXR1cm4gMQpzPUMu
+eEIuWFUoYSwiXFwiLDIpCmlmKHM+MCl7cz1DLnhCLlhVKGEsIlxcIixzKzEpCmlmKHM+MClyZXR1cm4g
+c31yZXR1cm4gcn1pZihyPDMpcmV0dXJuIDAKaWYoIUIuT1ModCkpcmV0dXJuIDAKaWYoQy54Qi5XKGEs
+MSkhPT01OClyZXR1cm4gMApyPUMueEIuVyhhLDIpCmlmKCEocj09PTQ3fHxyPT09OTIpKXJldHVybiAw
+CnJldHVybiAzfSwKWXI6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuU3AoYSwhMSl9LApoSzpmdW5jdGlv
+bihhKXtyZXR1cm4gdGhpcy5ZcihhKT09PTF9LApPdDpmdW5jdGlvbihhLGIpe3ZhciB0CmlmKGE9PT1i
+KXJldHVybiEwCmlmKGE9PT00NylyZXR1cm4gYj09PTkyCmlmKGE9PT05MilyZXR1cm4gYj09PTQ3Cmlm
+KChhXmIpIT09MzIpcmV0dXJuITEKdD1hfDMyCnJldHVybiB0Pj05NyYmdDw9MTIyfSwKTmM6ZnVuY3Rp
+b24oYSxiKXt2YXIgdCxzLHIKaWYoYT09YilyZXR1cm4hMAp0PWEubGVuZ3RoCmlmKHQhPT1iLmxlbmd0
+aClyZXR1cm4hMQpmb3Iocz1KLnJZKGIpLHI9MDtyPHQ7KytyKWlmKCF0aGlzLk90KEMueEIuVyhhLHIp
+LHMuVyhiLHIpKSlyZXR1cm4hMQpyZXR1cm4hMH0sCmdvYzpmdW5jdGlvbigpe3JldHVybiJ3aW5kb3dz
+In0sCmdtSTpmdW5jdGlvbigpe3JldHVybiJcXCJ9fTsoZnVuY3Rpb24gYWxpYXNlcygpe3ZhciB0PUou
+dkIucHJvdG90eXBlCnQuVT10LloKdC5Taj10LmU3CnQ9Si5NRi5wcm90b3R5cGUKdC50PXQuWgp0PVAu
+Y1gucHJvdG90eXBlCnQuR0c9dC5ldgp0PVAuTWgucHJvdG90eXBlCnQueGI9dC5aCnQ9Vy5jdi5wcm90
+b3R5cGUKdC5EVz10LnI2CnQ9Vy5tNi5wcm90b3R5cGUKdC5qRj10LkViCnQ9UC5FNC5wcm90b3R5cGUK
+dC5Vcj10LnEKdC5lND10Lll9KSgpOyhmdW5jdGlvbiBpbnN0YWxsVGVhck9mZnMoKXt2YXIgdD1odW5r
+SGVscGVycy5fc3RhdGljXzEscz1odW5rSGVscGVycy5fc3RhdGljXzAscj1odW5rSGVscGVycy5pbnN0
+YWxsSW5zdGFuY2VUZWFyT2ZmLHE9aHVua0hlbHBlcnMuaW5zdGFsbFN0YXRpY1RlYXJPZmYscD1odW5r
+SGVscGVycy5faW5zdGFuY2VfMXUKdChQLCJFWCIsIlpWIiw4KQp0KFAsInl0Iiwib0EiLDgpCnQoUCwi
+cVciLCJCeiIsOCkKcyhQLCJWOSIsImVOIiwyKQpyKFAuUGYucHJvdG90eXBlLCJnWUoiLDAsMSxudWxs
+LFsiJDIiLCIkMSJdLFsidzAiLCJwbSJdLDI4LDApCnQoUCwiQ3kiLCJOQyIsMSkKdChQLCJQSCIsIk10
+Iiw1KQpxKFcsInBTIiw0LG51bGwsWyIkNCJdLFsicUQiXSw5LDApCnEoVywiVjQiLDQsbnVsbCxbIiQ0
+Il0sWyJRVyJdLDksMCkKcChQLkFzLnByb3RvdHlwZSwiZ3VNIiwiVCIsNSkKdChQLCJpRyIsIndZIiwx
+KQp0KFAsIncwIiwiTDciLDMyKQp0KEwsImlTIiwiaTYiLDE4KX0pKCk7KGZ1bmN0aW9uIGluaGVyaXRh
+bmNlKCl7dmFyIHQ9aHVua0hlbHBlcnMubWl4aW4scz1odW5rSGVscGVycy5pbmhlcml0LHI9aHVua0hl
+bHBlcnMuaW5oZXJpdE1hbnkKcyhQLk1oLG51bGwpCnIoUC5NaCxbSC5GSyxKLnZCLEoubTEsUC5uWSxQ
+LmNYLEguYTcsUC5BbixILlNVLEguUmUsSC53dixQLlBuLEguV1UsSC5MSSxILlRwLEguZjksUC5YUyxI
+LmJxLEguWE8sUC5ZayxILmRiLEguTjYsSC5WUixILkVLLEguUGIsSC50USxILlNkLEguSmMsSC5FVCxQ
+LlczLFAuaWgsUC5GeSxQLkdWLFAuYjgsUC5QZixQLkZlLFAudnMsUC5PTSxQLnFoLFAuTU8sUC5rVCxQ
+LnhJLFAuT0gsUC5tMCxQLlh2LFAuYm4sUC5sbSxQLmxELFAuS1AsUC5NYSxQLlRDLFAuVWssUC5TaCxQ
+LlJ3LFAuYnosUC5hMixQLmlQLFAubGYsUC5rNSxQLktZLFAuQ0QsUC5hRSxQLkVILFAuek0sUC5aMCxQ
+Lk4zLFAuYzgsUC5PZCxQLmliLFAuR3osUC5aZCxQLnFVLFAuUm4sUC5HRCxQLkRuLFAuUEUsUC5VZixX
+LmlkLFcuRmssVy5KUSxXLkdtLFcudkQsVy5tNixXLk93LFcuVzksVy5kVyxXLkZiLFcua0YsVy5tayxX
+LktvLFAuaUosUC5FNCxQLm42LE0uSDcsVS5MTCxVLmQyLFUuU2UsVS5NbCxVLnlELFUud2IsQi5qOCxC
+LnFwLFQubVEsTC5YQSxMLlpaLEwuTzksTS5sSSxPLnpMLFguV0QsWC5kdl0pCnIoSi52QixbSi55RSxK
+LllFLEouTUYsSi5qZCxKLnFJLEouRHIsSC5lSCxXLkQwLFcuQXosVy5MZSxXLk5oLFcuSUIsVy5uNyxX
+LmVhLFcuYnIsVy5TZyxXLnU4LFcuSzcsVy5YVyxQLmhGXSkKcihKLk1GLFtKLmlDLEoua2QsSi5jNV0p
+CnMoSi5QbyxKLmpkKQpyKEoucUksW0ouYlUsSi5WQV0pCnMoUC51eSxQLm5ZKQpyKFAudXksW0gudzIs
+Vy53eixXLmU3XSkKcyhILnFqLEgudzIpCnIoUC5jWCxbSC5iUSxILmkxLEguVTUsSC5YUixQLm1XLEgu
+TkZdKQpyKEguYlEsW0guYUwsSC5pNSxQLnh1XSkKcihILmFMLFtILm5ILEgubEosUC5pOF0pCnMoSC54
+eSxILmkxKQpyKFAuQW4sW0guTUgsSC52R10pCnMoUC5SVSxQLlBuKQpzKFAuR2osUC5SVSkKcyhILlBE
+LFAuR2opCnMoSC5MUCxILldVKQpyKEguVHAsW0guQ2osSC5BbSxILmxjLEgucixILmRDLEgud04sUC50
+aCxQLmhhLFAuVnMsUC5GdCxQLnlILFAuV00sUC5TWCxQLkdzLFAuZGEsUC5vUSxQLnBWLFAuVTcsUC52
+cixQLnJILFAuS0YsUC5aTCxQLlJULFAualosUC5ycSxQLlJXLFAuQjUsUC51TyxQLnBLLFAuaGosUC5W
+cCxQLk9SLFAucmEsUC55USxQLnRpLFAuV0YsUC5uMSxQLmNTLFAuVkMsUC5KVCxQLmUxLFAuTlksUC5S
+WixQLk1FLFAueTUsUC5xMyxQLnlJLFAuYzYsUC5xZCxXLkN2LFcuS1MsVy5BMyxXLnZOLFcuVXYsVy5F
+ZyxXLkVvLFcuV2ssVy5JQSxXLmZtLFAuamcsUC5UYSxQLkdFLFAuTjcsUC51USxQLlBDLFAubXQsUC5O
+eixQLlFTLFAubnAsVS5NRCxVLmFOLFUuYjAsTC5lLEwuVlcsTC5vWixMLmpyLEwucWwsTC55OCxMLkhp
+LEwuQlQsTC5MLEwuV3gsTC5BTyxMLmROLEwuSG8sTC54eixMLklDLEwuZkMsTC5uVCxMLkJaLEwuR0gs
+TC5FRSxMLlFMLEwuVlMsTC5URCxMLkFTLE0uTWksTS5xNyxNLk5vXSkKcihQLlhTLFtILlcwLEguYXos
+SC52VixILkVxLFAuQzYsSC51OSxQLlVkLFAuTEssUC5BVCxQLm1wLFAudWIsUC5kcyxQLmxqLFAuVVYs
+UC50N10pCnIoSC5sYyxbSC56eCxILmp5XSkKcyhILmtZLFAuQzYpCnMoUC5pbCxQLllrKQpyKFAuaWws
+W0guTjUsUC51dyxXLmNmLFcuU3ldKQpyKFAubVcsW0guS1csUC5xNF0pCnMoSC5MWixILmVIKQpyKEgu
+TFosW0guUkcsSC5XQl0pCnMoSC5WUCxILlJHKQpzKEguRGcsSC5WUCkKcyhILlpHLEguV0IpCnMoSC5Q
+ZyxILlpHKQpyKEguUGcsW0gueGosSC5kRSxILlpBLEgud2YsSC5QcSxILmVFLEguVjZdKQpzKEgueCxI
+LnU5KQpzKFAuWmYsUC5QZikKcyhQLkppLFAubTApCnMoUC5iNixQLlh2KQpzKFAuVmosUC5UQykKcihQ
+LlVrLFtQLkNWLFAuWmksUC5ieV0pCnMoUC53SSxQLmtUKQpyKFAud0ksW1AuVTgsUC5vaixQLk14LFAu
+RTMsUC5HWV0pCnMoUC5LOCxQLlVkKQpzKFAudHUsUC5TaCkKcyhQLnU1LFAuWmkpCnIoUC5sZixbUC5D
+UCxQLklmXSkKcihQLkFULFtQLmJKLFAuZVldKQpzKFAucWUsUC5EbikKcihXLkQwLFtXLnVILFcud2Es
+Vy5LNSxXLkNtXSkKcihXLnVILFtXLmN2LFcubngsVy5RRixXLkNRXSkKcihXLmN2LFtXLnFFLFAuZDVd
+KQpyKFcucUUsW1cuR2gsVy5mWSxXLm5CLFcuUVAsVy5oNCxXLlNOLFcubHAsVy5UYixXLkl2LFcuV1As
+Vy55WV0pCnMoVy5vSixXLkxlKQpzKFcuaEgsVy5BeikKcyhXLlZiLFcuUUYpCnMoVy5mSixXLndhKQpy
+KFcuZWEsW1cudzYsVy5ld10pCnMoVy5PSyxXLnc2KQpzKFcuckIsVy5LNykKcyhXLkJILFcuckIpCnMo
+Vy53NCxXLklCKQpzKFcub2EsVy5YVykKcyhXLnJoLFcub2EpCnMoVy5pNyxXLmNmKQpzKFAuQXMsUC5W
+aikKcihQLkFzLFtXLkk0LFAuS2VdKQpzKFcuUk8sUC5xaCkKcyhXLmV1LFcuUk8pCnMoVy54QyxQLk1P
+KQpzKFcuY3QsVy5tNikKcyhQLkJmLFAuaUopCnIoUC5FNCxbUC5yNyxQLmNvXSkKcyhQLlR6LFAuY28p
+CnMoUC5uZCxQLmQ1KQpzKEIuZnYsTy56TCkKcihCLmZ2LFtFLk9GLEYucnUsTC5JVl0pCnQoSC53MixI
+LlJlKQp0KEguUkcsUC5sRCkKdChILlZQLEguU1UpCnQoSC5XQixQLmxEKQp0KEguWkcsSC5TVSkKdChQ
+Lm5ZLFAubEQpCnQoUC5UQyxQLk1hKQp0KFAuUlUsUC5LUCkKdChXLkxlLFcuaWQpCnQoVy5LNyxQLmxE
+KQp0KFcuckIsVy5HbSkKdChXLlhXLFAubEQpCnQoVy5vYSxXLkdtKQp0KFAuY28sUC5sRCl9KSgpCnZh
+ciB2PXt0eXBlVW5pdmVyc2U6e2VDOm5ldyBNYXAoKSx0Ujp7fSxlVDp7fSx0UFY6e30sc0VBOltdfSxt
+YW5nbGVkR2xvYmFsTmFtZXM6e0lmOiJpbnQiLENQOiJkb3VibGUiLGxmOiJudW0iLHFVOiJTdHJpbmci
+LGEyOiJib29sIixjODoiTnVsbCIsek06Ikxpc3QifSxtYW5nbGVkTmFtZXM6e30sZ2V0VHlwZUZyb21O
+YW1lOmdldEdsb2JhbEZyb21OYW1lLG1ldGFkYXRhOltdLHR5cGVzOlsiYzgoKSIsIkAoQCkiLCJ+KCki
+LCJjOChPSykiLCJjOChALEApIiwicVUocVUpIiwiYzgoY3YpIiwiYTIocVUpIiwifih+KCkpIiwiYTIo
+Y3YscVUscVUsSlEpIiwiYzgoQCkiLCJ+KHh1PHFVPikiLCJjOChxVSxAKSIsImM4KHFVKSIsImM4KHFV
+LHFVKSIsImEyKGtGKSIsImM4KGVhKSIsImI4PGM4PihPSykiLCJ+KE9LKSIsIlowPHFVLHFVPihaMDxx
+VSxxVT4scVUpIiwiYzgofigpKSIsImM4KEAsR3opIiwifihxVSxxVSkiLCJuNihJZikiLCJuNihALEAp
+IiwiYTIodUgpIiwiYzgoSWYsQCkiLCJAKGVhKSIsIn4oTWhbR3pdKSIsImM4KEBbR3pdKSIsIn4odUgs
+dUgpIiwiYTIoeHU8cVU+KSIsIk1oKEApIiwicjcoQCkiLCJUejxAPihAKSIsIkU0KEApIiwiYTIoSDcp
+IiwiTEwoQCkiLCJaMDxxVSxNaD4oTEwpIiwidnM8QD4oQCkiLCJAKHFVKSIsImM4KFowPHFVLE1oPiki
+LCJjOChHRCxAKSIsInFVKE9LKSIsIkAoQCxxVSkiLCJjOChldykiLCJ+KHFVLElmKSIsIn4ocVVbQF0p
+IiwiSWYoSWYsSWYpIiwifihAKSJdLGludGVyY2VwdG9yc0J5VGFnOm51bGwsbGVhZlRhZ3M6bnVsbCxh
+cnJheVJ0aTp0eXBlb2YgU3ltYm9sPT0iZnVuY3Rpb24iJiZ0eXBlb2YgU3ltYm9sKCk9PSJzeW1ib2wi
+P1N5bWJvbCgiJHRpIik6IiR0aSJ9CkgueGIodi50eXBlVW5pdmVyc2UsSlNPTi5wYXJzZSgneyJjNSI6
+Ik1GIiwiaUMiOiJNRiIsImtkIjoiTUYiLCJyeCI6ImVhIiwiZTUiOiJlYSIsIlkwIjoiZDUiLCJ0cCI6
+ImQ1IiwiRzgiOiJldyIsIk1yIjoicUUiLCJlTCI6InFFIiwiSTAiOiJ1SCIsImhzIjoidUgiLCJYZyI6
+IlFGIiwibnIiOiJPSyIsInk0IjoidzYiLCJhUCI6IkNtIiwieGMiOiJueCIsImtKIjoibngiLCJ6VSI6
+IkRnIiwiZGYiOiJlSCIsInlFIjp7ImEyIjpbXX0sIllFIjp7ImM4IjpbXX0sIk1GIjp7InZtIjpbXSwi
+RUgiOltdfSwiamQiOnsiek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIlBvIjp7ImpkIjpb
+IjEiXSwiek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIm0xIjp7IkFuIjpbIjEiXX0sInFJ
+Ijp7IkNQIjpbXSwibGYiOltdfSwiYlUiOnsiSWYiOltdLCJDUCI6W10sImxmIjpbXX0sIlZBIjp7IkNQ
+IjpbXSwibGYiOltdfSwiRHIiOnsicVUiOltdLCJ2WCI6W119LCJxaiI6eyJSZSI6WyJJZiJdLCJsRCI6
+WyJJZiJdLCJ6TSI6WyJJZiJdLCJiUSI6WyJJZiJdLCJjWCI6WyJJZiJdLCJsRC5FIjoiSWYiLCJSZS5F
+IjoiSWYifSwiYlEiOnsiY1giOlsiMSJdfSwiYUwiOnsiYlEiOlsiMSJdLCJjWCI6WyIxIl19LCJuSCI6
+eyJhTCI6WyIxIl0sImJRIjpbIjEiXSwiY1giOlsiMSJdLCJhTC5FIjoiMSIsImNYLkUiOiIxIn0sImE3
+Ijp7IkFuIjpbIjEiXX0sImkxIjp7ImNYIjpbIjIiXSwiY1guRSI6IjIifSwieHkiOnsiaTEiOlsiMSIs
+IjIiXSwiYlEiOlsiMiJdLCJjWCI6WyIyIl0sImNYLkUiOiIyIn0sIk1IIjp7IkFuIjpbIjIiXX0sImxK
+Ijp7ImFMIjpbIjIiXSwiYlEiOlsiMiJdLCJjWCI6WyIyIl0sImFMLkUiOiIyIiwiY1guRSI6IjIifSwi
+VTUiOnsiY1giOlsiMSJdLCJjWC5FIjoiMSJ9LCJ2RyI6eyJBbiI6WyIxIl19LCJ3MiI6eyJSZSI6WyIx
+Il0sImxEIjpbIjEiXSwiek0iOlsiMSJdLCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sInd2Ijp7IkdEIjpb
+XX0sIlBEIjp7IkdqIjpbIjEiLCIyIl0sIlJVIjpbIjEiLCIyIl0sIlBuIjpbIjEiLCIyIl0sIktQIjpb
+IjEiLCIyIl0sIlowIjpbIjEiLCIyIl19LCJXVSI6eyJaMCI6WyIxIiwiMiJdfSwiTFAiOnsiV1UiOlsi
+MSIsIjIiXSwiWjAiOlsiMSIsIjIiXX0sIlhSIjp7ImNYIjpbIjEiXSwiY1guRSI6IjEifSwiTEkiOnsi
+dlEiOltdfSwiVzAiOnsiWFMiOltdfSwiYXoiOnsiWFMiOltdfSwidlYiOnsiWFMiOltdfSwiWE8iOnsi
+R3oiOltdfSwiVHAiOnsiRUgiOltdfSwibGMiOnsiRUgiOltdfSwiengiOnsiRUgiOltdfSwiankiOnsi
+RUgiOltdfSwiRXEiOnsiWFMiOltdfSwia1kiOnsiWFMiOltdfSwiTjUiOnsiRm8iOlsiMSIsIjIiXSwi
+WWsiOlsiMSIsIjIiXSwiWjAiOlsiMSIsIjIiXSwiWWsuSyI6IjEiLCJZay5WIjoiMiJ9LCJpNSI6eyJi
+USI6WyIxIl0sImNYIjpbIjEiXSwiY1guRSI6IjEifSwiTjYiOnsiQW4iOlsiMSJdfSwiVlIiOnsid0wi
+OltdLCJ2WCI6W119LCJFSyI6eyJpYiI6W10sIk9kIjpbXX0sIktXIjp7ImNYIjpbImliIl0sImNYLkUi
+OiJpYiJ9LCJQYiI6eyJBbiI6WyJpYiJdfSwidFEiOnsiT2QiOltdfSwiTkYiOnsiY1giOlsiT2QiXSwi
+Y1guRSI6Ik9kIn0sIlNkIjp7IkFuIjpbIk9kIl19LCJlSCI6eyJlcSI6W119LCJMWiI6eyJYaiI6WyJA
+Il0sImVIIjpbXSwiZXEiOltdfSwiRGciOnsibEQiOlsiQ1AiXSwiWGoiOlsiQCJdLCJ6TSI6WyJDUCJd
+LCJlSCI6W10sImJRIjpbIkNQIl0sIlNVIjpbIkNQIl0sImVxIjpbXSwiY1giOlsiQ1AiXSwibEQuRSI6
+IkNQIn0sIlBnIjp7ImxEIjpbIklmIl0sInpNIjpbIklmIl0sIlhqIjpbIkAiXSwiZUgiOltdLCJiUSI6
+WyJJZiJdLCJTVSI6WyJJZiJdLCJlcSI6W10sImNYIjpbIklmIl19LCJ4aiI6eyJsRCI6WyJJZiJdLCJ6
+TSI6WyJJZiJdLCJYaiI6WyJAIl0sImVIIjpbXSwiYlEiOlsiSWYiXSwiU1UiOlsiSWYiXSwiZXEiOltd
+LCJjWCI6WyJJZiJdLCJsRC5FIjoiSWYifSwiZEUiOnsibEQiOlsiSWYiXSwiek0iOlsiSWYiXSwiWGoi
+OlsiQCJdLCJlSCI6W10sImJRIjpbIklmIl0sIlNVIjpbIklmIl0sImVxIjpbXSwiY1giOlsiSWYiXSwi
+bEQuRSI6IklmIn0sIlpBIjp7ImxEIjpbIklmIl0sInpNIjpbIklmIl0sIlhqIjpbIkAiXSwiZUgiOltd
+LCJiUSI6WyJJZiJdLCJTVSI6WyJJZiJdLCJlcSI6W10sImNYIjpbIklmIl0sImxELkUiOiJJZiJ9LCJ3
+ZiI6eyJsRCI6WyJJZiJdLCJ6TSI6WyJJZiJdLCJYaiI6WyJAIl0sImVIIjpbXSwiYlEiOlsiSWYiXSwi
+U1UiOlsiSWYiXSwiZXEiOltdLCJjWCI6WyJJZiJdLCJsRC5FIjoiSWYifSwiUHEiOnsibEQiOlsiSWYi
+XSwiek0iOlsiSWYiXSwiWGoiOlsiQCJdLCJlSCI6W10sImJRIjpbIklmIl0sIlNVIjpbIklmIl0sImVx
+IjpbXSwiY1giOlsiSWYiXSwibEQuRSI6IklmIn0sImVFIjp7ImxEIjpbIklmIl0sInpNIjpbIklmIl0s
+IlhqIjpbIkAiXSwiZUgiOltdLCJiUSI6WyJJZiJdLCJTVSI6WyJJZiJdLCJlcSI6W10sImNYIjpbIklm
+Il0sImxELkUiOiJJZiJ9LCJWNiI6eyJuNiI6W10sImxEIjpbIklmIl0sInpNIjpbIklmIl0sIlhqIjpb
+IkAiXSwiZUgiOltdLCJiUSI6WyJJZiJdLCJTVSI6WyJJZiJdLCJlcSI6W10sImNYIjpbIklmIl0sImxE
+LkUiOiJJZiJ9LCJ1OSI6eyJYUyI6W119LCJ4Ijp7IlhTIjpbXX0sIkdWIjp7IkFuIjpbIjEiXX0sInE0
+Ijp7ImNYIjpbIjEiXSwiY1guRSI6IjEifSwiWmYiOnsiUGYiOlsiMSJdfSwidnMiOnsiYjgiOlsiMSJd
+fSwiT0giOnsiWFMiOltdfSwibTAiOnsiSkIiOltdfSwiSmkiOnsiSkIiOltdfSwiYjYiOnsiWHYiOlsi
+MSJdLCJ4dSI6WyIxIl0sImJRIjpbIjEiXSwiY1giOlsiMSJdfSwibG0iOnsiQW4iOlsiMSJdfSwibVci
+OnsiY1giOlsiMSJdfSwidXkiOnsibEQiOlsiMSJdLCJ6TSI6WyIxIl0sImJRIjpbIjEiXSwiY1giOlsi
+MSJdfSwiaWwiOnsiWWsiOlsiMSIsIjIiXSwiWjAiOlsiMSIsIjIiXX0sIllrIjp7IlowIjpbIjEiLCIy
+Il19LCJQbiI6eyJaMCI6WyIxIiwiMiJdfSwiR2oiOnsiUlUiOlsiMSIsIjIiXSwiUG4iOlsiMSIsIjIi
+XSwiS1AiOlsiMSIsIjIiXSwiWjAiOlsiMSIsIjIiXX0sIlZqIjp7Ik1hIjpbIjEiXSwieHUiOlsiMSJd
+LCJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIlh2Ijp7Inh1IjpbIjEiXSwiYlEiOlsiMSJdLCJjWCI6WyIx
+Il19LCJ1dyI6eyJZayI6WyJxVSIsIkAiXSwiWjAiOlsicVUiLCJAIl0sIllrLksiOiJxVSIsIllrLlYi
+OiJAIn0sImk4Ijp7ImFMIjpbInFVIl0sImJRIjpbInFVIl0sImNYIjpbInFVIl0sImFMLkUiOiJxVSIs
+ImNYLkUiOiJxVSJ9LCJDViI6eyJVayI6WyJ6TTxJZj4iLCJxVSJdLCJVay5TIjoiek08SWY+In0sIlU4
+Ijp7IndJIjpbInpNPElmPiIsInFVIl19LCJaaSI6eyJVayI6WyJxVSIsInpNPElmPiJdfSwiVWQiOnsi
+WFMiOltdfSwiSzgiOnsiWFMiOltdfSwiYnkiOnsiVWsiOlsiTWgiLCJxVSJdLCJVay5TIjoiTWgifSwi
+b2oiOnsid0kiOlsiTWgiLCJxVSJdfSwiTXgiOnsid0kiOlsicVUiLCJNaCJdfSwidTUiOnsiVWsiOlsi
+cVUiLCJ6TTxJZj4iXSwiVWsuUyI6InFVIn0sIkUzIjp7IndJIjpbInFVIiwiek08SWY+Il19LCJHWSI6
+eyJ3SSI6WyJ6TTxJZj4iLCJxVSJdfSwiQ1AiOnsibGYiOltdfSwiQzYiOnsiWFMiOltdfSwiTEsiOnsi
+WFMiOltdfSwiQVQiOnsiWFMiOltdfSwiYkoiOnsiWFMiOltdfSwiZVkiOnsiWFMiOltdfSwibXAiOnsi
+WFMiOltdfSwidWIiOnsiWFMiOltdfSwiZHMiOnsiWFMiOltdfSwibGoiOnsiWFMiOltdfSwiVVYiOnsi
+WFMiOltdfSwiazUiOnsiWFMiOltdfSwiS1kiOnsiWFMiOltdfSwidDciOnsiWFMiOltdfSwiQ0QiOnsi
+UnoiOltdfSwiYUUiOnsiUnoiOltdfSwiSWYiOnsibGYiOltdfSwiek0iOnsiYlEiOlsiMSJdLCJjWCI6
+WyIxIl19LCJpYiI6eyJPZCI6W119LCJ4dSI6eyJiUSI6WyIxIl0sImNYIjpbIjEiXX0sIlpkIjp7Ikd6
+IjpbXX0sInFVIjp7InZYIjpbXX0sIlJuIjp7IkJMIjpbXX0sIkRuIjp7ImlEIjpbXX0sIlVmIjp7ImlE
+IjpbXX0sInFlIjp7ImlEIjpbXX0sInFFIjp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJHaCI6eyJj
+diI6W10sInVIIjpbXSwiRDAiOltdfSwiZlkiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpbXX0sIm5CIjp7
+ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJRUCI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwibngi
+OnsidUgiOltdLCJEMCI6W119LCJRRiI6eyJ1SCI6W10sIkQwIjpbXX0sIklCIjp7InRuIjpbImxmIl19
+LCJ3eiI6eyJsRCI6WyIxIl0sInpNIjpbIjEiXSwiYlEiOlsiMSJdLCJjWCI6WyIxIl0sImxELkUiOiIx
+In0sImN2Ijp7InVIIjpbXSwiRDAiOltdfSwiaEgiOnsiQXoiOltdfSwiaDQiOnsiY3YiOltdLCJ1SCI6
+W10sIkQwIjpbXX0sIlZiIjp7InVIIjpbXSwiRDAiOltdfSwiZkoiOnsiRDAiOltdfSwid2EiOnsiRDAi
+OltdfSwiT0siOnsiZWEiOltdfSwiZTciOnsibEQiOlsidUgiXSwiek0iOlsidUgiXSwiYlEiOlsidUgi
+XSwiY1giOlsidUgiXSwibEQuRSI6InVIIn0sInVIIjp7IkQwIjpbXX0sIkJIIjp7IkdtIjpbInVIIl0s
+ImxEIjpbInVIIl0sInpNIjpbInVIIl0sIlhqIjpbInVIIl0sImJRIjpbInVIIl0sImNYIjpbInVIIl0s
+ImxELkUiOiJ1SCIsIkdtLkUiOiJ1SCJ9LCJTTiI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwiZXci
+OnsiZWEiOltdfSwibHAiOnsiY3YiOltdLCJ1SCI6W10sIkQwIjpbXX0sIlRiIjp7ImN2IjpbXSwidUgi
+OltdLCJEMCI6W119LCJJdiI6eyJjdiI6W10sInVIIjpbXSwiRDAiOltdfSwiV1AiOnsiY3YiOltdLCJ1
+SCI6W10sIkQwIjpbXX0sInlZIjp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJ3NiI6eyJlYSI6W119
+LCJLNSI6eyJ2NiI6W10sIkQwIjpbXX0sIkNtIjp7IkQwIjpbXX0sIkNRIjp7InVIIjpbXSwiRDAiOltd
+fSwidzQiOnsidG4iOlsibGYiXX0sInJoIjp7IkdtIjpbInVIIl0sImxEIjpbInVIIl0sInpNIjpbInVI
+Il0sIlhqIjpbInVIIl0sImJRIjpbInVIIl0sImNYIjpbInVIIl0sImxELkUiOiJ1SCIsIkdtLkUiOiJ1
+SCJ9LCJjZiI6eyJZayI6WyJxVSIsInFVIl0sIlowIjpbInFVIiwicVUiXX0sImk3Ijp7IllrIjpbInFV
+IiwicVUiXSwiWjAiOlsicVUiLCJxVSJdLCJZay5LIjoicVUiLCJZay5WIjoicVUifSwiU3kiOnsiWWsi
+OlsicVUiLCJxVSJdLCJaMCI6WyJxVSIsInFVIl0sIllrLksiOiJxVSIsIllrLlYiOiJxVSJ9LCJJNCI6
+eyJNYSI6WyJxVSJdLCJ4dSI6WyJxVSJdLCJiUSI6WyJxVSJdLCJjWCI6WyJxVSJdfSwiUk8iOnsicWgi
+OlsiMSJdfSwiZXUiOnsiUk8iOlsiMSJdLCJxaCI6WyIxIl19LCJ4QyI6eyJNTyI6WyIxIl19LCJKUSI6
+eyJrRiI6W119LCJ2RCI6eyJrRiI6W119LCJtNiI6eyJrRiI6W119LCJjdCI6eyJrRiI6W119LCJPdyI6
+eyJrRiI6W119LCJXOSI6eyJBbiI6WyIxIl19LCJkVyI6eyJ2NiI6W10sIkQwIjpbXX0sIm1rIjp7Inkw
+IjpbXX0sIktvIjp7Im9uIjpbXX0sIkFzIjp7Ik1hIjpbInFVIl0sInh1IjpbInFVIl0sImJRIjpbInFV
+Il0sImNYIjpbInFVIl19LCJyNyI6eyJFNCI6W119LCJUeiI6eyJsRCI6WyIxIl0sInpNIjpbIjEiXSwi
+YlEiOlsiMSJdLCJFNCI6W10sImNYIjpbIjEiXSwibEQuRSI6IjEifSwibmQiOnsiZDUiOltdLCJjdiI6
+W10sInVIIjpbXSwiRDAiOltdfSwiS2UiOnsiTWEiOlsicVUiXSwieHUiOlsicVUiXSwiYlEiOlsicVUi
+XSwiY1giOlsicVUiXX0sImQ1Ijp7ImN2IjpbXSwidUgiOltdLCJEMCI6W119LCJuNiI6eyJ6TSI6WyJJ
+ZiJdLCJiUSI6WyJJZiJdLCJlcSI6W10sImNYIjpbIklmIl19LCJYQSI6eyJrRiI6W119LCJkdiI6eyJS
+eiI6W119LCJPRiI6eyJmdiI6W119LCJydSI6eyJmdiI6W119LCJJViI6eyJmdiI6W119fScpKQpILkZG
+KHYudHlwZVVuaXZlcnNlLEpTT04ucGFyc2UoJ3siYlEiOjEsIncyIjoxLCJNTyI6MSwia1QiOjIsIm1X
+IjoxLCJ1eSI6MSwiaWwiOjIsIlZqIjoxLCJuWSI6MSwiVEMiOjEsImNvIjoxfScpKQp2YXIgdT0oZnVu
+Y3Rpb24gcnRpaSgpe3ZhciB0PUguTjAKcmV0dXJue2JxOnQoIkdoIiksbjp0KCJPSCIpLGNSOnQoIm5C
+IiksZDp0KCJBeiIpLFk6dCgiUVAiKSxnRjp0KCJQRDxHRCxAPiIpLGd3OnQoImJRPEA+IiksaDp0KCJj
+diIpLFc6dCgiWFMiKSxCOnQoImVhIikscjp0KCJEMCIpLGc4OnQoIlJ6IiksYzg6dCgiaEgiKSxaOnQo
+IkVIIiksYVE6dCgiYjg8Yzg+IiksYzp0KCJiODxAPiIpLEU6dCgiTEwiKSxncDp0KCJINyIpLEk6dCgi
+U2ciKSxvOnQoInZRIiksZWg6dCgiY1g8dUg+IiksWDp0KCJjWDxxVT4iKSxSOnQoImNYPEA+IiksZkE6
+dCgiamQ8U2U+IiksZ2k6dCgiamQ8ajg+IiksSjp0KCJqZDxaMDxxVSxNaD4+IiksZmg6dCgiamQ8Wlo+
+IiksaTp0KCJqZDxrRj4iKSxzOnQoImpkPHFVPiIpLGhoOnQoImpkPHlEPiIpLGFKOnQoImpkPHdiPiIp
+LGI6dCgiamQ8QD4iKSx0OnQoImpkPElmPiIpLGVIOnQoInZtIiksZzp0KCJjNSIpLGFVOnQoIlhqPEA+
+IiksYW06dCgiVHo8QD4iKSxlbzp0KCJONTxHRCxAPiIpLG06dCgiRTQiKSxkejp0KCJoRiIpLGY0OnQo
+InpNPGo4PiIpLGQzOnQoInpNPFowPHFVLE1oPj4iKSxldzp0KCJ6TTxNaD4iKSxhOnQoInpNPHFVPiIp
+LGo6dCgiek08QD4iKSxMOnQoInpNPElmPiIpLGFfOnQoInU4IiksUzp0KCJaMDxxVSxNaD4iKSxmOnQo
+IlowPHFVLHFVPiIpLGs6dCgiWjA8cVUsQD4iKSxHOnQoIlowPEAsQD4iKSxkdjp0KCJsSjxxVSxxVT4i
+KSxkbzp0KCJsSjxxVSxAPiIpLFY6dCgiT0siKSxkRDp0KCJlSCIpLGJtOnQoIlY2IiksQTp0KCJ1SCIp
+LGU6dCgia0YiKSxQOnQoImM4IiksSzp0KCJNaCIpLEY6dCgiZXciKSxxOnQoInRuPGxmPiIpLGZ2OnQo
+IndMIiksYXY6dCgiSmMiKSxhTzp0KCJuZCIpLEM6dCgieHU8cVU+IiksbDp0KCJHeiIpLE46dCgicVUi
+KSxkRzp0KCJxVShxVSkiKSxnNzp0KCJkNSIpLGZvOnQoIkdEIiksYVc6dCgieVkiKSx1OnQoImVxIiks
+Z2M6dCgibjYiKSxhazp0KCJrZCIpLHY6dCgiR2o8cVUscVU+Iiksdzp0KCJpRCIpLGNjOnQoIlU1PHFV
+PiIpLGc0OnQoIks1IiksY2k6dCgidjYiKSxnMjp0KCJDbSIpLGJqOnQoIlpmPGZKPiIpLGg5OnQoIkNR
+IiksYWM6dCgiZTciKSxROnQoImV1PE9LPiIpLFQ6dCgid3o8Y3Y+IikseDp0KCJGZTxALEA+IiksYW86
+dCgidnM8Zko+IiksXzp0KCJ2czxAPiIpLGZKOnQoInZzPElmPiIpLE86dCgiSlEiKSxEOnQoImJuIiks
+eTp0KCJhMiIpLGFsOnQoImEyKE1oKSIpLGJCOnQoImEyKHFVKSIpLGJmOnQoImEyKEApIiksZ1I6dCgi
+Q1AiKSx6OnQoIkAiKSxmTzp0KCJAKCkiKSxVOnQoIkAoZWEpIiksYkk6dCgiQChNaCkiKSxlcDp0KCJA
+KE1oLE1oKSIpLGFnOnQoIkAoTWgsR3opIiksYlU6dCgiQCh4dTxxVT4pIiksZE86dCgiQChxVSkiKSxi
+Yzp0KCJAKEApIiksYjg6dCgiQChALEApIikscDp0KCJJZiIpLGRpOnQoImxmIiksSDp0KCJ+IiksTTp0
+KCJ+KCkiKSxhbjp0KCJ+KGV3KSIpLGVBOnQoIn4ocVUscVUpIiksY0E6dCgifihxVSxAKSIpfX0pKCk7
+KGZ1bmN0aW9uIGNvbnN0YW50cygpe3ZhciB0PWh1bmtIZWxwZXJzLm1ha2VDb25zdExpc3QKQy5SWT1X
+LlFQLnByb3RvdHlwZQpDLkJaPVcuVmIucHJvdG90eXBlCkMuRHQ9Vy5mSi5wcm90b3R5cGUKQy5Paz1K
+LnZCLnByb3RvdHlwZQpDLk5tPUouamQucHJvdG90eXBlCkMuam49Si5iVS5wcm90b3R5cGUKQy5DRD1K
+LnFJLnByb3RvdHlwZQpDLnhCPUouRHIucHJvdG90eXBlCkMuREc9Si5jNS5wcm90b3R5cGUKQy5FeD1X
+LnU4LnByb3RvdHlwZQpDLnQ1PVcuQkgucHJvdG90eXBlCkMuTHQ9Vy5TTi5wcm90b3R5cGUKQy5aUT1K
+LmlDLnByb3RvdHlwZQpDLkllPVcuVGIucHJvdG90eXBlCkMudkI9Si5rZC5wcm90b3R5cGUKQy5vbD1X
+Lks1LnByb3RvdHlwZQpDLnk4PW5ldyBQLlU4KCkKQy5oOT1uZXcgUC5DVigpCkMud2I9ZnVuY3Rpb24g
+Z2V0VGFnRmFsbGJhY2sobykgewogIHZhciBzID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxs
+KG8pOwogIHJldHVybiBzLnN1YnN0cmluZyg4LCBzLmxlbmd0aCAtIDEpOwp9CkMuTzQ9ZnVuY3Rpb24o
+KSB7CiAgdmFyIHRvU3RyaW5nRnVuY3Rpb24gPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nOwogIGZ1
+bmN0aW9uIGdldFRhZyhvKSB7CiAgICB2YXIgcyA9IHRvU3RyaW5nRnVuY3Rpb24uY2FsbChvKTsKICAg
+IHJldHVybiBzLnN1YnN0cmluZyg4LCBzLmxlbmd0aCAtIDEpOwogIH0KICBmdW5jdGlvbiBnZXRVbmtu
+b3duVGFnKG9iamVjdCwgdGFnKSB7CiAgICBpZiAoL15IVE1MW0EtWl0uKkVsZW1lbnQkLy50ZXN0KHRh
+ZykpIHsKICAgICAgdmFyIG5hbWUgPSB0b1N0cmluZ0Z1bmN0aW9uLmNhbGwob2JqZWN0KTsKICAgICAg
+aWYgKG5hbWUgPT0gIltvYmplY3QgT2JqZWN0XSIpIHJldHVybiBudWxsOwogICAgICByZXR1cm4gIkhU
+TUxFbGVtZW50IjsKICAgIH0KICB9CiAgZnVuY3Rpb24gZ2V0VW5rbm93blRhZ0dlbmVyaWNCcm93c2Vy
+KG9iamVjdCwgdGFnKSB7CiAgICBpZiAoc2VsZi5IVE1MRWxlbWVudCAmJiBvYmplY3QgaW5zdGFuY2Vv
+ZiBIVE1MRWxlbWVudCkgcmV0dXJuICJIVE1MRWxlbWVudCI7CiAgICByZXR1cm4gZ2V0VW5rbm93blRh
+ZyhvYmplY3QsIHRhZyk7CiAgfQogIGZ1bmN0aW9uIHByb3RvdHlwZUZvclRhZyh0YWcpIHsKICAgIGlm
+ICh0eXBlb2Ygd2luZG93ID09ICJ1bmRlZmluZWQiKSByZXR1cm4gbnVsbDsKICAgIGlmICh0eXBlb2Yg
+d2luZG93W3RhZ10gPT0gInVuZGVmaW5lZCIpIHJldHVybiBudWxsOwogICAgdmFyIGNvbnN0cnVjdG9y
+ID0gd2luZG93W3RhZ107CiAgICBpZiAodHlwZW9mIGNvbnN0cnVjdG9yICE9ICJmdW5jdGlvbiIpIHJl
+dHVybiBudWxsOwogICAgcmV0dXJuIGNvbnN0cnVjdG9yLnByb3RvdHlwZTsKICB9CiAgZnVuY3Rpb24g
+ZGlzY3JpbWluYXRvcih0YWcpIHsgcmV0dXJuIG51bGw7IH0KICB2YXIgaXNCcm93c2VyID0gdHlwZW9m
+IG5hdmlnYXRvciA9PSAib2JqZWN0IjsKICByZXR1cm4gewogICAgZ2V0VGFnOiBnZXRUYWcsCiAgICBn
+ZXRVbmtub3duVGFnOiBpc0Jyb3dzZXIgPyBnZXRVbmtub3duVGFnR2VuZXJpY0Jyb3dzZXIgOiBnZXRV
+bmtub3duVGFnLAogICAgcHJvdG90eXBlRm9yVGFnOiBwcm90b3R5cGVGb3JUYWcsCiAgICBkaXNjcmlt
+aW5hdG9yOiBkaXNjcmltaW5hdG9yIH07Cn0KQy5kaz1mdW5jdGlvbihnZXRUYWdGYWxsYmFjaykgewog
+IHJldHVybiBmdW5jdGlvbihob29rcykgewogICAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IgIT0gIm9iamVj
+dCIpIHJldHVybiBob29rczsKICAgIHZhciB1YSA9IG5hdmlnYXRvci51c2VyQWdlbnQ7CiAgICBpZiAo
+dWEuaW5kZXhPZigiRHVtcFJlbmRlclRyZWUiKSA+PSAwKSByZXR1cm4gaG9va3M7CiAgICBpZiAodWEu
+aW5kZXhPZigiQ2hyb21lIikgPj0gMCkgewogICAgICBmdW5jdGlvbiBjb25maXJtKHApIHsKICAgICAg
+ICByZXR1cm4gdHlwZW9mIHdpbmRvdyA9PSAib2JqZWN0IiAmJiB3aW5kb3dbcF0gJiYgd2luZG93W3Bd
+Lm5hbWUgPT0gcDsKICAgICAgfQogICAgICBpZiAoY29uZmlybSgiV2luZG93IikgJiYgY29uZmlybSgi
+SFRNTEVsZW1lbnQiKSkgcmV0dXJuIGhvb2tzOwogICAgfQogICAgaG9va3MuZ2V0VGFnID0gZ2V0VGFn
+RmFsbGJhY2s7CiAgfTsKfQpDLllxPWZ1bmN0aW9uKGhvb2tzKSB7CiAgaWYgKHR5cGVvZiBkYXJ0RXhw
+ZXJpbWVudGFsRml4dXBHZXRUYWcgIT0gImZ1bmN0aW9uIikgcmV0dXJuIGhvb2tzOwogIGhvb2tzLmdl
+dFRhZyA9IGRhcnRFeHBlcmltZW50YWxGaXh1cEdldFRhZyhob29rcy5nZXRUYWcpOwp9CkMuS1U9ZnVu
+Y3Rpb24oaG9va3MpIHsKICB2YXIgZ2V0VGFnID0gaG9va3MuZ2V0VGFnOwogIHZhciBwcm90b3R5cGVG
+b3JUYWcgPSBob29rcy5wcm90b3R5cGVGb3JUYWc7CiAgZnVuY3Rpb24gZ2V0VGFnRml4ZWQobykgewog
+ICAgdmFyIHRhZyA9IGdldFRhZyhvKTsKICAgIGlmICh0YWcgPT0gIkRvY3VtZW50IikgewogICAgICBp
+ZiAoISFvLnhtbFZlcnNpb24pIHJldHVybiAiIURvY3VtZW50IjsKICAgICAgcmV0dXJuICIhSFRNTERv
+Y3VtZW50IjsKICAgIH0KICAgIHJldHVybiB0YWc7CiAgfQogIGZ1bmN0aW9uIHByb3RvdHlwZUZvclRh
+Z0ZpeGVkKHRhZykgewogICAgaWYgKHRhZyA9PSAiRG9jdW1lbnQiKSByZXR1cm4gbnVsbDsKICAgIHJl
+dHVybiBwcm90b3R5cGVGb3JUYWcodGFnKTsKICB9CiAgaG9va3MuZ2V0VGFnID0gZ2V0VGFnRml4ZWQ7
+CiAgaG9va3MucHJvdG90eXBlRm9yVGFnID0gcHJvdG90eXBlRm9yVGFnRml4ZWQ7Cn0KQy54aT1mdW5j
+dGlvbihob29rcykgewogIHZhciB1c2VyQWdlbnQgPSB0eXBlb2YgbmF2aWdhdG9yID09ICJvYmplY3Qi
+ID8gbmF2aWdhdG9yLnVzZXJBZ2VudCA6ICIiOwogIGlmICh1c2VyQWdlbnQuaW5kZXhPZigiRmlyZWZv
+eCIpID09IC0xKSByZXR1cm4gaG9va3M7CiAgdmFyIGdldFRhZyA9IGhvb2tzLmdldFRhZzsKICB2YXIg
+cXVpY2tNYXAgPSB7CiAgICAiQmVmb3JlVW5sb2FkRXZlbnQiOiAiRXZlbnQiLAogICAgIkRhdGFUcmFu
+c2ZlciI6ICJDbGlwYm9hcmQiLAogICAgIkdlb0dlb2xvY2F0aW9uIjogIkdlb2xvY2F0aW9uIiwKICAg
+ICJMb2NhdGlvbiI6ICIhTG9jYXRpb24iLAogICAgIldvcmtlck1lc3NhZ2VFdmVudCI6ICJNZXNzYWdl
+RXZlbnQiLAogICAgIlhNTERvY3VtZW50IjogIiFEb2N1bWVudCJ9OwogIGZ1bmN0aW9uIGdldFRhZ0Zp
+cmVmb3gobykgewogICAgdmFyIHRhZyA9IGdldFRhZyhvKTsKICAgIHJldHVybiBxdWlja01hcFt0YWdd
+IHx8IHRhZzsKICB9CiAgaG9va3MuZ2V0VGFnID0gZ2V0VGFnRmlyZWZveDsKfQpDLmk3PWZ1bmN0aW9u
+KGhvb2tzKSB7CiAgdmFyIHVzZXJBZ2VudCA9IHR5cGVvZiBuYXZpZ2F0b3IgPT0gIm9iamVjdCIgPyBu
+YXZpZ2F0b3IudXNlckFnZW50IDogIiI7CiAgaWYgKHVzZXJBZ2VudC5pbmRleE9mKCJUcmlkZW50LyIp
+ID09IC0xKSByZXR1cm4gaG9va3M7CiAgdmFyIGdldFRhZyA9IGhvb2tzLmdldFRhZzsKICB2YXIgcXVp
+Y2tNYXAgPSB7CiAgICAiQmVmb3JlVW5sb2FkRXZlbnQiOiAiRXZlbnQiLAogICAgIkRhdGFUcmFuc2Zl
+ciI6ICJDbGlwYm9hcmQiLAogICAgIkhUTUxEREVsZW1lbnQiOiAiSFRNTEVsZW1lbnQiLAogICAgIkhU
+TUxEVEVsZW1lbnQiOiAiSFRNTEVsZW1lbnQiLAogICAgIkhUTUxQaHJhc2VFbGVtZW50IjogIkhUTUxF
+bGVtZW50IiwKICAgICJQb3NpdGlvbiI6ICJHZW9wb3NpdGlvbiIKICB9OwogIGZ1bmN0aW9uIGdldFRh
+Z0lFKG8pIHsKICAgIHZhciB0YWcgPSBnZXRUYWcobyk7CiAgICB2YXIgbmV3VGFnID0gcXVpY2tNYXBb
+dGFnXTsKICAgIGlmIChuZXdUYWcpIHJldHVybiBuZXdUYWc7CiAgICBpZiAodGFnID09ICJPYmplY3Qi
+KSB7CiAgICAgIGlmICh3aW5kb3cuRGF0YVZpZXcgJiYgKG8gaW5zdGFuY2VvZiB3aW5kb3cuRGF0YVZp
+ZXcpKSByZXR1cm4gIkRhdGFWaWV3IjsKICAgIH0KICAgIHJldHVybiB0YWc7CiAgfQogIGZ1bmN0aW9u
+IHByb3RvdHlwZUZvclRhZ0lFKHRhZykgewogICAgdmFyIGNvbnN0cnVjdG9yID0gd2luZG93W3RhZ107
+CiAgICBpZiAoY29uc3RydWN0b3IgPT0gbnVsbCkgcmV0dXJuIG51bGw7CiAgICByZXR1cm4gY29uc3Ry
+dWN0b3IucHJvdG90eXBlOwogIH0KICBob29rcy5nZXRUYWcgPSBnZXRUYWdJRTsKICBob29rcy5wcm90
+b3R5cGVGb3JUYWcgPSBwcm90b3R5cGVGb3JUYWdJRTsKfQpDLmZRPWZ1bmN0aW9uKGhvb2tzKSB7IHJl
+dHVybiBob29rczsgfQoKQy5DdD1uZXcgUC5ieSgpCkMuRXE9bmV3IFAuazUoKQpDLnhNPW5ldyBQLnU1
+KCkKQy5Raz1uZXcgUC5FMygpCkMuTlU9bmV3IFAuSmkoKQpDLnBkPW5ldyBQLlpkKCkKQy5BZD1uZXcg
+TS5INygwLCJIaW50QWN0aW9uS2luZC5hZGROdWxsYWJsZUhpbnQiKQpDLm5lPW5ldyBNLkg3KDEsIkhp
+bnRBY3Rpb25LaW5kLmFkZE5vbk51bGxhYmxlSGludCIpCkMubXk9bmV3IE0uSDcoMiwiSGludEFjdGlv
+bktpbmQuY2hhbmdlVG9OdWxsYWJsZUhpbnQiKQpDLnJ4PW5ldyBNLkg3KDMsIkhpbnRBY3Rpb25LaW5k
+LmNoYW5nZVRvTm9uTnVsbGFibGVIaW50IikKQy53Vj1uZXcgTS5INyg0LCJIaW50QWN0aW9uS2luZC5y
+ZW1vdmVOdWxsYWJsZUhpbnQiKQpDLmZSPW5ldyBNLkg3KDUsIkhpbnRBY3Rpb25LaW5kLnJlbW92ZU5v
+bk51bGxhYmxlSGludCIpCkMuQTM9bmV3IFAuTXgobnVsbCkKQy5uWD1uZXcgUC5vaihudWxsKQpDLkdi
+PUguVk0odChbMTI3LDIwNDcsNjU1MzUsMTExNDExMV0pLHUudCkKQy5haz1ILlZNKHQoWzAsMCwzMjc3
+NiwzMzc5MiwxLDEwMjQwLDAsMF0pLHUudCkKQy5jbT1ILlZNKHQoWyIqOjpjbGFzcyIsIio6OmRpciIs
+Iio6OmRyYWdnYWJsZSIsIio6OmhpZGRlbiIsIio6OmlkIiwiKjo6aW5lcnQiLCIqOjppdGVtcHJvcCIs
+Iio6Oml0ZW1yZWYiLCIqOjppdGVtc2NvcGUiLCIqOjpsYW5nIiwiKjo6c3BlbGxjaGVjayIsIio6OnRp
+dGxlIiwiKjo6dHJhbnNsYXRlIiwiQTo6YWNjZXNza2V5IiwiQTo6Y29vcmRzIiwiQTo6aHJlZmxhbmci
+LCJBOjpuYW1lIiwiQTo6c2hhcGUiLCJBOjp0YWJpbmRleCIsIkE6OnRhcmdldCIsIkE6OnR5cGUiLCJB
+UkVBOjphY2Nlc3NrZXkiLCJBUkVBOjphbHQiLCJBUkVBOjpjb29yZHMiLCJBUkVBOjpub2hyZWYiLCJB
+UkVBOjpzaGFwZSIsIkFSRUE6OnRhYmluZGV4IiwiQVJFQTo6dGFyZ2V0IiwiQVVESU86OmNvbnRyb2xz
+IiwiQVVESU86Omxvb3AiLCJBVURJTzo6bWVkaWFncm91cCIsIkFVRElPOjptdXRlZCIsIkFVRElPOjpw
+cmVsb2FkIiwiQkRPOjpkaXIiLCJCT0RZOjphbGluayIsIkJPRFk6OmJnY29sb3IiLCJCT0RZOjpsaW5r
+IiwiQk9EWTo6dGV4dCIsIkJPRFk6OnZsaW5rIiwiQlI6OmNsZWFyIiwiQlVUVE9OOjphY2Nlc3NrZXki
+LCJCVVRUT046OmRpc2FibGVkIiwiQlVUVE9OOjpuYW1lIiwiQlVUVE9OOjp0YWJpbmRleCIsIkJVVFRP
+Tjo6dHlwZSIsIkJVVFRPTjo6dmFsdWUiLCJDQU5WQVM6OmhlaWdodCIsIkNBTlZBUzo6d2lkdGgiLCJD
+QVBUSU9OOjphbGlnbiIsIkNPTDo6YWxpZ24iLCJDT0w6OmNoYXIiLCJDT0w6OmNoYXJvZmYiLCJDT0w6
+OnNwYW4iLCJDT0w6OnZhbGlnbiIsIkNPTDo6d2lkdGgiLCJDT0xHUk9VUDo6YWxpZ24iLCJDT0xHUk9V
+UDo6Y2hhciIsIkNPTEdST1VQOjpjaGFyb2ZmIiwiQ09MR1JPVVA6OnNwYW4iLCJDT0xHUk9VUDo6dmFs
+aWduIiwiQ09MR1JPVVA6OndpZHRoIiwiQ09NTUFORDo6Y2hlY2tlZCIsIkNPTU1BTkQ6OmNvbW1hbmQi
+LCJDT01NQU5EOjpkaXNhYmxlZCIsIkNPTU1BTkQ6OmxhYmVsIiwiQ09NTUFORDo6cmFkaW9ncm91cCIs
+IkNPTU1BTkQ6OnR5cGUiLCJEQVRBOjp2YWx1ZSIsIkRFTDo6ZGF0ZXRpbWUiLCJERVRBSUxTOjpvcGVu
+IiwiRElSOjpjb21wYWN0IiwiRElWOjphbGlnbiIsIkRMOjpjb21wYWN0IiwiRklFTERTRVQ6OmRpc2Fi
+bGVkIiwiRk9OVDo6Y29sb3IiLCJGT05UOjpmYWNlIiwiRk9OVDo6c2l6ZSIsIkZPUk06OmFjY2VwdCIs
+IkZPUk06OmF1dG9jb21wbGV0ZSIsIkZPUk06OmVuY3R5cGUiLCJGT1JNOjptZXRob2QiLCJGT1JNOjpu
+YW1lIiwiRk9STTo6bm92YWxpZGF0ZSIsIkZPUk06OnRhcmdldCIsIkZSQU1FOjpuYW1lIiwiSDE6OmFs
+aWduIiwiSDI6OmFsaWduIiwiSDM6OmFsaWduIiwiSDQ6OmFsaWduIiwiSDU6OmFsaWduIiwiSDY6OmFs
+aWduIiwiSFI6OmFsaWduIiwiSFI6Om5vc2hhZGUiLCJIUjo6c2l6ZSIsIkhSOjp3aWR0aCIsIkhUTUw6
+OnZlcnNpb24iLCJJRlJBTUU6OmFsaWduIiwiSUZSQU1FOjpmcmFtZWJvcmRlciIsIklGUkFNRTo6aGVp
+Z2h0IiwiSUZSQU1FOjptYXJnaW5oZWlnaHQiLCJJRlJBTUU6Om1hcmdpbndpZHRoIiwiSUZSQU1FOjp3
+aWR0aCIsIklNRzo6YWxpZ24iLCJJTUc6OmFsdCIsIklNRzo6Ym9yZGVyIiwiSU1HOjpoZWlnaHQiLCJJ
+TUc6OmhzcGFjZSIsIklNRzo6aXNtYXAiLCJJTUc6Om5hbWUiLCJJTUc6OnVzZW1hcCIsIklNRzo6dnNw
+YWNlIiwiSU1HOjp3aWR0aCIsIklOUFVUOjphY2NlcHQiLCJJTlBVVDo6YWNjZXNza2V5IiwiSU5QVVQ6
+OmFsaWduIiwiSU5QVVQ6OmFsdCIsIklOUFVUOjphdXRvY29tcGxldGUiLCJJTlBVVDo6YXV0b2ZvY3Vz
+IiwiSU5QVVQ6OmNoZWNrZWQiLCJJTlBVVDo6ZGlzYWJsZWQiLCJJTlBVVDo6aW5wdXRtb2RlIiwiSU5Q
+VVQ6OmlzbWFwIiwiSU5QVVQ6Omxpc3QiLCJJTlBVVDo6bWF4IiwiSU5QVVQ6Om1heGxlbmd0aCIsIklO
+UFVUOjptaW4iLCJJTlBVVDo6bXVsdGlwbGUiLCJJTlBVVDo6bmFtZSIsIklOUFVUOjpwbGFjZWhvbGRl
+ciIsIklOUFVUOjpyZWFkb25seSIsIklOUFVUOjpyZXF1aXJlZCIsIklOUFVUOjpzaXplIiwiSU5QVVQ6
+OnN0ZXAiLCJJTlBVVDo6dGFiaW5kZXgiLCJJTlBVVDo6dHlwZSIsIklOUFVUOjp1c2VtYXAiLCJJTlBV
+VDo6dmFsdWUiLCJJTlM6OmRhdGV0aW1lIiwiS0VZR0VOOjpkaXNhYmxlZCIsIktFWUdFTjo6a2V5dHlw
+ZSIsIktFWUdFTjo6bmFtZSIsIkxBQkVMOjphY2Nlc3NrZXkiLCJMQUJFTDo6Zm9yIiwiTEVHRU5EOjph
+Y2Nlc3NrZXkiLCJMRUdFTkQ6OmFsaWduIiwiTEk6OnR5cGUiLCJMSTo6dmFsdWUiLCJMSU5LOjpzaXpl
+cyIsIk1BUDo6bmFtZSIsIk1FTlU6OmNvbXBhY3QiLCJNRU5VOjpsYWJlbCIsIk1FTlU6OnR5cGUiLCJN
+RVRFUjo6aGlnaCIsIk1FVEVSOjpsb3ciLCJNRVRFUjo6bWF4IiwiTUVURVI6Om1pbiIsIk1FVEVSOjp2
+YWx1ZSIsIk9CSkVDVDo6dHlwZW11c3RtYXRjaCIsIk9MOjpjb21wYWN0IiwiT0w6OnJldmVyc2VkIiwi
+T0w6OnN0YXJ0IiwiT0w6OnR5cGUiLCJPUFRHUk9VUDo6ZGlzYWJsZWQiLCJPUFRHUk9VUDo6bGFiZWwi
+LCJPUFRJT046OmRpc2FibGVkIiwiT1BUSU9OOjpsYWJlbCIsIk9QVElPTjo6c2VsZWN0ZWQiLCJPUFRJ
+T046OnZhbHVlIiwiT1VUUFVUOjpmb3IiLCJPVVRQVVQ6Om5hbWUiLCJQOjphbGlnbiIsIlBSRTo6d2lk
+dGgiLCJQUk9HUkVTUzo6bWF4IiwiUFJPR1JFU1M6Om1pbiIsIlBST0dSRVNTOjp2YWx1ZSIsIlNFTEVD
+VDo6YXV0b2NvbXBsZXRlIiwiU0VMRUNUOjpkaXNhYmxlZCIsIlNFTEVDVDo6bXVsdGlwbGUiLCJTRUxF
+Q1Q6Om5hbWUiLCJTRUxFQ1Q6OnJlcXVpcmVkIiwiU0VMRUNUOjpzaXplIiwiU0VMRUNUOjp0YWJpbmRl
+eCIsIlNPVVJDRTo6dHlwZSIsIlRBQkxFOjphbGlnbiIsIlRBQkxFOjpiZ2NvbG9yIiwiVEFCTEU6OmJv
+cmRlciIsIlRBQkxFOjpjZWxscGFkZGluZyIsIlRBQkxFOjpjZWxsc3BhY2luZyIsIlRBQkxFOjpmcmFt
+ZSIsIlRBQkxFOjpydWxlcyIsIlRBQkxFOjpzdW1tYXJ5IiwiVEFCTEU6OndpZHRoIiwiVEJPRFk6OmFs
+aWduIiwiVEJPRFk6OmNoYXIiLCJUQk9EWTo6Y2hhcm9mZiIsIlRCT0RZOjp2YWxpZ24iLCJURDo6YWJi
+ciIsIlREOjphbGlnbiIsIlREOjpheGlzIiwiVEQ6OmJnY29sb3IiLCJURDo6Y2hhciIsIlREOjpjaGFy
+b2ZmIiwiVEQ6OmNvbHNwYW4iLCJURDo6aGVhZGVycyIsIlREOjpoZWlnaHQiLCJURDo6bm93cmFwIiwi
+VEQ6OnJvd3NwYW4iLCJURDo6c2NvcGUiLCJURDo6dmFsaWduIiwiVEQ6OndpZHRoIiwiVEVYVEFSRUE6
+OmFjY2Vzc2tleSIsIlRFWFRBUkVBOjphdXRvY29tcGxldGUiLCJURVhUQVJFQTo6Y29scyIsIlRFWFRB
+UkVBOjpkaXNhYmxlZCIsIlRFWFRBUkVBOjppbnB1dG1vZGUiLCJURVhUQVJFQTo6bmFtZSIsIlRFWFRB
+UkVBOjpwbGFjZWhvbGRlciIsIlRFWFRBUkVBOjpyZWFkb25seSIsIlRFWFRBUkVBOjpyZXF1aXJlZCIs
+IlRFWFRBUkVBOjpyb3dzIiwiVEVYVEFSRUE6OnRhYmluZGV4IiwiVEVYVEFSRUE6OndyYXAiLCJURk9P
+VDo6YWxpZ24iLCJURk9PVDo6Y2hhciIsIlRGT09UOjpjaGFyb2ZmIiwiVEZPT1Q6OnZhbGlnbiIsIlRI
+OjphYmJyIiwiVEg6OmFsaWduIiwiVEg6OmF4aXMiLCJUSDo6Ymdjb2xvciIsIlRIOjpjaGFyIiwiVEg6
+OmNoYXJvZmYiLCJUSDo6Y29sc3BhbiIsIlRIOjpoZWFkZXJzIiwiVEg6OmhlaWdodCIsIlRIOjpub3dy
+YXAiLCJUSDo6cm93c3BhbiIsIlRIOjpzY29wZSIsIlRIOjp2YWxpZ24iLCJUSDo6d2lkdGgiLCJUSEVB
+RDo6YWxpZ24iLCJUSEVBRDo6Y2hhciIsIlRIRUFEOjpjaGFyb2ZmIiwiVEhFQUQ6OnZhbGlnbiIsIlRS
+OjphbGlnbiIsIlRSOjpiZ2NvbG9yIiwiVFI6OmNoYXIiLCJUUjo6Y2hhcm9mZiIsIlRSOjp2YWxpZ24i
+LCJUUkFDSzo6ZGVmYXVsdCIsIlRSQUNLOjpraW5kIiwiVFJBQ0s6OmxhYmVsIiwiVFJBQ0s6OnNyY2xh
+bmciLCJVTDo6Y29tcGFjdCIsIlVMOjp0eXBlIiwiVklERU86OmNvbnRyb2xzIiwiVklERU86OmhlaWdo
+dCIsIlZJREVPOjpsb29wIiwiVklERU86Om1lZGlhZ3JvdXAiLCJWSURFTzo6bXV0ZWQiLCJWSURFTzo6
+cHJlbG9hZCIsIlZJREVPOjp3aWR0aCJdKSx1LnMpCkMuVkM9SC5WTSh0KFswLDAsNjU0OTAsNDUwNTUs
+NjU1MzUsMzQ4MTUsNjU1MzQsMTg0MzFdKSx1LnQpCkMubUs9SC5WTSh0KFswLDAsMjY2MjQsMTAyMyw2
+NTUzNCwyMDQ3LDY1NTM0LDIwNDddKSx1LnQpCkMuU3E9SC5WTSh0KFsiSEVBRCIsIkFSRUEiLCJCQVNF
+IiwiQkFTRUZPTlQiLCJCUiIsIkNPTCIsIkNPTEdST1VQIiwiRU1CRUQiLCJGUkFNRSIsIkZSQU1FU0VU
+IiwiSFIiLCJJTUFHRSIsIklNRyIsIklOUFVUIiwiSVNJTkRFWCIsIkxJTksiLCJNRVRBIiwiUEFSQU0i
+LCJTT1VSQ0UiLCJTVFlMRSIsIlRJVExFIiwiV0JSIl0pLHUucykKQy5kbj1ILlZNKHQoW10pLEguTjAo
+ImpkPExMPiIpKQpDLnhEPUguVk0odChbXSksdS5zKQpDLmhVPUguVk0odChbXSksdS5iKQpDLnRvPUgu
+Vk0odChbMCwwLDMyNzIyLDEyMjg3LDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLnJrPUgu
+Vk0odChbQy5BZCxDLm5lLEMubXksQy5yeCxDLndWLEMuZlJdKSxILk4wKCJqZDxINz4iKSkKQy5GMz1I
+LlZNKHQoWzAsMCwyNDU3NiwxMDIzLDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLmVhPUgu
+Vk0odChbMCwwLDMyNzU0LDExMjYzLDY1NTM0LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLlpKPUgu
+Vk0odChbMCwwLDMyNzIyLDEyMjg3LDY1NTM1LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLldkPUgu
+Vk0odChbMCwwLDY1NDkwLDEyMjg3LDY1NTM1LDM0ODE1LDY1NTM0LDE4NDMxXSksdS50KQpDLlF4PUgu
+Vk0odChbImJpbmQiLCJpZiIsInJlZiIsInJlcGVhdCIsInN5bnRheCJdKSx1LnMpCkMuQkk9SC5WTSh0
+KFsiQTo6aHJlZiIsIkFSRUE6OmhyZWYiLCJCTE9DS1FVT1RFOjpjaXRlIiwiQk9EWTo6YmFja2dyb3Vu
+ZCIsIkNPTU1BTkQ6Omljb24iLCJERUw6OmNpdGUiLCJGT1JNOjphY3Rpb24iLCJJTUc6OnNyYyIsIklO
+UFVUOjpzcmMiLCJJTlM6OmNpdGUiLCJROjpjaXRlIiwiVklERU86OnBvc3RlciJdKSx1LnMpCkMuQ009
+bmV3IEguTFAoMCx7fSxDLnhELEguTjAoIkxQPHFVLHpNPGo4Pj4iKSkKQy5XTz1uZXcgSC5MUCgwLHt9
+LEMueEQsSC5OMCgiTFA8cVUscVU+IikpCkMuaUg9SC5WTSh0KFtdKSxILk4wKCJqZDxHRD4iKSkKQy5E
+eD1uZXcgSC5MUCgwLHt9LEMuaUgsSC5OMCgiTFA8R0QsQD4iKSkKQy5ZMj1uZXcgTC5POSgiTmF2aWdh
+dGlvblRyZWVOb2RlVHlwZS5kaXJlY3RvcnkiKQpDLnJmPW5ldyBMLk85KCJOYXZpZ2F0aW9uVHJlZU5v
+ZGVUeXBlLmZpbGUiKQpDLlRlPW5ldyBILnd2KCJjYWxsIikKQy53UT1uZXcgUC5GeShudWxsLDIpfSko
+KTsoZnVuY3Rpb24gc3RhdGljRmllbGRzKCl7JC55aj0wCiQubUo9bnVsbAokLlA0PW51bGwKJC55PW51
+bGwKJC51PW51bGwKJC54Nz1udWxsCiQuaj1udWxsCiQudj1udWxsCiQuSz1udWxsCiQuUzY9bnVsbAok
+Lms4PW51bGwKJC5tZz1udWxsCiQuVUQ9ITEKJC5YMz1DLk5VCiQueGc9W10KJC54bz1udWxsCiQuQk89
+bnVsbAokLmx0PW51bGwKJC5FVT1udWxsCiQub3I9UC5GbCh1Lk4sdS5aKQokLkk2PW51bGwKJC5GZj1u
+dWxsfSkoKTsoZnVuY3Rpb24gbGF6eUluaXRpYWxpemVycygpe3ZhciB0PWh1bmtIZWxwZXJzLmxhenkK
+dCgkLCJmYSIsIndRIixmdW5jdGlvbigpe3JldHVybiBILllnKCJfJGRhcnRfZGFydENsb3N1cmUiKX0p
+CnQoJCwiWTIiLCJBIixmdW5jdGlvbigpe3JldHVybiBILllnKCJfJGRhcnRfanMiKX0pCnQoJCwiVTIi
+LCJTbiIsZnVuY3Rpb24oKXtyZXR1cm4gSC5jTShILlM3KHsKdG9TdHJpbmc6ZnVuY3Rpb24oKXtyZXR1
+cm4iJHJlY2VpdmVyJCJ9fSkpfSkKdCgkLCJ4cSIsImxxIixmdW5jdGlvbigpe3JldHVybiBILmNNKEgu
+UzcoeyRtZXRob2QkOm51bGwsCnRvU3RyaW5nOmZ1bmN0aW9uKCl7cmV0dXJuIiRyZWNlaXZlciQifX0p
+KX0pCnQoJCwiUjEiLCJOOSIsZnVuY3Rpb24oKXtyZXR1cm4gSC5jTShILlM3KG51bGwpKX0pCnQoJCwi
+Zk4iLCJpSSIsZnVuY3Rpb24oKXtyZXR1cm4gSC5jTShmdW5jdGlvbigpe3ZhciAkYXJndW1lbnRzRXhw
+ciQ9JyRhcmd1bWVudHMkJwp0cnl7bnVsbC4kbWV0aG9kJCgkYXJndW1lbnRzRXhwciQpfWNhdGNoKHMp
+e3JldHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQoJCwicWkiLCJVTiIsZnVuY3Rpb24oKXtyZXR1cm4gSC5j
+TShILlM3KHZvaWQgMCkpfSkKdCgkLCJyWiIsIlpoIixmdW5jdGlvbigpe3JldHVybiBILmNNKGZ1bmN0
+aW9uKCl7dmFyICRhcmd1bWVudHNFeHByJD0nJGFyZ3VtZW50cyQnCnRyeXsodm9pZCAwKS4kbWV0aG9k
+JCgkYXJndW1lbnRzRXhwciQpfWNhdGNoKHMpe3JldHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQoJCwia3Ei
+LCJyTiIsZnVuY3Rpb24oKXtyZXR1cm4gSC5jTShILk1qKG51bGwpKX0pCnQoJCwidHQiLCJjMyIsZnVu
+Y3Rpb24oKXtyZXR1cm4gSC5jTShmdW5jdGlvbigpe3RyeXtudWxsLiRtZXRob2QkfWNhdGNoKHMpe3Jl
+dHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQoJCwiZHQiLCJISyIsZnVuY3Rpb24oKXtyZXR1cm4gSC5jTShI
+Lk1qKHZvaWQgMCkpfSkKdCgkLCJBNyIsInIxIixmdW5jdGlvbigpe3JldHVybiBILmNNKGZ1bmN0aW9u
+KCl7dHJ5eyh2b2lkIDApLiRtZXRob2QkfWNhdGNoKHMpe3JldHVybiBzLm1lc3NhZ2V9fSgpKX0pCnQo
+JCwiV2MiLCJ1dCIsZnVuY3Rpb24oKXtyZXR1cm4gUC5PaigpfSkKdCgkLCJraCIsInRMIixmdW5jdGlv
+bigpe3JldHVybiBQLldJKCl9KQp0KCQsImJ0IiwiVjciLGZ1bmN0aW9uKCl7cmV0dXJuIEguRFEoSC5Y
+RihILlZNKFstMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwt
+MiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwtMiwt
+MSwtMiwtMiwtMiwtMiwtMiw2MiwtMiw2MiwtMiw2Myw1Miw1Myw1NCw1NSw1Niw1Nyw1OCw1OSw2MCw2
+MSwtMiwtMiwtMiwtMSwtMiwtMiwtMiwwLDEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1
+LDE2LDE3LDE4LDE5LDIwLDIxLDIyLDIzLDI0LDI1LC0yLC0yLC0yLC0yLDYzLC0yLDI2LDI3LDI4LDI5
+LDMwLDMxLDMyLDMzLDM0LDM1LDM2LDM3LDM4LDM5LDQwLDQxLDQyLDQzLDQ0LDQ1LDQ2LDQ3LDQ4LDQ5
+LDUwLDUxLC0yLC0yLC0yLC0yLC0yXSx1LnQpKSl9KQp0KCQsIk01IiwiT3giLGZ1bmN0aW9uKCl7cmV0
+dXJuIHR5cGVvZiBwcm9jZXNzIT0idW5kZWZpbmVkIiYmT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5j
+YWxsKHByb2Nlc3MpPT0iW29iamVjdCBwcm9jZXNzXSImJnByb2Nlc3MucGxhdGZvcm09PSJ3aW4zMiJ9
+KQp0KCQsIm1mIiwiejQiLGZ1bmN0aW9uKCl7cmV0dXJuIFAubnUoIl5bXFwtXFwuMC05QS1aX2Eten5d
+KiQiKX0pCnQoJCwiQXYiLCJwNiIsZnVuY3Rpb24oKXtyZXR1cm4gbmV3IEVycm9yKCkuc3RhY2shPXZv
+aWQgMH0pCnQoJCwiSkciLCJ2WiIsZnVuY3Rpb24oKXtyZXR1cm4gUC5LTigpfSkKdCgkLCJTQyIsIkFO
+IixmdW5jdGlvbigpe3JldHVybiBQLnRNKFsiQSIsIkFCQlIiLCJBQ1JPTllNIiwiQUREUkVTUyIsIkFS
+RUEiLCJBUlRJQ0xFIiwiQVNJREUiLCJBVURJTyIsIkIiLCJCREkiLCJCRE8iLCJCSUciLCJCTE9DS1FV
+T1RFIiwiQlIiLCJCVVRUT04iLCJDQU5WQVMiLCJDQVBUSU9OIiwiQ0VOVEVSIiwiQ0lURSIsIkNPREUi
+LCJDT0wiLCJDT0xHUk9VUCIsIkNPTU1BTkQiLCJEQVRBIiwiREFUQUxJU1QiLCJERCIsIkRFTCIsIkRF
+VEFJTFMiLCJERk4iLCJESVIiLCJESVYiLCJETCIsIkRUIiwiRU0iLCJGSUVMRFNFVCIsIkZJR0NBUFRJ
+T04iLCJGSUdVUkUiLCJGT05UIiwiRk9PVEVSIiwiRk9STSIsIkgxIiwiSDIiLCJIMyIsIkg0IiwiSDUi
+LCJINiIsIkhFQURFUiIsIkhHUk9VUCIsIkhSIiwiSSIsIklGUkFNRSIsIklNRyIsIklOUFVUIiwiSU5T
+IiwiS0JEIiwiTEFCRUwiLCJMRUdFTkQiLCJMSSIsIk1BUCIsIk1BUksiLCJNRU5VIiwiTUVURVIiLCJO
+QVYiLCJOT0JSIiwiT0wiLCJPUFRHUk9VUCIsIk9QVElPTiIsIk9VVFBVVCIsIlAiLCJQUkUiLCJQUk9H
+UkVTUyIsIlEiLCJTIiwiU0FNUCIsIlNFQ1RJT04iLCJTRUxFQ1QiLCJTTUFMTCIsIlNPVVJDRSIsIlNQ
+QU4iLCJTVFJJS0UiLCJTVFJPTkciLCJTVUIiLCJTVU1NQVJZIiwiU1VQIiwiVEFCTEUiLCJUQk9EWSIs
+IlREIiwiVEVYVEFSRUEiLCJURk9PVCIsIlRIIiwiVEhFQUQiLCJUSU1FIiwiVFIiLCJUUkFDSyIsIlRU
+IiwiVSIsIlVMIiwiVkFSIiwiVklERU8iLCJXQlIiXSx1Lk4pfSkKdCgkLCJYNCIsImhHIixmdW5jdGlv
+bigpe3JldHVybiBQLm51KCJeXFxTKyQiKX0pCnQoJCwid08iLCJvdyIsZnVuY3Rpb24oKXtyZXR1cm4g
+dS5tLmEoUC5ORChzZWxmKSl9KQp0KCQsImt0IiwiQ3IiLGZ1bmN0aW9uKCl7cmV0dXJuIEguWWcoIl8k
+ZGFydF9kYXJ0T2JqZWN0Iil9KQp0KCQsImZLIiwia0kiLGZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9u
+IERhcnRPYmplY3QoYSl7dGhpcy5vPWF9fSkKdCgkLCJxdCIsInpCIixmdW5jdGlvbigpe3JldHVybiBu
+ZXcgVC5tUSgpfSkKdCgkLCJPbCIsIlVFIixmdW5jdGlvbigpe3JldHVybiBQLmhLKEMub2wuZ21XKFcu
+eDMoKSkuaHJlZikuZ2hZKCkucSgwLCJhdXRoVG9rZW4iKX0pCnQoJCwiaFQiLCJ5UCIsZnVuY3Rpb24o
+KXtyZXR1cm4gVy5acigpLnF1ZXJ5U2VsZWN0b3IoIi5lZGl0LWxpc3QgLnBhbmVsLWNvbnRlbnQiKX0p
+CnQoJCwiVzYiLCJoTCIsZnVuY3Rpb24oKXtyZXR1cm4gVy5acigpLnF1ZXJ5U2VsZWN0b3IoIi5lZGl0
+LXBhbmVsIC5wYW5lbC1jb250ZW50Iil9KQp0KCQsIlRSIiwiRFciLGZ1bmN0aW9uKCl7cmV0dXJuIFcu
+WnIoKS5xdWVyeVNlbGVjdG9yKCJmb290ZXIiKX0pCnQoJCwiRVkiLCJmaSIsZnVuY3Rpb24oKXtyZXR1
+cm4gVy5acigpLnF1ZXJ5U2VsZWN0b3IoImhlYWRlciIpfSkKdCgkLCJhdiIsIkQ5IixmdW5jdGlvbigp
+e3JldHVybiBXLlpyKCkucXVlcnlTZWxlY3RvcigiI3VuaXQtbmFtZSIpfSkKdCgkLCJmZSIsIktHIixm
+dW5jdGlvbigpe3JldHVybiBuZXcgTC5YQSgpfSkKdCgkLCJlbyIsIm5VIixmdW5jdGlvbigpe3JldHVy
+biBuZXcgTS5sSSgkLkhrKCkpfSkKdCgkLCJ5ciIsImJEIixmdW5jdGlvbigpe3JldHVybiBuZXcgRS5P
+RihQLm51KCIvIiksUC5udSgiW14vXSQiKSxQLm51KCJeLyIpKX0pCnQoJCwiTWsiLCJLayIsZnVuY3Rp
+b24oKXtyZXR1cm4gbmV3IEwuSVYoUC5udSgiWy9cXFxcXSIpLFAubnUoIlteL1xcXFxdJCIpLFAubnUo
+Il4oXFxcXFxcXFxbXlxcXFxdK1xcXFxbXlxcXFwvXSt8W2EtekEtWl06Wy9cXFxcXSkiKSxQLm51KCJe
+Wy9cXFxcXSg/IVsvXFxcXF0pIikpfSkKdCgkLCJhayIsIkViIixmdW5jdGlvbigpe3JldHVybiBuZXcg
+Ri5ydShQLm51KCIvIiksUC5udSgiKF5bYS16QS1aXVstKy5hLXpBLVpcXGRdKjovL3xbXi9dKSQiKSxQ
+Lm51KCJbYS16QS1aXVstKy5hLXpBLVpcXGRdKjovL1teL10qIiksUC5udSgiXi8iKSl9KQp0KCQsImxz
+IiwiSGsiLGZ1bmN0aW9uKCl7cmV0dXJuIE8uUmgoKX0pfSkoKTsoZnVuY3Rpb24gbmF0aXZlU3VwcG9y
+dCgpeyFmdW5jdGlvbigpe3ZhciB0PWZ1bmN0aW9uKGEpe3ZhciBuPXt9Cm5bYV09MQpyZXR1cm4gT2Jq
+ZWN0LmtleXMoaHVua0hlbHBlcnMuY29udmVydFRvRmFzdE9iamVjdChuKSlbMF19CnYuZ2V0SXNvbGF0
+ZVRhZz1mdW5jdGlvbihhKXtyZXR1cm4gdCgiX19fZGFydF8iK2Erdi5pc29sYXRlVGFnKX0KdmFyIHM9
+Il9fX2RhcnRfaXNvbGF0ZV90YWdzXyIKdmFyIHI9T2JqZWN0W3NdfHwoT2JqZWN0W3NdPU9iamVjdC5j
+cmVhdGUobnVsbCkpCnZhciBxPSJfWnhZeFgiCmZvcih2YXIgcD0wOztwKyspe3ZhciBvPXQocSsiXyIr
+cCsiXyIpCmlmKCEobyBpbiByKSl7cltvXT0xCnYuaXNvbGF0ZVRhZz1vCmJyZWFrfX12LmRpc3BhdGNo
+UHJvcGVydHlOYW1lPXYuZ2V0SXNvbGF0ZVRhZygiZGlzcGF0Y2hfcmVjb3JkIil9KCkKaHVua0hlbHBl
+cnMuc2V0T3JVcGRhdGVJbnRlcmNlcHRvcnNCeVRhZyh7RE9NRXJyb3I6Si52QixET01JbXBsZW1lbnRh
+dGlvbjpKLnZCLE1lZGlhRXJyb3I6Si52QixOYXZpZ2F0b3I6Si52QixOYXZpZ2F0b3JDb25jdXJyZW50
+SGFyZHdhcmU6Si52QixOYXZpZ2F0b3JVc2VyTWVkaWFFcnJvcjpKLnZCLE92ZXJjb25zdHJhaW5lZEVy
+cm9yOkoudkIsUG9zaXRpb25FcnJvcjpKLnZCLFJhbmdlOkoudkIsU1FMRXJyb3I6Si52QixEYXRhVmll
+dzpILmVILEFycmF5QnVmZmVyVmlldzpILmVILEZsb2F0MzJBcnJheTpILkRnLEZsb2F0NjRBcnJheTpI
+LkRnLEludDE2QXJyYXk6SC54aixJbnQzMkFycmF5OkguZEUsSW50OEFycmF5OkguWkEsVWludDE2QXJy
+YXk6SC53ZixVaW50MzJBcnJheTpILlBxLFVpbnQ4Q2xhbXBlZEFycmF5OkguZUUsQ2FudmFzUGl4ZWxB
+cnJheTpILmVFLFVpbnQ4QXJyYXk6SC5WNixIVE1MQXVkaW9FbGVtZW50OlcucUUsSFRNTEJSRWxlbWVu
+dDpXLnFFLEhUTUxCdXR0b25FbGVtZW50OlcucUUsSFRNTENhbnZhc0VsZW1lbnQ6Vy5xRSxIVE1MQ29u
+dGVudEVsZW1lbnQ6Vy5xRSxIVE1MRExpc3RFbGVtZW50OlcucUUsSFRNTERhdGFFbGVtZW50OlcucUUs
+SFRNTERhdGFMaXN0RWxlbWVudDpXLnFFLEhUTUxEZXRhaWxzRWxlbWVudDpXLnFFLEhUTUxEaWFsb2dF
+bGVtZW50OlcucUUsSFRNTERpdkVsZW1lbnQ6Vy5xRSxIVE1MRW1iZWRFbGVtZW50OlcucUUsSFRNTEZp
+ZWxkU2V0RWxlbWVudDpXLnFFLEhUTUxIUkVsZW1lbnQ6Vy5xRSxIVE1MSGVhZEVsZW1lbnQ6Vy5xRSxI
+VE1MSGVhZGluZ0VsZW1lbnQ6Vy5xRSxIVE1MSHRtbEVsZW1lbnQ6Vy5xRSxIVE1MSUZyYW1lRWxlbWVu
+dDpXLnFFLEhUTUxJbWFnZUVsZW1lbnQ6Vy5xRSxIVE1MSW5wdXRFbGVtZW50OlcucUUsSFRNTExJRWxl
+bWVudDpXLnFFLEhUTUxMYWJlbEVsZW1lbnQ6Vy5xRSxIVE1MTGVnZW5kRWxlbWVudDpXLnFFLEhUTUxM
+aW5rRWxlbWVudDpXLnFFLEhUTUxNYXBFbGVtZW50OlcucUUsSFRNTE1lZGlhRWxlbWVudDpXLnFFLEhU
+TUxNZW51RWxlbWVudDpXLnFFLEhUTUxNZXRhRWxlbWVudDpXLnFFLEhUTUxNZXRlckVsZW1lbnQ6Vy5x
+RSxIVE1MTW9kRWxlbWVudDpXLnFFLEhUTUxPTGlzdEVsZW1lbnQ6Vy5xRSxIVE1MT2JqZWN0RWxlbWVu
+dDpXLnFFLEhUTUxPcHRHcm91cEVsZW1lbnQ6Vy5xRSxIVE1MT3B0aW9uRWxlbWVudDpXLnFFLEhUTUxP
+dXRwdXRFbGVtZW50OlcucUUsSFRNTFBhcmFtRWxlbWVudDpXLnFFLEhUTUxQaWN0dXJlRWxlbWVudDpX
+LnFFLEhUTUxQcmVFbGVtZW50OlcucUUsSFRNTFByb2dyZXNzRWxlbWVudDpXLnFFLEhUTUxRdW90ZUVs
+ZW1lbnQ6Vy5xRSxIVE1MU2NyaXB0RWxlbWVudDpXLnFFLEhUTUxTaGFkb3dFbGVtZW50OlcucUUsSFRN
+TFNsb3RFbGVtZW50OlcucUUsSFRNTFNvdXJjZUVsZW1lbnQ6Vy5xRSxIVE1MU3BhbkVsZW1lbnQ6Vy5x
+RSxIVE1MU3R5bGVFbGVtZW50OlcucUUsSFRNTFRhYmxlQ2FwdGlvbkVsZW1lbnQ6Vy5xRSxIVE1MVGFi
+bGVDZWxsRWxlbWVudDpXLnFFLEhUTUxUYWJsZURhdGFDZWxsRWxlbWVudDpXLnFFLEhUTUxUYWJsZUhl
+YWRlckNlbGxFbGVtZW50OlcucUUsSFRNTFRhYmxlQ29sRWxlbWVudDpXLnFFLEhUTUxUZXh0QXJlYUVs
+ZW1lbnQ6Vy5xRSxIVE1MVGltZUVsZW1lbnQ6Vy5xRSxIVE1MVGl0bGVFbGVtZW50OlcucUUsSFRNTFRy
+YWNrRWxlbWVudDpXLnFFLEhUTUxVTGlzdEVsZW1lbnQ6Vy5xRSxIVE1MVW5rbm93bkVsZW1lbnQ6Vy5x
+RSxIVE1MVmlkZW9FbGVtZW50OlcucUUsSFRNTERpcmVjdG9yeUVsZW1lbnQ6Vy5xRSxIVE1MRm9udEVs
+ZW1lbnQ6Vy5xRSxIVE1MRnJhbWVFbGVtZW50OlcucUUsSFRNTEZyYW1lU2V0RWxlbWVudDpXLnFFLEhU
+TUxNYXJxdWVlRWxlbWVudDpXLnFFLEhUTUxFbGVtZW50OlcucUUsSFRNTEFuY2hvckVsZW1lbnQ6Vy5H
+aCxIVE1MQXJlYUVsZW1lbnQ6Vy5mWSxIVE1MQmFzZUVsZW1lbnQ6Vy5uQixCbG9iOlcuQXosSFRNTEJv
+ZHlFbGVtZW50OlcuUVAsQ0RBVEFTZWN0aW9uOlcubngsQ2hhcmFjdGVyRGF0YTpXLm54LENvbW1lbnQ6
+Vy5ueCxQcm9jZXNzaW5nSW5zdHJ1Y3Rpb246Vy5ueCxUZXh0OlcubngsQ1NTU3R5bGVEZWNsYXJhdGlv
+bjpXLm9KLE1TU3R5bGVDU1NQcm9wZXJ0aWVzOlcub0osQ1NTMlByb3BlcnRpZXM6Vy5vSixYTUxEb2N1
+bWVudDpXLlFGLERvY3VtZW50OlcuUUYsRE9NRXhjZXB0aW9uOlcuTmgsRE9NUmVjdFJlYWRPbmx5Olcu
+SUIsRE9NVG9rZW5MaXN0OlcubjcsRWxlbWVudDpXLmN2LEFib3J0UGF5bWVudEV2ZW50OlcuZWEsQW5p
+bWF0aW9uRXZlbnQ6Vy5lYSxBbmltYXRpb25QbGF5YmFja0V2ZW50OlcuZWEsQXBwbGljYXRpb25DYWNo
+ZUVycm9yRXZlbnQ6Vy5lYSxCYWNrZ3JvdW5kRmV0Y2hDbGlja0V2ZW50OlcuZWEsQmFja2dyb3VuZEZl
+dGNoRXZlbnQ6Vy5lYSxCYWNrZ3JvdW5kRmV0Y2hGYWlsRXZlbnQ6Vy5lYSxCYWNrZ3JvdW5kRmV0Y2hl
+ZEV2ZW50OlcuZWEsQmVmb3JlSW5zdGFsbFByb21wdEV2ZW50OlcuZWEsQmVmb3JlVW5sb2FkRXZlbnQ6
+Vy5lYSxCbG9iRXZlbnQ6Vy5lYSxDYW5NYWtlUGF5bWVudEV2ZW50OlcuZWEsQ2xpcGJvYXJkRXZlbnQ6
+Vy5lYSxDbG9zZUV2ZW50OlcuZWEsQ3VzdG9tRXZlbnQ6Vy5lYSxEZXZpY2VNb3Rpb25FdmVudDpXLmVh
+LERldmljZU9yaWVudGF0aW9uRXZlbnQ6Vy5lYSxFcnJvckV2ZW50OlcuZWEsRXh0ZW5kYWJsZUV2ZW50
+OlcuZWEsRXh0ZW5kYWJsZU1lc3NhZ2VFdmVudDpXLmVhLEZldGNoRXZlbnQ6Vy5lYSxGb250RmFjZVNl
+dExvYWRFdmVudDpXLmVhLEZvcmVpZ25GZXRjaEV2ZW50OlcuZWEsR2FtZXBhZEV2ZW50OlcuZWEsSGFz
+aENoYW5nZUV2ZW50OlcuZWEsSW5zdGFsbEV2ZW50OlcuZWEsTWVkaWFFbmNyeXB0ZWRFdmVudDpXLmVh
+LE1lZGlhS2V5TWVzc2FnZUV2ZW50OlcuZWEsTWVkaWFRdWVyeUxpc3RFdmVudDpXLmVhLE1lZGlhU3Ry
+ZWFtRXZlbnQ6Vy5lYSxNZWRpYVN0cmVhbVRyYWNrRXZlbnQ6Vy5lYSxNZXNzYWdlRXZlbnQ6Vy5lYSxN
+SURJQ29ubmVjdGlvbkV2ZW50OlcuZWEsTUlESU1lc3NhZ2VFdmVudDpXLmVhLE11dGF0aW9uRXZlbnQ6
+Vy5lYSxOb3RpZmljYXRpb25FdmVudDpXLmVhLFBhZ2VUcmFuc2l0aW9uRXZlbnQ6Vy5lYSxQYXltZW50
+UmVxdWVzdEV2ZW50OlcuZWEsUGF5bWVudFJlcXVlc3RVcGRhdGVFdmVudDpXLmVhLFBvcFN0YXRlRXZl
+bnQ6Vy5lYSxQcmVzZW50YXRpb25Db25uZWN0aW9uQXZhaWxhYmxlRXZlbnQ6Vy5lYSxQcmVzZW50YXRp
+b25Db25uZWN0aW9uQ2xvc2VFdmVudDpXLmVhLFByb21pc2VSZWplY3Rpb25FdmVudDpXLmVhLFB1c2hF
+dmVudDpXLmVhLFJUQ0RhdGFDaGFubmVsRXZlbnQ6Vy5lYSxSVENEVE1GVG9uZUNoYW5nZUV2ZW50Olcu
+ZWEsUlRDUGVlckNvbm5lY3Rpb25JY2VFdmVudDpXLmVhLFJUQ1RyYWNrRXZlbnQ6Vy5lYSxTZWN1cml0
+eVBvbGljeVZpb2xhdGlvbkV2ZW50OlcuZWEsU2Vuc29yRXJyb3JFdmVudDpXLmVhLFNwZWVjaFJlY29n
+bml0aW9uRXJyb3I6Vy5lYSxTcGVlY2hSZWNvZ25pdGlvbkV2ZW50OlcuZWEsU3BlZWNoU3ludGhlc2lz
+RXZlbnQ6Vy5lYSxTdG9yYWdlRXZlbnQ6Vy5lYSxTeW5jRXZlbnQ6Vy5lYSxUcmFja0V2ZW50OlcuZWEs
+VHJhbnNpdGlvbkV2ZW50OlcuZWEsV2ViS2l0VHJhbnNpdGlvbkV2ZW50OlcuZWEsVlJEZXZpY2VFdmVu
+dDpXLmVhLFZSRGlzcGxheUV2ZW50OlcuZWEsVlJTZXNzaW9uRXZlbnQ6Vy5lYSxNb2pvSW50ZXJmYWNl
+UmVxdWVzdEV2ZW50OlcuZWEsVVNCQ29ubmVjdGlvbkV2ZW50OlcuZWEsSURCVmVyc2lvbkNoYW5nZUV2
+ZW50OlcuZWEsQXVkaW9Qcm9jZXNzaW5nRXZlbnQ6Vy5lYSxPZmZsaW5lQXVkaW9Db21wbGV0aW9uRXZl
+bnQ6Vy5lYSxXZWJHTENvbnRleHRFdmVudDpXLmVhLEV2ZW50OlcuZWEsSW5wdXRFdmVudDpXLmVhLFN1
+Ym1pdEV2ZW50OlcuZWEsRXZlbnRUYXJnZXQ6Vy5EMCxGaWxlOlcuaEgsSFRNTEZvcm1FbGVtZW50Olcu
+aDQsSGlzdG9yeTpXLmJyLEhUTUxEb2N1bWVudDpXLlZiLFhNTEh0dHBSZXF1ZXN0OlcuZkosWE1MSHR0
+cFJlcXVlc3RFdmVudFRhcmdldDpXLndhLEltYWdlRGF0YTpXLlNnLExvY2F0aW9uOlcudTgsTW91c2VF
+dmVudDpXLk9LLERyYWdFdmVudDpXLk9LLFBvaW50ZXJFdmVudDpXLk9LLFdoZWVsRXZlbnQ6Vy5PSyxE
+b2N1bWVudEZyYWdtZW50OlcudUgsU2hhZG93Um9vdDpXLnVILERvY3VtZW50VHlwZTpXLnVILE5vZGU6
+Vy51SCxOb2RlTGlzdDpXLkJILFJhZGlvTm9kZUxpc3Q6Vy5CSCxIVE1MUGFyYWdyYXBoRWxlbWVudDpX
+LlNOLFByb2dyZXNzRXZlbnQ6Vy5ldyxSZXNvdXJjZVByb2dyZXNzRXZlbnQ6Vy5ldyxIVE1MU2VsZWN0
+RWxlbWVudDpXLmxwLEhUTUxUYWJsZUVsZW1lbnQ6Vy5UYixIVE1MVGFibGVSb3dFbGVtZW50OlcuSXYs
+SFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQ6Vy5XUCxIVE1MVGVtcGxhdGVFbGVtZW50OlcueVksQ29tcG9z
+aXRpb25FdmVudDpXLnc2LEZvY3VzRXZlbnQ6Vy53NixLZXlib2FyZEV2ZW50OlcudzYsVGV4dEV2ZW50
+OlcudzYsVG91Y2hFdmVudDpXLnc2LFVJRXZlbnQ6Vy53NixXaW5kb3c6Vy5LNSxET01XaW5kb3c6Vy5L
+NSxEZWRpY2F0ZWRXb3JrZXJHbG9iYWxTY29wZTpXLkNtLFNlcnZpY2VXb3JrZXJHbG9iYWxTY29wZTpX
+LkNtLFNoYXJlZFdvcmtlckdsb2JhbFNjb3BlOlcuQ20sV29ya2VyR2xvYmFsU2NvcGU6Vy5DbSxBdHRy
+OlcuQ1EsQ2xpZW50UmVjdDpXLnc0LERPTVJlY3Q6Vy53NCxOYW1lZE5vZGVNYXA6Vy5yaCxNb3pOYW1l
+ZEF0dHJNYXA6Vy5yaCxJREJLZXlSYW5nZTpQLmhGLFNWR1NjcmlwdEVsZW1lbnQ6UC5uZCxTVkdBRWxl
+bWVudDpQLmQ1LFNWR0FuaW1hdGVFbGVtZW50OlAuZDUsU1ZHQW5pbWF0ZU1vdGlvbkVsZW1lbnQ6UC5k
+NSxTVkdBbmltYXRlVHJhbnNmb3JtRWxlbWVudDpQLmQ1LFNWR0FuaW1hdGlvbkVsZW1lbnQ6UC5kNSxT
+VkdDaXJjbGVFbGVtZW50OlAuZDUsU1ZHQ2xpcFBhdGhFbGVtZW50OlAuZDUsU1ZHRGVmc0VsZW1lbnQ6
+UC5kNSxTVkdEZXNjRWxlbWVudDpQLmQ1LFNWR0Rpc2NhcmRFbGVtZW50OlAuZDUsU1ZHRWxsaXBzZUVs
+ZW1lbnQ6UC5kNSxTVkdGRUJsZW5kRWxlbWVudDpQLmQ1LFNWR0ZFQ29sb3JNYXRyaXhFbGVtZW50OlAu
+ZDUsU1ZHRkVDb21wb25lbnRUcmFuc2ZlckVsZW1lbnQ6UC5kNSxTVkdGRUNvbXBvc2l0ZUVsZW1lbnQ6
+UC5kNSxTVkdGRUNvbnZvbHZlTWF0cml4RWxlbWVudDpQLmQ1LFNWR0ZFRGlmZnVzZUxpZ2h0aW5nRWxl
+bWVudDpQLmQ1LFNWR0ZFRGlzcGxhY2VtZW50TWFwRWxlbWVudDpQLmQ1LFNWR0ZFRGlzdGFudExpZ2h0
+RWxlbWVudDpQLmQ1LFNWR0ZFRmxvb2RFbGVtZW50OlAuZDUsU1ZHRkVGdW5jQUVsZW1lbnQ6UC5kNSxT
+VkdGRUZ1bmNCRWxlbWVudDpQLmQ1LFNWR0ZFRnVuY0dFbGVtZW50OlAuZDUsU1ZHRkVGdW5jUkVsZW1l
+bnQ6UC5kNSxTVkdGRUdhdXNzaWFuQmx1ckVsZW1lbnQ6UC5kNSxTVkdGRUltYWdlRWxlbWVudDpQLmQ1
+LFNWR0ZFTWVyZ2VFbGVtZW50OlAuZDUsU1ZHRkVNZXJnZU5vZGVFbGVtZW50OlAuZDUsU1ZHRkVNb3Jw
+aG9sb2d5RWxlbWVudDpQLmQ1LFNWR0ZFT2Zmc2V0RWxlbWVudDpQLmQ1LFNWR0ZFUG9pbnRMaWdodEVs
+ZW1lbnQ6UC5kNSxTVkdGRVNwZWN1bGFyTGlnaHRpbmdFbGVtZW50OlAuZDUsU1ZHRkVTcG90TGlnaHRF
+bGVtZW50OlAuZDUsU1ZHRkVUaWxlRWxlbWVudDpQLmQ1LFNWR0ZFVHVyYnVsZW5jZUVsZW1lbnQ6UC5k
+NSxTVkdGaWx0ZXJFbGVtZW50OlAuZDUsU1ZHRm9yZWlnbk9iamVjdEVsZW1lbnQ6UC5kNSxTVkdHRWxl
+bWVudDpQLmQ1LFNWR0dlb21ldHJ5RWxlbWVudDpQLmQ1LFNWR0dyYXBoaWNzRWxlbWVudDpQLmQ1LFNW
+R0ltYWdlRWxlbWVudDpQLmQ1LFNWR0xpbmVFbGVtZW50OlAuZDUsU1ZHTGluZWFyR3JhZGllbnRFbGVt
+ZW50OlAuZDUsU1ZHTWFya2VyRWxlbWVudDpQLmQ1LFNWR01hc2tFbGVtZW50OlAuZDUsU1ZHTWV0YWRh
+dGFFbGVtZW50OlAuZDUsU1ZHUGF0aEVsZW1lbnQ6UC5kNSxTVkdQYXR0ZXJuRWxlbWVudDpQLmQ1LFNW
+R1BvbHlnb25FbGVtZW50OlAuZDUsU1ZHUG9seWxpbmVFbGVtZW50OlAuZDUsU1ZHUmFkaWFsR3JhZGll
+bnRFbGVtZW50OlAuZDUsU1ZHUmVjdEVsZW1lbnQ6UC5kNSxTVkdTZXRFbGVtZW50OlAuZDUsU1ZHU3Rv
+cEVsZW1lbnQ6UC5kNSxTVkdTdHlsZUVsZW1lbnQ6UC5kNSxTVkdTVkdFbGVtZW50OlAuZDUsU1ZHU3dp
+dGNoRWxlbWVudDpQLmQ1LFNWR1N5bWJvbEVsZW1lbnQ6UC5kNSxTVkdUU3BhbkVsZW1lbnQ6UC5kNSxT
+VkdUZXh0Q29udGVudEVsZW1lbnQ6UC5kNSxTVkdUZXh0RWxlbWVudDpQLmQ1LFNWR1RleHRQYXRoRWxl
+bWVudDpQLmQ1LFNWR1RleHRQb3NpdGlvbmluZ0VsZW1lbnQ6UC5kNSxTVkdUaXRsZUVsZW1lbnQ6UC5k
+NSxTVkdVc2VFbGVtZW50OlAuZDUsU1ZHVmlld0VsZW1lbnQ6UC5kNSxTVkdHcmFkaWVudEVsZW1lbnQ6
+UC5kNSxTVkdDb21wb25lbnRUcmFuc2ZlckZ1bmN0aW9uRWxlbWVudDpQLmQ1LFNWR0ZFRHJvcFNoYWRv
+d0VsZW1lbnQ6UC5kNSxTVkdNUGF0aEVsZW1lbnQ6UC5kNSxTVkdFbGVtZW50OlAuZDV9KQpodW5rSGVs
+cGVycy5zZXRPclVwZGF0ZUxlYWZUYWdzKHtET01FcnJvcjp0cnVlLERPTUltcGxlbWVudGF0aW9uOnRy
+dWUsTWVkaWFFcnJvcjp0cnVlLE5hdmlnYXRvcjp0cnVlLE5hdmlnYXRvckNvbmN1cnJlbnRIYXJkd2Fy
+ZTp0cnVlLE5hdmlnYXRvclVzZXJNZWRpYUVycm9yOnRydWUsT3ZlcmNvbnN0cmFpbmVkRXJyb3I6dHJ1
+ZSxQb3NpdGlvbkVycm9yOnRydWUsUmFuZ2U6dHJ1ZSxTUUxFcnJvcjp0cnVlLERhdGFWaWV3OnRydWUs
+QXJyYXlCdWZmZXJWaWV3OmZhbHNlLEZsb2F0MzJBcnJheTp0cnVlLEZsb2F0NjRBcnJheTp0cnVlLElu
+dDE2QXJyYXk6dHJ1ZSxJbnQzMkFycmF5OnRydWUsSW50OEFycmF5OnRydWUsVWludDE2QXJyYXk6dHJ1
+ZSxVaW50MzJBcnJheTp0cnVlLFVpbnQ4Q2xhbXBlZEFycmF5OnRydWUsQ2FudmFzUGl4ZWxBcnJheTp0
+cnVlLFVpbnQ4QXJyYXk6ZmFsc2UsSFRNTEF1ZGlvRWxlbWVudDp0cnVlLEhUTUxCUkVsZW1lbnQ6dHJ1
+ZSxIVE1MQnV0dG9uRWxlbWVudDp0cnVlLEhUTUxDYW52YXNFbGVtZW50OnRydWUsSFRNTENvbnRlbnRF
+bGVtZW50OnRydWUsSFRNTERMaXN0RWxlbWVudDp0cnVlLEhUTUxEYXRhRWxlbWVudDp0cnVlLEhUTUxE
+YXRhTGlzdEVsZW1lbnQ6dHJ1ZSxIVE1MRGV0YWlsc0VsZW1lbnQ6dHJ1ZSxIVE1MRGlhbG9nRWxlbWVu
+dDp0cnVlLEhUTUxEaXZFbGVtZW50OnRydWUsSFRNTEVtYmVkRWxlbWVudDp0cnVlLEhUTUxGaWVsZFNl
+dEVsZW1lbnQ6dHJ1ZSxIVE1MSFJFbGVtZW50OnRydWUsSFRNTEhlYWRFbGVtZW50OnRydWUsSFRNTEhl
+YWRpbmdFbGVtZW50OnRydWUsSFRNTEh0bWxFbGVtZW50OnRydWUsSFRNTElGcmFtZUVsZW1lbnQ6dHJ1
+ZSxIVE1MSW1hZ2VFbGVtZW50OnRydWUsSFRNTElucHV0RWxlbWVudDp0cnVlLEhUTUxMSUVsZW1lbnQ6
+dHJ1ZSxIVE1MTGFiZWxFbGVtZW50OnRydWUsSFRNTExlZ2VuZEVsZW1lbnQ6dHJ1ZSxIVE1MTGlua0Vs
+ZW1lbnQ6dHJ1ZSxIVE1MTWFwRWxlbWVudDp0cnVlLEhUTUxNZWRpYUVsZW1lbnQ6dHJ1ZSxIVE1MTWVu
+dUVsZW1lbnQ6dHJ1ZSxIVE1MTWV0YUVsZW1lbnQ6dHJ1ZSxIVE1MTWV0ZXJFbGVtZW50OnRydWUsSFRN
+TE1vZEVsZW1lbnQ6dHJ1ZSxIVE1MT0xpc3RFbGVtZW50OnRydWUsSFRNTE9iamVjdEVsZW1lbnQ6dHJ1
+ZSxIVE1MT3B0R3JvdXBFbGVtZW50OnRydWUsSFRNTE9wdGlvbkVsZW1lbnQ6dHJ1ZSxIVE1MT3V0cHV0
+RWxlbWVudDp0cnVlLEhUTUxQYXJhbUVsZW1lbnQ6dHJ1ZSxIVE1MUGljdHVyZUVsZW1lbnQ6dHJ1ZSxI
+VE1MUHJlRWxlbWVudDp0cnVlLEhUTUxQcm9ncmVzc0VsZW1lbnQ6dHJ1ZSxIVE1MUXVvdGVFbGVtZW50
+OnRydWUsSFRNTFNjcmlwdEVsZW1lbnQ6dHJ1ZSxIVE1MU2hhZG93RWxlbWVudDp0cnVlLEhUTUxTbG90
+RWxlbWVudDp0cnVlLEhUTUxTb3VyY2VFbGVtZW50OnRydWUsSFRNTFNwYW5FbGVtZW50OnRydWUsSFRN
+TFN0eWxlRWxlbWVudDp0cnVlLEhUTUxUYWJsZUNhcHRpb25FbGVtZW50OnRydWUsSFRNTFRhYmxlQ2Vs
+bEVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVEYXRhQ2VsbEVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVIZWFkZXJD
+ZWxsRWxlbWVudDp0cnVlLEhUTUxUYWJsZUNvbEVsZW1lbnQ6dHJ1ZSxIVE1MVGV4dEFyZWFFbGVtZW50
+OnRydWUsSFRNTFRpbWVFbGVtZW50OnRydWUsSFRNTFRpdGxlRWxlbWVudDp0cnVlLEhUTUxUcmFja0Vs
+ZW1lbnQ6dHJ1ZSxIVE1MVUxpc3RFbGVtZW50OnRydWUsSFRNTFVua25vd25FbGVtZW50OnRydWUsSFRN
+TFZpZGVvRWxlbWVudDp0cnVlLEhUTUxEaXJlY3RvcnlFbGVtZW50OnRydWUsSFRNTEZvbnRFbGVtZW50
+OnRydWUsSFRNTEZyYW1lRWxlbWVudDp0cnVlLEhUTUxGcmFtZVNldEVsZW1lbnQ6dHJ1ZSxIVE1MTWFy
+cXVlZUVsZW1lbnQ6dHJ1ZSxIVE1MRWxlbWVudDpmYWxzZSxIVE1MQW5jaG9yRWxlbWVudDp0cnVlLEhU
+TUxBcmVhRWxlbWVudDp0cnVlLEhUTUxCYXNlRWxlbWVudDp0cnVlLEJsb2I6ZmFsc2UsSFRNTEJvZHlF
+bGVtZW50OnRydWUsQ0RBVEFTZWN0aW9uOnRydWUsQ2hhcmFjdGVyRGF0YTp0cnVlLENvbW1lbnQ6dHJ1
+ZSxQcm9jZXNzaW5nSW5zdHJ1Y3Rpb246dHJ1ZSxUZXh0OnRydWUsQ1NTU3R5bGVEZWNsYXJhdGlvbjp0
+cnVlLE1TU3R5bGVDU1NQcm9wZXJ0aWVzOnRydWUsQ1NTMlByb3BlcnRpZXM6dHJ1ZSxYTUxEb2N1bWVu
+dDp0cnVlLERvY3VtZW50OmZhbHNlLERPTUV4Y2VwdGlvbjp0cnVlLERPTVJlY3RSZWFkT25seTpmYWxz
+ZSxET01Ub2tlbkxpc3Q6dHJ1ZSxFbGVtZW50OmZhbHNlLEFib3J0UGF5bWVudEV2ZW50OnRydWUsQW5p
+bWF0aW9uRXZlbnQ6dHJ1ZSxBbmltYXRpb25QbGF5YmFja0V2ZW50OnRydWUsQXBwbGljYXRpb25DYWNo
+ZUVycm9yRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5kRmV0Y2hDbGlja0V2ZW50OnRydWUsQmFja2dyb3VuZEZl
+dGNoRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5kRmV0Y2hGYWlsRXZlbnQ6dHJ1ZSxCYWNrZ3JvdW5kRmV0Y2hl
+ZEV2ZW50OnRydWUsQmVmb3JlSW5zdGFsbFByb21wdEV2ZW50OnRydWUsQmVmb3JlVW5sb2FkRXZlbnQ6
+dHJ1ZSxCbG9iRXZlbnQ6dHJ1ZSxDYW5NYWtlUGF5bWVudEV2ZW50OnRydWUsQ2xpcGJvYXJkRXZlbnQ6
+dHJ1ZSxDbG9zZUV2ZW50OnRydWUsQ3VzdG9tRXZlbnQ6dHJ1ZSxEZXZpY2VNb3Rpb25FdmVudDp0cnVl
+LERldmljZU9yaWVudGF0aW9uRXZlbnQ6dHJ1ZSxFcnJvckV2ZW50OnRydWUsRXh0ZW5kYWJsZUV2ZW50
+OnRydWUsRXh0ZW5kYWJsZU1lc3NhZ2VFdmVudDp0cnVlLEZldGNoRXZlbnQ6dHJ1ZSxGb250RmFjZVNl
+dExvYWRFdmVudDp0cnVlLEZvcmVpZ25GZXRjaEV2ZW50OnRydWUsR2FtZXBhZEV2ZW50OnRydWUsSGFz
+aENoYW5nZUV2ZW50OnRydWUsSW5zdGFsbEV2ZW50OnRydWUsTWVkaWFFbmNyeXB0ZWRFdmVudDp0cnVl
+LE1lZGlhS2V5TWVzc2FnZUV2ZW50OnRydWUsTWVkaWFRdWVyeUxpc3RFdmVudDp0cnVlLE1lZGlhU3Ry
+ZWFtRXZlbnQ6dHJ1ZSxNZWRpYVN0cmVhbVRyYWNrRXZlbnQ6dHJ1ZSxNZXNzYWdlRXZlbnQ6dHJ1ZSxN
+SURJQ29ubmVjdGlvbkV2ZW50OnRydWUsTUlESU1lc3NhZ2VFdmVudDp0cnVlLE11dGF0aW9uRXZlbnQ6
+dHJ1ZSxOb3RpZmljYXRpb25FdmVudDp0cnVlLFBhZ2VUcmFuc2l0aW9uRXZlbnQ6dHJ1ZSxQYXltZW50
+UmVxdWVzdEV2ZW50OnRydWUsUGF5bWVudFJlcXVlc3RVcGRhdGVFdmVudDp0cnVlLFBvcFN0YXRlRXZl
+bnQ6dHJ1ZSxQcmVzZW50YXRpb25Db25uZWN0aW9uQXZhaWxhYmxlRXZlbnQ6dHJ1ZSxQcmVzZW50YXRp
+b25Db25uZWN0aW9uQ2xvc2VFdmVudDp0cnVlLFByb21pc2VSZWplY3Rpb25FdmVudDp0cnVlLFB1c2hF
+dmVudDp0cnVlLFJUQ0RhdGFDaGFubmVsRXZlbnQ6dHJ1ZSxSVENEVE1GVG9uZUNoYW5nZUV2ZW50OnRy
+dWUsUlRDUGVlckNvbm5lY3Rpb25JY2VFdmVudDp0cnVlLFJUQ1RyYWNrRXZlbnQ6dHJ1ZSxTZWN1cml0
+eVBvbGljeVZpb2xhdGlvbkV2ZW50OnRydWUsU2Vuc29yRXJyb3JFdmVudDp0cnVlLFNwZWVjaFJlY29n
+bml0aW9uRXJyb3I6dHJ1ZSxTcGVlY2hSZWNvZ25pdGlvbkV2ZW50OnRydWUsU3BlZWNoU3ludGhlc2lz
+RXZlbnQ6dHJ1ZSxTdG9yYWdlRXZlbnQ6dHJ1ZSxTeW5jRXZlbnQ6dHJ1ZSxUcmFja0V2ZW50OnRydWUs
+VHJhbnNpdGlvbkV2ZW50OnRydWUsV2ViS2l0VHJhbnNpdGlvbkV2ZW50OnRydWUsVlJEZXZpY2VFdmVu
+dDp0cnVlLFZSRGlzcGxheUV2ZW50OnRydWUsVlJTZXNzaW9uRXZlbnQ6dHJ1ZSxNb2pvSW50ZXJmYWNl
+UmVxdWVzdEV2ZW50OnRydWUsVVNCQ29ubmVjdGlvbkV2ZW50OnRydWUsSURCVmVyc2lvbkNoYW5nZUV2
+ZW50OnRydWUsQXVkaW9Qcm9jZXNzaW5nRXZlbnQ6dHJ1ZSxPZmZsaW5lQXVkaW9Db21wbGV0aW9uRXZl
+bnQ6dHJ1ZSxXZWJHTENvbnRleHRFdmVudDp0cnVlLEV2ZW50OmZhbHNlLElucHV0RXZlbnQ6ZmFsc2Us
+U3VibWl0RXZlbnQ6ZmFsc2UsRXZlbnRUYXJnZXQ6ZmFsc2UsRmlsZTp0cnVlLEhUTUxGb3JtRWxlbWVu
+dDp0cnVlLEhpc3Rvcnk6dHJ1ZSxIVE1MRG9jdW1lbnQ6dHJ1ZSxYTUxIdHRwUmVxdWVzdDp0cnVlLFhN
+TEh0dHBSZXF1ZXN0RXZlbnRUYXJnZXQ6ZmFsc2UsSW1hZ2VEYXRhOnRydWUsTG9jYXRpb246dHJ1ZSxN
+b3VzZUV2ZW50OnRydWUsRHJhZ0V2ZW50OnRydWUsUG9pbnRlckV2ZW50OnRydWUsV2hlZWxFdmVudDp0
+cnVlLERvY3VtZW50RnJhZ21lbnQ6dHJ1ZSxTaGFkb3dSb290OnRydWUsRG9jdW1lbnRUeXBlOnRydWUs
+Tm9kZTpmYWxzZSxOb2RlTGlzdDp0cnVlLFJhZGlvTm9kZUxpc3Q6dHJ1ZSxIVE1MUGFyYWdyYXBoRWxl
+bWVudDp0cnVlLFByb2dyZXNzRXZlbnQ6dHJ1ZSxSZXNvdXJjZVByb2dyZXNzRXZlbnQ6dHJ1ZSxIVE1M
+U2VsZWN0RWxlbWVudDp0cnVlLEhUTUxUYWJsZUVsZW1lbnQ6dHJ1ZSxIVE1MVGFibGVSb3dFbGVtZW50
+OnRydWUsSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQ6dHJ1ZSxIVE1MVGVtcGxhdGVFbGVtZW50OnRydWUs
+Q29tcG9zaXRpb25FdmVudDp0cnVlLEZvY3VzRXZlbnQ6dHJ1ZSxLZXlib2FyZEV2ZW50OnRydWUsVGV4
+dEV2ZW50OnRydWUsVG91Y2hFdmVudDp0cnVlLFVJRXZlbnQ6ZmFsc2UsV2luZG93OnRydWUsRE9NV2lu
+ZG93OnRydWUsRGVkaWNhdGVkV29ya2VyR2xvYmFsU2NvcGU6dHJ1ZSxTZXJ2aWNlV29ya2VyR2xvYmFs
+U2NvcGU6dHJ1ZSxTaGFyZWRXb3JrZXJHbG9iYWxTY29wZTp0cnVlLFdvcmtlckdsb2JhbFNjb3BlOnRy
+dWUsQXR0cjp0cnVlLENsaWVudFJlY3Q6dHJ1ZSxET01SZWN0OnRydWUsTmFtZWROb2RlTWFwOnRydWUs
+TW96TmFtZWRBdHRyTWFwOnRydWUsSURCS2V5UmFuZ2U6dHJ1ZSxTVkdTY3JpcHRFbGVtZW50OnRydWUs
+U1ZHQUVsZW1lbnQ6dHJ1ZSxTVkdBbmltYXRlRWxlbWVudDp0cnVlLFNWR0FuaW1hdGVNb3Rpb25FbGVt
+ZW50OnRydWUsU1ZHQW5pbWF0ZVRyYW5zZm9ybUVsZW1lbnQ6dHJ1ZSxTVkdBbmltYXRpb25FbGVtZW50
+OnRydWUsU1ZHQ2lyY2xlRWxlbWVudDp0cnVlLFNWR0NsaXBQYXRoRWxlbWVudDp0cnVlLFNWR0RlZnNF
+bGVtZW50OnRydWUsU1ZHRGVzY0VsZW1lbnQ6dHJ1ZSxTVkdEaXNjYXJkRWxlbWVudDp0cnVlLFNWR0Vs
+bGlwc2VFbGVtZW50OnRydWUsU1ZHRkVCbGVuZEVsZW1lbnQ6dHJ1ZSxTVkdGRUNvbG9yTWF0cml4RWxl
+bWVudDp0cnVlLFNWR0ZFQ29tcG9uZW50VHJhbnNmZXJFbGVtZW50OnRydWUsU1ZHRkVDb21wb3NpdGVF
+bGVtZW50OnRydWUsU1ZHRkVDb252b2x2ZU1hdHJpeEVsZW1lbnQ6dHJ1ZSxTVkdGRURpZmZ1c2VMaWdo
+dGluZ0VsZW1lbnQ6dHJ1ZSxTVkdGRURpc3BsYWNlbWVudE1hcEVsZW1lbnQ6dHJ1ZSxTVkdGRURpc3Rh
+bnRMaWdodEVsZW1lbnQ6dHJ1ZSxTVkdGRUZsb29kRWxlbWVudDp0cnVlLFNWR0ZFRnVuY0FFbGVtZW50
+OnRydWUsU1ZHRkVGdW5jQkVsZW1lbnQ6dHJ1ZSxTVkdGRUZ1bmNHRWxlbWVudDp0cnVlLFNWR0ZFRnVu
+Y1JFbGVtZW50OnRydWUsU1ZHRkVHYXVzc2lhbkJsdXJFbGVtZW50OnRydWUsU1ZHRkVJbWFnZUVsZW1l
+bnQ6dHJ1ZSxTVkdGRU1lcmdlRWxlbWVudDp0cnVlLFNWR0ZFTWVyZ2VOb2RlRWxlbWVudDp0cnVlLFNW
+R0ZFTW9ycGhvbG9neUVsZW1lbnQ6dHJ1ZSxTVkdGRU9mZnNldEVsZW1lbnQ6dHJ1ZSxTVkdGRVBvaW50
+TGlnaHRFbGVtZW50OnRydWUsU1ZHRkVTcGVjdWxhckxpZ2h0aW5nRWxlbWVudDp0cnVlLFNWR0ZFU3Bv
+dExpZ2h0RWxlbWVudDp0cnVlLFNWR0ZFVGlsZUVsZW1lbnQ6dHJ1ZSxTVkdGRVR1cmJ1bGVuY2VFbGVt
+ZW50OnRydWUsU1ZHRmlsdGVyRWxlbWVudDp0cnVlLFNWR0ZvcmVpZ25PYmplY3RFbGVtZW50OnRydWUs
+U1ZHR0VsZW1lbnQ6dHJ1ZSxTVkdHZW9tZXRyeUVsZW1lbnQ6dHJ1ZSxTVkdHcmFwaGljc0VsZW1lbnQ6
+dHJ1ZSxTVkdJbWFnZUVsZW1lbnQ6dHJ1ZSxTVkdMaW5lRWxlbWVudDp0cnVlLFNWR0xpbmVhckdyYWRp
+ZW50RWxlbWVudDp0cnVlLFNWR01hcmtlckVsZW1lbnQ6dHJ1ZSxTVkdNYXNrRWxlbWVudDp0cnVlLFNW
+R01ldGFkYXRhRWxlbWVudDp0cnVlLFNWR1BhdGhFbGVtZW50OnRydWUsU1ZHUGF0dGVybkVsZW1lbnQ6
+dHJ1ZSxTVkdQb2x5Z29uRWxlbWVudDp0cnVlLFNWR1BvbHlsaW5lRWxlbWVudDp0cnVlLFNWR1JhZGlh
+bEdyYWRpZW50RWxlbWVudDp0cnVlLFNWR1JlY3RFbGVtZW50OnRydWUsU1ZHU2V0RWxlbWVudDp0cnVl
+LFNWR1N0b3BFbGVtZW50OnRydWUsU1ZHU3R5bGVFbGVtZW50OnRydWUsU1ZHU1ZHRWxlbWVudDp0cnVl
+LFNWR1N3aXRjaEVsZW1lbnQ6dHJ1ZSxTVkdTeW1ib2xFbGVtZW50OnRydWUsU1ZHVFNwYW5FbGVtZW50
+OnRydWUsU1ZHVGV4dENvbnRlbnRFbGVtZW50OnRydWUsU1ZHVGV4dEVsZW1lbnQ6dHJ1ZSxTVkdUZXh0
+UGF0aEVsZW1lbnQ6dHJ1ZSxTVkdUZXh0UG9zaXRpb25pbmdFbGVtZW50OnRydWUsU1ZHVGl0bGVFbGVt
+ZW50OnRydWUsU1ZHVXNlRWxlbWVudDp0cnVlLFNWR1ZpZXdFbGVtZW50OnRydWUsU1ZHR3JhZGllbnRF
+bGVtZW50OnRydWUsU1ZHQ29tcG9uZW50VHJhbnNmZXJGdW5jdGlvbkVsZW1lbnQ6dHJ1ZSxTVkdGRURy
+b3BTaGFkb3dFbGVtZW50OnRydWUsU1ZHTVBhdGhFbGVtZW50OnRydWUsU1ZHRWxlbWVudDpmYWxzZX0p
+CkguTFouJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVmZmVyVmlldyIKSC5SRy4kbmF0aXZlU3Vw
+ZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILlZQLiRuYXRpdmVTdXBlcmNsYXNzVGFnPSJBcnJh
+eUJ1ZmZlclZpZXciCkguRGcuJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVmZmVyVmlldyIKSC5X
+Qi4kbmF0aXZlU3VwZXJjbGFzc1RhZz0iQXJyYXlCdWZmZXJWaWV3IgpILlpHLiRuYXRpdmVTdXBlcmNs
+YXNzVGFnPSJBcnJheUJ1ZmZlclZpZXciCkguUGcuJG5hdGl2ZVN1cGVyY2xhc3NUYWc9IkFycmF5QnVm
+ZmVyVmlldyJ9KSgpCmNvbnZlcnRBbGxUb0Zhc3RPYmplY3QodykKY29udmVydFRvRmFzdE9iamVjdCgk
+KTsoZnVuY3Rpb24oYSl7aWYodHlwZW9mIGRvY3VtZW50PT09InVuZGVmaW5lZCIpe2EobnVsbCkKcmV0
+dXJufWlmKHR5cGVvZiBkb2N1bWVudC5jdXJyZW50U2NyaXB0IT0ndW5kZWZpbmVkJyl7YShkb2N1bWVu
+dC5jdXJyZW50U2NyaXB0KQpyZXR1cm59dmFyIHQ9ZG9jdW1lbnQuc2NyaXB0cwpmdW5jdGlvbiBvbkxv
+YWQoYil7Zm9yKHZhciByPTA7cjx0Lmxlbmd0aDsrK3IpdFtyXS5yZW1vdmVFdmVudExpc3RlbmVyKCJs
+b2FkIixvbkxvYWQsZmFsc2UpCmEoYi50YXJnZXQpfWZvcih2YXIgcz0wO3M8dC5sZW5ndGg7KytzKXRb
+c10uYWRkRXZlbnRMaXN0ZW5lcigibG9hZCIsb25Mb2FkLGZhbHNlKX0pKGZ1bmN0aW9uKGEpe3YuY3Vy
+cmVudFNjcmlwdD1hCmlmKHR5cGVvZiBkYXJ0TWFpblJ1bm5lcj09PSJmdW5jdGlvbiIpZGFydE1haW5S
+dW5uZXIoTC5JcSxbXSkKZWxzZSBMLklxKFtdKX0pfSkoKQovLyMgc291cmNlTWFwcGluZ1VSTD1taWdy
+YXRpb24uanMubWFwCg==
''';
diff --git a/pkg/nnbd_migration/lib/src/preview/dart_logo_page.dart b/pkg/nnbd_migration/lib/src/preview/dart_logo_page.dart
new file mode 100644
index 0000000..b4f8b70
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/preview/dart_logo_page.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:nnbd_migration/src/front_end/resources/resources.g.dart'
+ as resources;
+import 'package:nnbd_migration/src/preview/preview_page.dart';
+import 'package:nnbd_migration/src/preview/preview_site.dart';
+
+/// The page that contains the Dart logo.
+class DartLogoPage extends PreviewPage {
+ /// Initialize a newly created Dart logo page within the given [site].
+ DartLogoPage(PreviewSite site)
+ : super(site, PreviewSite.dartLogoPath.substring(1));
+
+ @override
+ bool get requiresAuth => false;
+
+ @override
+ void generateBody(Map<String, String> params) {
+ throw UnimplementedError();
+ }
+
+ @override
+ Future<void> generatePage(Map<String, String> params) async {
+ buf.write(resources.dart_192_png);
+ }
+}
diff --git a/pkg/nnbd_migration/lib/src/preview/preview_site.dart b/pkg/nnbd_migration/lib/src/preview/preview_site.dart
index d561cda..6e67a2d 100644
--- a/pkg/nnbd_migration/lib/src/preview/preview_site.dart
+++ b/pkg/nnbd_migration/lib/src/preview/preview_site.dart
@@ -14,6 +14,7 @@
import 'package:nnbd_migration/src/front_end/migration_state.dart';
import 'package:nnbd_migration/src/front_end/path_mapper.dart';
import 'package:nnbd_migration/src/preview/dart_file_page.dart';
+import 'package:nnbd_migration/src/preview/dart_logo_page.dart';
import 'package:nnbd_migration/src/preview/exception_page.dart';
import 'package:nnbd_migration/src/preview/highlight_css_page.dart';
import 'package:nnbd_migration/src/preview/highlight_js_page.dart';
@@ -47,6 +48,9 @@
/// The path of the JS page used to associate highlighting within a Dart file.
static const highlightJsPath = '/highlight.pack.js';
+ /// The path of the Dart logo displayed in the toolbar.
+ static const dartLogoPath = '/dart_192.png';
+
static const navigationTreePath = '/_preview/navigationTree.json';
static const applyHintPath = '/apply-hint';
@@ -133,6 +137,10 @@
// Note: `return await` needed due to
// https://github.com/dart-lang/sdk/issues/39204
return await respond(request, NavigationTreePage(this));
+ } else if (path == dartLogoPath) {
+ // Note: `return await` needed due to
+ // https://github.com/dart-lang/sdk/issues/39204
+ return await respond(request, DartLogoPage(this));
} else if (path == '/' ||
decodedPath == migrationInfo.includedRoot ||
decodedPath ==
@@ -359,6 +367,8 @@
} else if (page is HighlightJSPage) {
response.headers.contentType =
ContentType('application', 'javascript', charset: 'utf-8');
+ } else if (page is DartLogoPage) {
+ response.headers.contentType = ContentType('image', 'png');
} else {
response.headers.contentType = ContentType.html;
}
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 5973dcb..7ff4f24 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -389,6 +389,9 @@
} else if (element is VariableElement) {
decoratedType = _alreadyMigratedCodeDecorator.decorate(
element.preMigrationType, element, target);
+ } else if (element is ExtensionElement) {
+ decoratedType = _alreadyMigratedCodeDecorator.decorate(
+ element.preMigrationExtendedType, element, target);
} else {
// TODO(paulberry)
throw UnimplementedError('Decorating ${element.runtimeType}');
@@ -515,3 +518,15 @@
}
}
}
+
+extension on ExtensionElement {
+ DartType get preMigrationExtendedType {
+ var previousElementTypeProvider = ElementTypeProvider.current;
+ try {
+ ElementTypeProvider.current = const ElementTypeProvider();
+ return extendedType;
+ } finally {
+ ElementTypeProvider.current = previousElementTypeProvider;
+ }
+ }
+}
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 63a665d..a6f7f61 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -356,6 +356,29 @@
await _checkSingleFileChanges(content, expected);
}
+ Future<void> test_call_already_migrated_extension() async {
+ var content = '''
+import 'already_migrated.dart';
+void f() {
+ <int>[].g();
+}
+''';
+ var alreadyMigrated = '''
+extension Ext<T> on List<T> {
+ g() {}
+}
+''';
+ var expected = '''
+import 'already_migrated.dart';
+void f() {
+ <int>[].g();
+}
+''';
+ await _checkSingleFileChanges(content, expected, migratedInput: {
+ '/home/test/lib/already_migrated.dart': alreadyMigrated
+ });
+ }
+
Future<void> test_call_generic_function_returns_generic_class() async {
var content = '''
class B<E> implements List<E/*?*/> {
@@ -1429,6 +1452,16 @@
await _checkSingleFileChanges(content, expected, removeViaComments: true);
}
+ Future<void> test_do_not_add_question_to_null_type() async {
+ var content = '''
+Null f() => null;
+''';
+ var expected = '''
+Null f() => null;
+''';
+ await _checkSingleFileChanges(content, expected);
+ }
+
Future<void> test_do_not_propagate_non_null_intent_into_callback() async {
var content = '''
void f(int/*!*/ Function(int) callback) {
@@ -3527,7 +3560,6 @@
await _checkSingleFileChanges(content, expected);
}
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/41397')
Future<void> test_issue_41397() async {
var content = '''
void repro(){
@@ -4122,8 +4154,6 @@
await _checkSingleFileChanges(content, expected);
}
- @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/42327')
- // When fixing this issue, probably convert this to an edge builder test.
Future<void> test_migratedMethod_namedParameter() async {
var content = '''
void f(Iterable<int> a) {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 2c39e2c..7df67db 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -623,8 +623,7 @@
assertEdge(decoratedTypeAnnotation('Object o').node,
decoratedTypeAnnotation('dynamic').node,
hard: true);
- // TODO(mfairhurst): these should probably be hard edges.
- assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: false);
+ assertEdge(decoratedTypeAnnotation('dynamic').node, never, hard: true);
}
Future<void> test_as_int() async {
@@ -636,8 +635,7 @@
assertEdge(decoratedTypeAnnotation('Object o').node,
decoratedTypeAnnotation('int').node,
hard: true);
- // TODO(mfairhurst): these should probably be hard edges.
- assertEdge(decoratedTypeAnnotation('int').node, never, hard: false);
+ assertEdge(decoratedTypeAnnotation('int').node, never, hard: true);
expect(
variables.wasUnnecessaryCast(testSource, findNode.as_('o as')), false);
}
@@ -666,8 +664,7 @@
assertEdge(decoratedTypeAnnotation('int i').node,
decoratedTypeAnnotation('int)').node,
hard: true);
- // TODO(mfairhurst): these should probably be hard edges.
- assertEdge(decoratedTypeAnnotation('int)').node, never, hard: false);
+ assertEdge(decoratedTypeAnnotation('int)').node, never, hard: true);
expect(
variables.wasUnnecessaryCast(testSource, findNode.as_('i as')), true);
}
diff --git a/pkg/nnbd_migration/tool/codegen/generate_resources.dart b/pkg/nnbd_migration/tool/codegen/generate_resources.dart
index 21ed8fb..8a342a1 100644
--- a/pkg/nnbd_migration/tool/codegen/generate_resources.dart
+++ b/pkg/nnbd_migration/tool/codegen/generate_resources.dart
@@ -68,6 +68,7 @@
'.css',
'.html',
'.js',
+ '.png',
];
String base64Encode(List<int> bytes) {
@@ -170,7 +171,13 @@
for (var resource in resources) {
var name = path.basename(resource.path).replaceAll('.', '_');
- var source = resource.readAsStringSync();
+
+ String source;
+ if (path.extension(resource.path) == '.png') {
+ source = resource.readAsStringSync(encoding: latin1);
+ } else {
+ source = resource.readAsStringSync();
+ }
var delimiter = "'''";
@@ -203,6 +210,10 @@
return md5.convert(str.codeUnits).toString();
}
+String md5StringFromBytes(List<int> bytes) {
+ return md5.convert(bytes).toString();
+}
+
List<FileSystemEntity> sortDir(Iterable<FileSystemEntity> entities) {
var result = entities.toList();
result.sort((a, b) => a.path.compareTo(b.path));
@@ -229,8 +240,8 @@
continue;
}
- if (name == 'migration.js') {
- // skip the compiled js
+ if (name == 'migration.js' || name == 'dart_192.png') {
+ // skip the compiled js and logo
continue;
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 344a1c1..94033c1 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -105,7 +105,7 @@
_fe_analyzer_shared/test/*: SkipByDesign # Only meant to run on vm
analysis_server/test/integration: SkipByDesign # Analysis server integration tests don't make sense to run under dart2js, since the code under test always runs in the Dart vm as a subprocess.
analysis_server/tool/*: SkipByDesign # Only meant to run on vm
-analysis_server_client/test/live_test: SkipByDesign # Only meant to run on vm
+analysis_server_client/test/*: SkipByDesign # Only meant to run on vm
analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
analyzer_plugin/test/*: SkipByDesign # Only meant to run on vm
analyzer_plugin/tool/*: SkipByDesign # Only meant to run on vm
diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart
index 8bfdced..9e0d5a1 100644
--- a/pkg/test_runner/lib/src/test_configurations.dart
+++ b/pkg/test_runner/lib/src/test_configurations.dart
@@ -32,11 +32,12 @@
Path('runtime/observatory/tests/observatory_ui'),
Path('samples'),
Path('samples-dev'),
- Path('tests/compiler/dartdevc_native'),
Path('tests/corelib'),
Path('tests/corelib_2'),
Path('tests/dart2js'),
Path('tests/dart2js_2'),
+ Path('tests/dartdevc'),
+ Path('tests/dartdevc_2'),
Path('tests/kernel'),
Path('tests/language'),
Path('tests/language_2'),
diff --git a/pkg/vm/bin/snapshot_analysis.dart b/pkg/vm/bin/snapshot_analysis.dart
index 5d4a012..f3a037f 100755
--- a/pkg/vm/bin/snapshot_analysis.dart
+++ b/pkg/vm/bin/snapshot_analysis.dart
@@ -5,13 +5,15 @@
import 'package:args/command_runner.dart';
-import 'package:vm/snapshot/compare.dart';
-import 'package:vm/snapshot/treemap.dart';
+import 'package:vm/snapshot/commands/compare.dart';
+import 'package:vm/snapshot/commands/summary.dart';
+import 'package:vm/snapshot/commands/treemap.dart';
final runner = CommandRunner('snapshot_analysis.dart',
'Tools for binary size analysis of Dart VM AOT snapshots.')
..addCommand(TreemapCommand())
- ..addCommand(CompareCommand());
+ ..addCommand(CompareCommand())
+ ..addCommand(SummaryCommand());
void main(List<String> args) async {
try {
diff --git a/pkg/vm/lib/snapshot/ascii_table.dart b/pkg/vm/lib/snapshot/ascii_table.dart
new file mode 100644
index 0000000..a1b1df1
--- /dev/null
+++ b/pkg/vm/lib/snapshot/ascii_table.dart
@@ -0,0 +1,174 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library vm.snapshot.ascii_table;
+
+import 'dart:math' as math;
+
+/// A row in the [AsciiTable].
+abstract class Row {
+ String render(List<int> widths, List<AlignmentDirection> alignments);
+
+ /// Compute the total width of the row given [widths] of individual
+ /// columns.
+ ///
+ /// Note: there is a border on the left and right of each column
+ /// plus whitespace around it.
+ static int totalWidth(List<int> widths) =>
+ widths.fold(0, (sum, width) => sum + width + 3) + 1;
+}
+
+enum Separator {
+ /// Line separator looks like this: `+-------+------+`
+ Line,
+
+ /// Wave separator looks like this: `~~~~~~~~~~~~~~~~`.
+ Wave,
+}
+
+/// A separator row in the [AsciiTable].
+class SeparatorRow extends Row {
+ final Separator filler;
+ SeparatorRow(this.filler);
+
+ @override
+ String render(List<int> widths, List<AlignmentDirection> alignments) {
+ final sb = StringBuffer();
+ switch (filler) {
+ case Separator.Line:
+ sb.write('+');
+ for (var i = 0; i < widths.length; i++) {
+ sb.write('-' * (widths[i] + 2));
+ sb.write('+');
+ }
+ break;
+
+ case Separator.Wave:
+ sb.write('~' * Row.totalWidth(widths));
+ break;
+ }
+ return sb.toString();
+ }
+}
+
+/// A separator row in the [AsciiTable].
+class TextSeparatorRow extends Row {
+ final Text text;
+ TextSeparatorRow(String text)
+ : text = Text(value: text, direction: AlignmentDirection.Center);
+
+ @override
+ String render(List<int> widths, List<AlignmentDirection> alignments) {
+ return text.render(Row.totalWidth(widths));
+ }
+}
+
+class NormalRow extends Row {
+ final List<dynamic> columns;
+ NormalRow(this.columns);
+
+ @override
+ String render(List<int> widths, List<AlignmentDirection> alignments) {
+ final sb = StringBuffer();
+ sb.write('|');
+ for (var i = 0; i < widths.length; i++) {
+ sb.write(' ');
+ final text = columns[i] is Text
+ ? columns[i]
+ : Text(value: columns[i], direction: alignments[i]);
+ sb.write(text.render(widths[i]));
+ sb.write(' |');
+ }
+ return sb.toString();
+ }
+}
+
+enum AlignmentDirection { Left, Right, Center }
+
+/// A chunk of text aligned in the given direction within a cell.
+class Text {
+ final String value;
+ final AlignmentDirection direction;
+
+ Text({this.value, this.direction});
+ Text.left(String value)
+ : this(value: value, direction: AlignmentDirection.Left);
+ Text.right(String value)
+ : this(value: value, direction: AlignmentDirection.Right);
+ Text.center(String value)
+ : this(value: value, direction: AlignmentDirection.Center);
+
+ String render(int width) {
+ if (value.length > width) {
+ // Narrowed column.
+ return value.substring(0, width - 2) + '..';
+ }
+ switch (direction) {
+ case AlignmentDirection.Left:
+ return value.padRight(width);
+ case AlignmentDirection.Right:
+ return value.padLeft(width);
+ case AlignmentDirection.Center:
+ final diff = width - value.length;
+ return ' ' * (diff ~/ 2) + value + (' ' * (diff - diff ~/ 2));
+ }
+ return null; // Make analyzer happy.
+ }
+
+ int get length => value.length;
+}
+
+class AsciiTable {
+ static const int unlimitedWidth = 0;
+
+ final int maxWidth;
+
+ final List<Row> rows = <Row>[];
+
+ AsciiTable({List<dynamic> header, this.maxWidth: unlimitedWidth}) {
+ if (header != null) {
+ addSeparator();
+ addRow(header);
+ addSeparator();
+ }
+ }
+
+ void addRow(List<dynamic> columns) => rows.add(NormalRow(columns));
+
+ void addSeparator([Separator filler = Separator.Line]) =>
+ rows.add(SeparatorRow(filler));
+
+ void addTextSeparator(String text) => rows.add(TextSeparatorRow(text));
+
+ void render() {
+ // We assume that the first row gives us alignment directions that
+ // subsequent rows would follow.
+ List<AlignmentDirection> alignments = rows
+ .whereType<NormalRow>()
+ .first
+ .columns
+ .map((v) => v is Text ? v.direction : AlignmentDirection.Left)
+ .toList();
+ List<int> widths =
+ List<int>.filled(rows.whereType<NormalRow>().first.columns.length, 0);
+
+ // Compute max width for each column in the table.
+ for (var row in rows.whereType<NormalRow>()) {
+ assert(row.columns.length == widths.length);
+ for (var i = 0; i < widths.length; i++) {
+ widths[i] = math.max(row.columns[i].length, widths[i]);
+ }
+ }
+
+ if (maxWidth > 0) {
+ for (var i = 0; i < widths.length; i++) {
+ widths[i] = math.min(widths[i], maxWidth);
+ }
+ }
+
+ for (var row in rows) {
+ print(row.render(widths, alignments));
+ }
+ }
+}
diff --git a/pkg/vm/lib/snapshot/commands/compare.dart b/pkg/vm/lib/snapshot/commands/compare.dart
new file mode 100644
index 0000000..9e1598d
--- /dev/null
+++ b/pkg/vm/lib/snapshot/commands/compare.dart
@@ -0,0 +1,139 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This tool compares two JSON size reports produced by
+/// --print-instructions-sizes-to and reports which symbols increased in size
+/// and which symbols decreased in size.
+library vm.snapshot.compare;
+
+import 'dart:io';
+
+import 'package:args/command_runner.dart';
+import 'package:vm/snapshot/ascii_table.dart';
+
+import 'package:vm/snapshot/program_info.dart';
+import 'package:vm/snapshot/utils.dart';
+
+class CompareCommand extends Command<void> {
+ @override
+ final String name = 'compare';
+
+ @override
+ final String description = '''
+Compare two instruction size outputs and report which symbols changed in size.
+
+This tool compares two JSON size reports produced by
+--print-instructions-sizes-to and reports which symbols
+changed in size.
+
+Use --narrow flag to limit column widths.''';
+
+ @override
+ String get invocation =>
+ super.invocation.replaceAll('[arguments]', '<old.json> <new.json>');
+
+ CompareCommand() {
+ argParser
+ ..addOption('column-width',
+ help: 'Truncate column content to the given width'
+ ' (${AsciiTable.unlimitedWidth} means do not truncate).',
+ defaultsTo: AsciiTable.unlimitedWidth.toString())
+ ..addOption('granularity',
+ help: 'Choose the granularity of the output.',
+ allowed: ['method', 'class', 'library', 'package'],
+ defaultsTo: 'method')
+ ..addFlag('collapse-anonymous-closures', help: '''
+Collapse all anonymous closures from the same scope into a single entry.
+When comparing size of AOT snapshots for two different versions of a
+program there is no reliable way to precisely establish which two anonymous
+closures are the same and should be compared in size - so
+comparison might produce a noisy output. This option reduces confusion
+by collapsing different anonymous closures within the same scope into a
+single entry. Note that when comparing the same application compiled
+with two different versions of an AOT compiler closures can be distinguished
+precisely based on their source position (which is included in their name).
+''');
+ }
+
+ @override
+ Future<void> run() async {
+ if (argResults.rest.length != 2) {
+ usageException('Need to provide path to old.json and new.json reports.');
+ }
+
+ final columnWidth = argResults['column-width'];
+ final maxWidth = int.tryParse(columnWidth);
+ if (maxWidth == null) {
+ usageException(
+ 'Specified column width (${columnWidth}) is not an integer');
+ }
+
+ final oldJsonPath = _checkExists(argResults.rest[0]);
+ final newJsonPath = _checkExists(argResults.rest[1]);
+ printComparison(oldJsonPath, newJsonPath,
+ maxWidth: maxWidth,
+ granularity: _parseHistogramType(argResults['granularity']),
+ collapseAnonymousClosures: argResults['collapse-anonymous-closures']);
+ }
+
+ HistogramType _parseHistogramType(String value) {
+ switch (value) {
+ case 'method':
+ return HistogramType.bySymbol;
+ case 'class':
+ return HistogramType.byClass;
+ case 'library':
+ return HistogramType.byLibrary;
+ case 'package':
+ return HistogramType.byPackage;
+ }
+ }
+
+ File _checkExists(String path) {
+ final file = File(path);
+ if (!file.existsSync()) {
+ usageException('File $path does not exist!');
+ }
+ return file;
+ }
+}
+
+void printComparison(File oldJson, File newJson,
+ {int maxWidth: 0,
+ bool collapseAnonymousClosures = false,
+ HistogramType granularity = HistogramType.bySymbol}) async {
+ final oldSizes = await loadProgramInfo(oldJson,
+ collapseAnonymousClosures: collapseAnonymousClosures);
+ final newSizes = await loadProgramInfo(newJson,
+ collapseAnonymousClosures: collapseAnonymousClosures);
+ final diff = computeDiff(oldSizes, newSizes);
+
+ // Compute total sizes.
+ final totalOld = oldSizes.totalSize;
+ final totalNew = newSizes.totalSize;
+ final totalDiff = diff.totalSize;
+
+ // Compute histogram.
+ final histogram = SizesHistogram.from(diff, granularity);
+
+ // Now produce the report table.
+ const numLargerSymbolsToReport = 30;
+ const numSmallerSymbolsToReport = 10;
+ printHistogram(histogram,
+ sizeHeader: 'Diff (Bytes)',
+ prefix: histogram.bySize
+ .where((k) => histogram.buckets[k] > 0)
+ .take(numLargerSymbolsToReport),
+ suffix: histogram.bySize.reversed
+ .where((k) => histogram.buckets[k] < 0)
+ .take(numSmallerSymbolsToReport)
+ .toList()
+ .reversed,
+ maxWidth: maxWidth);
+
+ print('Comparing ${oldJson.path} (old) to ${newJson.path} (new)');
+ print('Old : ${totalOld} bytes.');
+ print('New : ${totalNew} bytes.');
+ print('Change: ${totalDiff > 0 ? '+' : ''}${totalDiff} bytes.');
+}
diff --git a/pkg/vm/lib/snapshot/commands/summary.dart b/pkg/vm/lib/snapshot/commands/summary.dart
new file mode 100644
index 0000000..f3860a7
--- /dev/null
+++ b/pkg/vm/lib/snapshot/commands/summary.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// This tool generates a summary report from a binary size reports produced by
+/// the AOT compiler's --print-instructions-sizes-to and
+/// --write-v8-snapshot-profile-to flags.
+library vm.snapshot.summary;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:args/command_runner.dart';
+
+import 'package:vm/snapshot/ascii_table.dart';
+import 'package:vm/snapshot/program_info.dart';
+import 'package:vm/snapshot/utils.dart';
+
+class SummaryCommand extends Command<void> {
+ @override
+ final name = 'summary';
+
+ @override
+ final description = '''
+Generate a summary report from a AOT compilers binary size dumps.
+
+This tool can process snapshot size reports produced by
+--print-instructions-sizes-to=symbol-sizes.json and
+--write-v8-snapshot-profile-to=profile.heapsnapshot flags.
+''';
+
+ SummaryCommand() {
+ argParser
+ ..addOption('column-width',
+ help: 'Truncate column content to the given width'
+ ' (${AsciiTable.unlimitedWidth} means do not truncate).',
+ defaultsTo: AsciiTable.unlimitedWidth.toString())
+ ..addOption('granularity',
+ help: 'Choose the granularity of the output.',
+ allowed: ['method', 'class', 'library', 'package'],
+ defaultsTo: 'method')
+ ..addFlag('collapse-anonymous-closures', help: '''
+Collapse all anonymous closures from the same scope into a single entry.
+When comparing size of AOT snapshots for two different versions of a
+program there is no reliable way to precisely establish which two anonymous
+closures are the same and should be compared in size - so
+comparison might produce a noisy output. This option reduces confusion
+by collapsing different anonymous closures within the same scope into a
+single entry. Note that when comparing the same application compiled
+with two different versions of an AOT compiler closures can be distinguished
+precisely based on their source position (which is included in their name).
+''');
+ }
+
+ @override
+ String get invocation =>
+ super.invocation.replaceAll('[arguments]', '<sizes.json>');
+
+ @override
+ Future<void> run() async {
+ if (argResults.rest.length != 1) {
+ usageException('Need to specify input JSON.');
+ }
+
+ final input = new File(argResults.rest[0]);
+ if (!input.existsSync()) {
+ usageException('Input file ${input.path} does not exist!');
+ }
+
+ final columnWidth = argResults['column-width'];
+ final maxWidth = int.tryParse(columnWidth);
+ if (maxWidth == null) {
+ usageException(
+ 'Specified column width (${columnWidth}) is not an integer');
+ }
+
+ await outputSummary(input,
+ maxWidth: maxWidth,
+ granularity: _parseHistogramType(argResults['granularity']),
+ collapseAnonymousClosures: argResults['collapse-anonymous-closures']);
+ }
+
+ static HistogramType _parseHistogramType(String value) {
+ switch (value) {
+ case 'method':
+ return HistogramType.bySymbol;
+ case 'class':
+ return HistogramType.byClass;
+ case 'library':
+ return HistogramType.byLibrary;
+ case 'package':
+ return HistogramType.byPackage;
+ }
+ return null;
+ }
+}
+
+void outputSummary(File input,
+ {int maxWidth = 0,
+ bool collapseAnonymousClosures = false,
+ HistogramType granularity = HistogramType.bySymbol}) async {
+ final info = await loadProgramInfo(input);
+
+ // Compute histogram.
+ final histogram = SizesHistogram.from(info, granularity);
+
+ // Now produce the report table.
+ const topToReport = 30;
+ printHistogram(histogram,
+ prefix: histogram.bySize.take(topToReport), maxWidth: maxWidth);
+}
diff --git a/pkg/vm/lib/snapshot/treemap.dart b/pkg/vm/lib/snapshot/commands/treemap.dart
similarity index 97%
rename from pkg/vm/lib/snapshot/treemap.dart
rename to pkg/vm/lib/snapshot/commands/treemap.dart
index af46dd8..1aa05d3 100644
--- a/pkg/vm/lib/snapshot/treemap.dart
+++ b/pkg/vm/lib/snapshot/commands/treemap.dart
@@ -8,7 +8,7 @@
///
/// It used the same visualization framework as Chromium's binary_size tool
/// located in runtime/third_party/binary_size.
-library vm.snapshot.treemap;
+library vm.snapshot.commands.treemap;
import 'dart:async';
import 'dart:convert';
@@ -19,6 +19,7 @@
import 'package:args/command_runner.dart';
import 'package:vm/snapshot/instruction_sizes.dart' as instruction_sizes;
+import 'package:vm/snapshot/utils.dart';
class TreemapCommand extends Command<void> {
@override
@@ -73,7 +74,7 @@
Future<void> generateTreeMap(File input, Directory outputDir) async {
// Load symbols data produced by the AOT compiler and convert it to
// a tree.
- final symbols = await instruction_sizes.load(input);
+ final symbols = instruction_sizes.fromJson(await loadJson(input));
final root = {'n': '', 'children': {}, 'k': kindPath, 'maxDepth': 0};
for (var symbol in symbols) {
diff --git a/pkg/vm/lib/snapshot/compare.dart b/pkg/vm/lib/snapshot/compare.dart
deleted file mode 100644
index cacf41b..0000000
--- a/pkg/vm/lib/snapshot/compare.dart
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// This tool compares two JSON size reports produced by
-/// --print-instructions-sizes-to and reports which symbols increased in size
-/// and which symbols decreased in size.
-library vm.snapshot.compare;
-
-import 'dart:io';
-import 'dart:math' as math;
-
-import 'package:args/command_runner.dart';
-
-import 'package:vm/snapshot/instruction_sizes.dart';
-import 'package:vm/snapshot/program_info.dart';
-
-class CompareCommand extends Command<void> {
- @override
- final String name = 'compare';
-
- @override
- final String description = '''
-Compare two instruction size outputs and report which symbols changed in size.
-
-This tool compares two JSON size reports produced by
---print-instructions-sizes-to and reports which symbols
-changed in size.
-
-Use --narrow flag to limit column widths.''';
-
- @override
- String get invocation =>
- super.invocation.replaceAll('[arguments]', '<old.json> <new.json>');
-
- CompareCommand() {
- argParser
- ..addOption('column-width',
- help: 'Truncate column content to the given width'
- ' (${AsciiTable.unlimitedWidth} means do not truncate).',
- defaultsTo: AsciiTable.unlimitedWidth.toString())
- ..addOption('granularity',
- help: 'Choose the granularity of the output.',
- allowed: ['method', 'class', 'library', 'package'],
- defaultsTo: 'method')
- ..addFlag('collapse-anonymous-closures', help: '''
-Collapse all anonymous closures from the same scope into a single entry.
-When comparing size of AOT snapshots for two different versions of a
-program there is no reliable way to precisely establish which two anonymous
-closures are the same and should be compared in size - so
-comparison might produce a noisy output. This option reduces confusion
-by collapsing different anonymous closures within the same scope into a
-single entry. Note that when comparing the same application compiled
-with two different versions of an AOT compiler closures can be distinguished
-precisely based on their source position (which is included in their name).
-''');
- }
-
- @override
- Future<void> run() async {
- if (argResults.rest.length != 2) {
- usageException('Need to provide path to old.json and new.json reports.');
- }
-
- final columnWidth = argResults['column-width'];
- final maxWidth = int.tryParse(columnWidth);
- if (maxWidth == null) {
- usageException(
- 'Specified column width (${columnWidth}) is not an integer');
- }
-
- final oldJsonPath = _checkExists(argResults.rest[0]);
- final newJsonPath = _checkExists(argResults.rest[1]);
- printComparison(oldJsonPath, newJsonPath,
- maxWidth: maxWidth,
- granularity: _parseHistogramType(argResults['granularity']),
- collapseAnonymousClosures: argResults['collapse-anonymous-closures']);
- }
-
- HistogramType _parseHistogramType(String value) {
- switch (value) {
- case 'method':
- return HistogramType.bySymbol;
- case 'class':
- return HistogramType.byClass;
- case 'library':
- return HistogramType.byLibrary;
- case 'package':
- return HistogramType.byPackage;
- }
- }
-
- File _checkExists(String path) {
- final file = File(path);
- if (!file.existsSync()) {
- usageException('File $path does not exist!');
- }
- return file;
- }
-}
-
-void printComparison(File oldJson, File newJson,
- {int maxWidth: 0,
- bool collapseAnonymousClosures = false,
- HistogramType granularity = HistogramType.bySymbol}) async {
- final oldSizes = await loadProgramInfo(oldJson,
- collapseAnonymousClosures: collapseAnonymousClosures);
- final newSizes = await loadProgramInfo(newJson,
- collapseAnonymousClosures: collapseAnonymousClosures);
- final diff = computeDiff(oldSizes, newSizes);
-
- // Compute total sizes.
- var totalOld = 0;
- oldSizes.visit((_, __, ___, size) {
- totalOld += size;
- });
-
- var totalNew = 0;
- newSizes.visit((_, __, ___, size) {
- totalNew += size;
- });
-
- var totalDiff = 0;
- diff.visit((_, __, ___, size) {
- totalDiff += size.inBytes;
- });
-
- // Compute histogram.
- final histogram = SizesHistogram.from<SymbolDiff>(
- diff, (diff) => diff.inBytes, granularity);
-
- // Now produce the report table.
- const numLargerSymbolsToReport = 30;
- const numSmallerSymbolsToReport = 10;
- final table = AsciiTable(header: [
- for (var col in histogram.bucketing.nameComponents) Text.left(col),
- Text.right('Diff (Bytes)')
- ], maxWidth: maxWidth);
-
- // Report [numLargerSymbolsToReport] symbols that increased in size most.
- for (var key in histogram.bySize
- .where((k) => histogram.buckets[k] > 0)
- .take(numLargerSymbolsToReport)) {
- table.addRow([
- ...histogram.bucketing.namesFromBucket(key),
- '+${histogram.buckets[key]}'
- ]);
- }
- table.addSeparator(Separator.Wave);
-
- // Report [numSmallerSymbolsToReport] symbols that decreased in size most.
- for (var key in histogram.bySize.reversed
- .where((k) => histogram.buckets[k] < 0)
- .take(numSmallerSymbolsToReport)
- .toList()
- .reversed) {
- table.addRow([
- ...histogram.bucketing.namesFromBucket(key),
- '${histogram.buckets[key]}'
- ]);
- }
- table.addSeparator();
-
- table.render();
- print('Comparing ${oldJson.path} (old) to ${newJson.path} (new)');
- print('Old : ${totalOld} bytes.');
- print('New : ${totalNew} bytes.');
- print('Change: ${totalDiff > 0 ? '+' : ''}${totalDiff} bytes.');
-}
-
-/// A row in the [AsciiTable].
-abstract class Row {
- String render(List<int> widths, List<AlignmentDirection> alignments);
-}
-
-enum Separator {
- /// Line separator looks like this: `+-------+------+`
- Line,
-
- /// Wave separator looks like this: `~~~~~~~~~~~~~~~~` repeated twice.
- Wave
-}
-
-/// A separator row in the [AsciiTable].
-class SeparatorRow extends Row {
- final Separator filler;
- SeparatorRow(this.filler);
-
- @override
- String render(List<int> widths, List<AlignmentDirection> alignments) {
- switch (filler) {
- case Separator.Line:
- final sb = StringBuffer();
- sb.write('+');
- for (var i = 0; i < widths.length; i++) {
- sb.write('-' * (widths[i] + 2));
- sb.write('+');
- }
- return sb.toString();
-
- case Separator.Wave:
- final sb = StringBuffer();
- sb.write('~');
- for (var i = 0; i < widths.length; i++) {
- sb.write('~' * (widths[i] + 2));
- sb.write('~');
- }
- return sb.toString() + '\n' + sb.toString();
- }
- return null; // Make analyzer happy.
- }
-}
-
-class NormalRow extends Row {
- final List<dynamic> columns;
- NormalRow(this.columns);
-
- @override
- String render(List<int> widths, List<AlignmentDirection> alignments) {
- final sb = StringBuffer();
- sb.write('|');
- for (var i = 0; i < widths.length; i++) {
- sb.write(' ');
- final text = columns[i] is Text
- ? columns[i]
- : Text(value: columns[i], direction: alignments[i]);
- sb.write(text.render(widths[i]));
- sb.write(' |');
- }
- return sb.toString();
- }
-}
-
-enum AlignmentDirection { Left, Right, Center }
-
-/// A chunk of text aligned in the given direction within a cell.
-class Text {
- final String value;
- final AlignmentDirection direction;
-
- Text({this.value, this.direction});
- Text.left(String value)
- : this(value: value, direction: AlignmentDirection.Left);
- Text.right(String value)
- : this(value: value, direction: AlignmentDirection.Right);
- Text.center(String value)
- : this(value: value, direction: AlignmentDirection.Center);
-
- String render(int width) {
- if (value.length > width) {
- // Narrowed column.
- return value.substring(0, width - 2) + '..';
- }
- switch (direction) {
- case AlignmentDirection.Left:
- return value.padRight(width);
- case AlignmentDirection.Right:
- return value.padLeft(width);
- case AlignmentDirection.Center:
- final diff = width - value.length;
- return ' ' * (diff ~/ 2) + value + (' ' * (diff - diff ~/ 2));
- }
- return null; // Make analyzer happy.
- }
-
- int get length => value.length;
-}
-
-class AsciiTable {
- static const int unlimitedWidth = 0;
-
- final int maxWidth;
-
- final List<Row> rows = <Row>[];
-
- AsciiTable({List<dynamic> header, this.maxWidth: unlimitedWidth}) {
- if (header != null) {
- addSeparator();
- addRow(header);
- addSeparator();
- }
- }
-
- void addRow(List<dynamic> columns) => rows.add(NormalRow(columns));
-
- void addSeparator([Separator filler = Separator.Line]) =>
- rows.add(SeparatorRow(filler));
-
- void render() {
- // We assume that the first row gives us alignment directions that
- // subsequent rows would follow.
- List<AlignmentDirection> alignments = rows
- .whereType<NormalRow>()
- .first
- .columns
- .map((v) => v is Text ? v.direction : AlignmentDirection.Left)
- .toList();
- List<int> widths =
- List<int>.filled(rows.whereType<NormalRow>().first.columns.length, 0);
-
- // Compute max width for each column in the table.
- for (var row in rows.whereType<NormalRow>()) {
- assert(row.columns.length == widths.length);
- for (var i = 0; i < widths.length; i++) {
- widths[i] = math.max(row.columns[i].length, widths[i]);
- }
- }
-
- if (maxWidth > 0) {
- for (var i = 0; i < widths.length; i++) {
- widths[i] = math.min(widths[i], maxWidth);
- }
- }
-
- for (var row in rows) {
- print(row.render(widths, alignments));
- }
- }
-}
diff --git a/pkg/vm/lib/snapshot/instruction_sizes.dart b/pkg/vm/lib/snapshot/instruction_sizes.dart
index 7efa3a1..c05bad8 100644
--- a/pkg/vm/lib/snapshot/instruction_sizes.dart
+++ b/pkg/vm/lib/snapshot/instruction_sizes.dart
@@ -5,28 +5,20 @@
/// Helper functions for parsing output of `--print-instructions-sizes-to` flag.
library vm.snapshot.instruction_sizes;
-import 'dart:convert';
-import 'dart:io';
-
import 'package:vm/snapshot/name.dart';
import 'package:vm/snapshot/program_info.dart';
/// Parse the output of `--print-instructions-sizes-to` saved in the given
/// file [input].
-Future<List<SymbolInfo>> load(File input) async {
- final List<dynamic> symbolsArray = await input
- .openRead()
- .transform(utf8.decoder)
- .transform(json.decoder)
- .first;
- return symbolsArray
+List<SymbolInfo> fromJson(List<dynamic> json) {
+ return json
.cast<Map<String, dynamic>>()
.map(SymbolInfo._fromJson)
.toList(growable: false);
}
/// Parse the output of `--print-instructions-sizes-to` saved in the given
-/// file [input] into [ProgramInfo<int>] structure representing the sizes
+/// file [input] into [ProgramInfo] structure representing the sizes
/// of individual functions.
///
/// If [collapseAnonymousClosures] is set to [true] then all anonymous closures
@@ -34,9 +26,9 @@
/// helpful when comparing symbol sizes between two versions of the same
/// program because in general there is no reliable way to recognize the same
/// anonymous closures into two independent compilations.
-Future<ProgramInfo<int>> loadProgramInfo(File input,
- {bool collapseAnonymousClosures = false}) async {
- final symbols = await load(input);
+ProgramInfo loadProgramInfo(List<dynamic> json,
+ {bool collapseAnonymousClosures = false}) {
+ final symbols = fromJson(json);
return toProgramInfo(symbols,
collapseAnonymousClosures: collapseAnonymousClosures);
}
@@ -69,7 +61,7 @@
}
}
-/// Restore hierarchical [ProgramInfo<int>] representation from the list of
+/// Restore hierarchical [ProgramInfo] representation from the list of
/// symbols by parsing function names.
///
/// If [collapseAnonymousClosures] is set to [true] then all anonymous closures
@@ -77,32 +69,41 @@
/// helpful when comparing symbol sizes between two versions of the same
/// program because in general there is no reliable way to recognize the same
/// anonymous closures into two independent compilations.
-ProgramInfo<int> toProgramInfo(List<SymbolInfo> symbols,
+ProgramInfo toProgramInfo(List<SymbolInfo> symbols,
{bool collapseAnonymousClosures = false}) {
- final program = ProgramInfo<int>();
+ final program = ProgramInfo();
for (var sym in symbols) {
final scrubbed = sym.name.scrubbed;
if (sym.libraryUri == null) {
assert(sym.name.isStub);
- assert(
- !program.stubs.containsKey(scrubbed) || sym.name.isTypeTestingStub);
- program.stubs[scrubbed] = (program.stubs[scrubbed] ?? 0) + sym.size;
+ final node = program.makeNode(
+ name: scrubbed, parent: program.stubs, type: NodeType.functionNode);
+ assert(node.size == null || sym.name.isTypeTestingStub);
+ node.size = (node.size ?? 0) + sym.size;
} else {
// Split the name into components (names of individual functions).
final path = sym.name.components;
- final lib =
- program.libraries.putIfAbsent(sym.libraryUri, () => LibraryInfo());
- final cls = lib.classes.putIfAbsent(sym.className, () => ClassInfo());
- var fun = cls.functions.putIfAbsent(path.first, () => FunctionInfo());
- for (var name in path.skip(1)) {
- if (collapseAnonymousClosures &&
- name.startsWith('<anonymous closure @')) {
- name = '<anonymous closure>';
- }
- fun = fun.closures.putIfAbsent(name, () => FunctionInfo());
+ var node = program.root;
+ final package = packageOf(sym.libraryUri);
+ if (package != sym.libraryUri) {
+ node = program.makeNode(
+ name: package, parent: node, type: NodeType.packageNode);
}
- fun.info = (fun.info ?? 0) + sym.size;
+ node = program.makeNode(
+ name: sym.libraryUri, parent: node, type: NodeType.libraryNode);
+ node = program.makeNode(
+ name: sym.className, parent: node, type: NodeType.classNode);
+ node = program.makeNode(
+ name: path.first, parent: node, type: NodeType.functionNode);
+ for (var name in path.skip(1)) {
+ if (collapseAnonymousClosures) {
+ name = Name.collapse(name);
+ }
+ node = program.makeNode(
+ name: name, parent: node, type: NodeType.functionNode);
+ }
+ node.size = (node.size ?? 0) + sym.size;
}
}
diff --git a/pkg/vm/lib/snapshot/name.dart b/pkg/vm/lib/snapshot/name.dart
index dba2c9f..e636b34 100644
--- a/pkg/vm/lib/snapshot/name.dart
+++ b/pkg/vm/lib/snapshot/name.dart
@@ -54,6 +54,9 @@
return result;
}
+
+ static String collapse(String name) =>
+ name.replaceAll(_collapseRe, '<anonymous closure>');
}
// Remove useless prefixes and private library suffixes from the raw name.
@@ -66,3 +69,6 @@
// Remove useless prefixes and private library suffixes from the raw name
// for stubs.
final _stubScrubbingRe = RegExp(r'\[Stub\]\s*|@\d+|\(H[a-f\d]+\) ');
+
+// Remove token positions from anonymous closure names.
+final _collapseRe = RegExp(r'<anonymous closure @\d+>');
diff --git a/pkg/vm/lib/snapshot/program_info.dart b/pkg/vm/lib/snapshot/program_info.dart
index 3094ee2..09f233c 100644
--- a/pkg/vm/lib/snapshot/program_info.dart
+++ b/pkg/vm/lib/snapshot/program_info.dart
@@ -5,154 +5,177 @@
/// Classes for representing information about the program structure.
library vm.snapshot.program_info;
+import 'package:meta/meta.dart';
+
/// Represents information about compiled program.
-class ProgramInfo<T> {
- final Map<String, LibraryInfo<T>> libraries = {};
- final Map<String, T> stubs = {};
+class ProgramInfo {
+ static const int rootId = 0;
+ static const int stubsId = 1;
+ static const int unknownId = 2;
+
+ final ProgramInfoNode root;
+ final ProgramInfoNode stubs;
+ final ProgramInfoNode unknown;
+ int _nextId = 3;
+
+ ProgramInfo._(this.root, this.stubs, this.unknown);
+
+ factory ProgramInfo() {
+ final ProgramInfoNode root = ProgramInfoNode._(
+ id: rootId, name: '@shared', type: NodeType.libraryNode, parent: null);
+
+ final ProgramInfoNode stubs = ProgramInfoNode._(
+ id: stubsId, name: '@stubs', type: NodeType.libraryNode, parent: root);
+ root.children[stubs.name] = stubs;
+
+ final ProgramInfoNode unknown = ProgramInfoNode._(
+ id: unknownId,
+ name: '@unknown',
+ type: NodeType.libraryNode,
+ parent: root);
+ root.children[unknown.name] = unknown;
+
+ return ProgramInfo._(root, stubs, unknown);
+ }
+
+ ProgramInfoNode makeNode(
+ {@required String name,
+ @required ProgramInfoNode parent,
+ @required NodeType type}) {
+ return parent.children.putIfAbsent(name, () {
+ final node = ProgramInfoNode._(
+ id: _nextId++, name: name, parent: parent ?? root, type: type);
+ node.parent.children[name] = node;
+ return node;
+ });
+ }
/// Recursively visit all function nodes, which have [FunctionInfo.info]
/// populated.
void visit(
- void Function(String lib, String cls, String fun, T info) callback) {
- void recurse(String lib, String cls, String name, FunctionInfo<T> fun) {
- if (fun.info != null) {
- callback(lib, cls, name, fun.info);
+ void Function(String pkg, String lib, String cls, String fun, int size)
+ callback) {
+ final context = List<String>(NodeType.values.length);
+
+ void recurse(ProgramInfoNode node) {
+ final prevContext = context[node._type];
+ if (prevContext != null && node._type == NodeType.functionNode.index) {
+ context[node._type] = '${prevContext}.${node.name}';
+ } else {
+ context[node._type] = node.name;
}
- for (var clo in fun.closures.entries) {
- recurse(lib, cls, '$name.${clo.key}', clo.value);
+ if (node.size != null) {
+ final String pkg = context[NodeType.packageNode.index];
+ final String lib = context[NodeType.libraryNode.index];
+ final String cls = context[NodeType.classNode.index];
+ final String mem = context[NodeType.functionNode.index];
+ callback(pkg, lib, cls, mem, node.size);
}
+
+ for (var child in node.children.values) {
+ recurse(child);
+ }
+
+ context[node._type] = prevContext;
}
- for (var stub in stubs.entries) {
- callback(null, null, stub.key, stub.value);
- }
+ recurse(root);
+ }
- for (var lib in libraries.entries) {
- for (var cls in lib.value.classes.entries) {
- for (var fun in cls.value.functions.entries) {
- recurse(lib.key, cls.key, fun.key, fun.value);
- }
- }
- }
+ int get totalSize {
+ var result = 0;
+ visit((pkg, lib, cls, fun, size) {
+ result += size;
+ });
+ return result;
}
/// Convert this program info to a JSON map using [infoToJson] to convert
- /// data attached to [FunctioInfo] nodes into its JSON representation.
- Map<String, dynamic> toJson(Object Function(T) infoToJson) {
- Map<String, dynamic> recurse(FunctionInfo<T> fun) {
- return {
- if (fun.info != null) 'info': infoToJson(fun.info),
- if (fun.closures.isNotEmpty)
- 'closures': {
- for (var clo in fun.closures.entries) clo.key: recurse(clo.value)
- }
+ /// data attached to nodes into its JSON representation.
+ Map<String, dynamic> toJson() => root.toJson();
+}
+
+enum NodeType {
+ packageNode,
+ libraryNode,
+ classNode,
+ functionNode,
+ other,
+}
+
+String _typeToJson(NodeType type) => const {
+ NodeType.packageNode: 'package',
+ NodeType.libraryNode: 'library',
+ NodeType.classNode: 'class',
+ NodeType.functionNode: 'function',
+ }[type];
+
+class ProgramInfoNode {
+ final int id;
+ final String name;
+ final ProgramInfoNode parent;
+ final Map<String, ProgramInfoNode> children = {};
+ final int _type;
+
+ int size;
+
+ ProgramInfoNode._(
+ {@required this.id,
+ @required this.name,
+ @required this.parent,
+ @required NodeType type})
+ : _type = type.index;
+
+ NodeType get type => NodeType.values[_type];
+
+ Map<String, dynamic> toJson() => {
+ if (size != null) '#size': size,
+ if (_type != NodeType.other.index) '#type': _typeToJson(type),
+ if (children.isNotEmpty)
+ for (var clo in children.entries) clo.key: clo.value.toJson()
};
- }
+}
- return {
- 'stubs': {
- for (var stub in stubs.entries) stub.key: infoToJson(stub.value)
- },
- 'libraries': {
- for (var lib in libraries.entries)
- lib.key: {
- for (var cls in lib.value.classes.entries)
- cls.key: {
- for (var fun in cls.value.functions.entries)
- fun.key: recurse(fun.value)
- }
- }
+/// Computes the size difference between two [ProgramInfo].
+ProgramInfo computeDiff(ProgramInfo oldInfo, ProgramInfo newInfo) {
+ final programDiff = ProgramInfo();
+
+ var path = <Object>[];
+ void recurse(ProgramInfoNode oldNode, ProgramInfoNode newNode) {
+ if (oldNode?.size != newNode?.size) {
+ var diffNode = programDiff.root;
+ for (var i = 0; i < path.length; i += 2) {
+ final name = path[i];
+ final type = path[i + 1];
+ diffNode =
+ programDiff.makeNode(name: name, parent: diffNode, type: type);
}
- };
- }
-}
-
-class LibraryInfo<T> {
- final Map<String, ClassInfo<T>> classes = {};
-}
-
-class ClassInfo<T> {
- final Map<String, FunctionInfo<T>> functions = {};
-}
-
-class FunctionInfo<T> {
- final Map<String, FunctionInfo<T>> closures = {};
-
- T info;
-}
-
-/// Computes the size difference between two [ProgramInfo<int>].
-ProgramInfo<SymbolDiff> computeDiff(
- ProgramInfo<int> oldInfo, ProgramInfo<int> newInfo) {
- final programDiff = ProgramInfo<SymbolDiff>();
-
- void recursiveDiff(FunctionInfo<SymbolDiff> Function() functionInfo,
- String fun, FunctionInfo<int> newFun, FunctionInfo<int> oldFun) {
- if (newFun?.info != oldFun?.info) {
- final funDiff = functionInfo();
- final diff = funDiff.info ??= SymbolDiff();
- diff.oldTotal += oldFun?.info ?? 0;
- diff.newTotal += newFun?.info ?? 0;
+ diffNode.size ??= 0;
+ diffNode.size += (newNode?.size ?? 0) - (oldNode?.size ?? 0);
}
- for (var clo in _allKeys(newFun?.closures, oldFun?.closures)) {
- final newClo = newFun != null ? newFun.closures[clo] : null;
- final oldClo = oldFun != null ? oldFun.closures[clo] : null;
- recursiveDiff(() {
- return functionInfo().closures.putIfAbsent(clo, () => FunctionInfo());
- }, clo, newClo, oldClo);
+ for (var key in _allKeys(newNode?.children, oldNode?.children)) {
+ final newChildNode = newNode != null ? newNode.children[key] : null;
+ final oldChildNode = oldNode != null ? oldNode.children[key] : null;
+ path.add(key);
+ path.add(oldChildNode?.type ?? newChildNode?.type);
+ recurse(oldChildNode, newChildNode);
+ path.removeLast();
+ path.removeLast();
}
}
- for (var stub in _allKeys(newInfo.stubs, oldInfo.stubs)) {
- final newSize = newInfo.stubs[stub];
- final oldSize = oldInfo.stubs[stub];
- if (newSize != oldSize) {
- programDiff.stubs[stub] = SymbolDiff()
- ..oldTotal = oldSize ?? 0
- ..newTotal = newSize ?? 0;
- }
- }
-
- for (var lib in _allKeys(newInfo.libraries, oldInfo.libraries)) {
- final newLib = newInfo.libraries[lib];
- final oldLib = oldInfo.libraries[lib];
- for (var cls in _allKeys(newLib?.classes, oldLib?.classes)) {
- final newCls = newLib != null ? newLib.classes[cls] : null;
- final oldCls = oldLib != null ? oldLib.classes[cls] : null;
- for (var fun in _allKeys(newCls?.functions, oldCls?.functions)) {
- final newFun = newCls != null ? newCls.functions[fun] : null;
- final oldFun = oldCls != null ? oldCls.functions[fun] : null;
- recursiveDiff(() {
- return programDiff.libraries
- .putIfAbsent(lib, () => LibraryInfo())
- .classes
- .putIfAbsent(cls, () => ClassInfo())
- .functions
- .putIfAbsent(fun, () => FunctionInfo());
- }, fun, newFun, oldFun);
- }
- }
- }
+ recurse(oldInfo.root, newInfo.root);
return programDiff;
}
-class SymbolDiff {
- int oldTotal = 0;
- int newTotal = 0;
-
- int get inBytes {
- return newTotal - oldTotal;
- }
-}
-
Iterable<T> _allKeys<T>(Map<T, dynamic> a, Map<T, dynamic> b) {
return <T>{...?a?.keys, ...?b?.keys};
}
-/// Histogram of sizes based on a [ProgramInfo] bucketted using one of the
+/// Histogram of sizes based on a [ProgramInfo] bucketed using one of the
/// [HistogramType] rules.
class SizesHistogram {
/// Rule used to produce this histogram. Specifies how bucket names
@@ -167,25 +190,28 @@
/// order.
final List<String> bySize;
- SizesHistogram._(this.bucketing, this.buckets, this.bySize);
+ final int totalSize;
- /// Construct the histogram of specific [type] given a [ProgramInfo<T>] and
- /// function [toSize] for computing an integer value based on the datum of
- /// type [T] attached to program nodes.
- static SizesHistogram from<T>(
- ProgramInfo<T> info, int Function(T) toSize, HistogramType type) {
+ int get length => bySize.length;
+
+ SizesHistogram._(this.bucketing, this.buckets, this.bySize, this.totalSize);
+
+ /// Construct the histogram of specific [type] given a [ProgramInfo].
+ static SizesHistogram from(ProgramInfo info, HistogramType type) {
final buckets = <String, int>{};
final bucketing = Bucketing._forType[type];
- info.visit((lib, cls, fun, info) {
- final bucket = bucketing.bucketFor(lib ?? '<stubs>', cls ?? '', fun);
- buckets[bucket] = (buckets[bucket] ?? 0) + toSize(info);
+ var totalSize = 0;
+ info.visit((pkg, lib, cls, fun, size) {
+ final bucket = bucketing.bucketFor(pkg, lib, cls, fun);
+ buckets[bucket] = (buckets[bucket] ?? 0) + size;
+ totalSize += size;
});
final bySize = buckets.keys.toList(growable: false);
bySize.sort((a, b) => buckets[b] - buckets[a]);
- return SizesHistogram._(bucketing, buckets, bySize);
+ return SizesHistogram._(bucketing, buckets, bySize, totalSize);
}
}
@@ -203,7 +229,7 @@
/// Constructs the bucket name from the given library name [lib], class name
/// [cls] and function name [fun].
- String bucketFor(String lib, String cls, String fun);
+ String bucketFor(String pkg, String lib, String cls, String fun);
/// Deconstructs bucket name into human readable components (the order matches
/// one returned by [nameComponents]).
@@ -224,11 +250,15 @@
class _BucketBySymbol extends Bucketing {
@override
- List<String> get nameComponents => const ['Library', 'Method'];
+ List<String> get nameComponents => const ['Library', 'Symbol'];
@override
- String bucketFor(String lib, String cls, String fun) =>
- '$lib${_nameSeparator}${cls}${cls != '' ? '.' : ''}${fun}';
+ String bucketFor(String pkg, String lib, String cls, String fun) {
+ if (fun == null) {
+ return '@other${_nameSeparator}';
+ }
+ return '$lib${_nameSeparator}${cls}${cls != '' ? '.' : ''}${fun}';
+ }
@override
List<String> namesFromBucket(String bucket) => bucket.split(_nameSeparator);
@@ -241,8 +271,12 @@
List<String> get nameComponents => ['Library', 'Class'];
@override
- String bucketFor(String lib, String cls, String fun) =>
- '$lib${_nameSeparator}${cls}';
+ String bucketFor(String pkg, String lib, String cls, String fun) {
+ if (cls == null) {
+ return '@other${_nameSeparator}';
+ }
+ return '$lib${_nameSeparator}${cls}';
+ }
@override
List<String> namesFromBucket(String bucket) => bucket.split(_nameSeparator);
@@ -255,7 +289,7 @@
List<String> get nameComponents => ['Library'];
@override
- String bucketFor(String lib, String cls, String fun) => '$lib';
+ String bucketFor(String pkg, String lib, String cls, String fun) => '$lib';
@override
List<String> namesFromBucket(String bucket) => [bucket];
@@ -268,19 +302,20 @@
List<String> get nameComponents => ['Package'];
@override
- String bucketFor(String lib, String cls, String fun) => _packageOf(lib);
+ String bucketFor(String pkg, String lib, String cls, String fun) =>
+ pkg ?? lib;
@override
List<String> namesFromBucket(String bucket) => [bucket];
const _BucketByPackage();
+}
- String _packageOf(String lib) {
- if (lib.startsWith('package:')) {
- final separatorPos = lib.indexOf('/');
- return lib.substring(0, separatorPos);
- } else {
- return lib;
- }
+String packageOf(String lib) {
+ if (lib.startsWith('package:')) {
+ final separatorPos = lib.indexOf('/');
+ return lib.substring(0, separatorPos);
+ } else {
+ return lib;
}
}
diff --git a/pkg/vm/lib/snapshot/utils.dart b/pkg/vm/lib/snapshot/utils.dart
new file mode 100644
index 0000000..e57a188
--- /dev/null
+++ b/pkg/vm/lib/snapshot/utils.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+library vm.snapshot.utils;
+
+import 'dart:io';
+import 'dart:convert';
+
+import 'package:vm/snapshot/ascii_table.dart';
+import 'package:vm/snapshot/program_info.dart';
+import 'package:vm/snapshot/instruction_sizes.dart' as instruction_sizes;
+
+Future<Object> loadJson(File input) async {
+ return await input
+ .openRead()
+ .transform(utf8.decoder)
+ .transform(json.decoder)
+ .first;
+}
+
+Future<ProgramInfo> loadProgramInfo(File input,
+ {bool collapseAnonymousClosures = false}) async {
+ final json = await loadJson(input);
+ return instruction_sizes.loadProgramInfo(json,
+ collapseAnonymousClosures: collapseAnonymousClosures);
+}
+
+void printHistogram(SizesHistogram histogram,
+ {Iterable<String> prefix = const [],
+ Iterable<String> suffix = const [],
+ String sizeHeader = 'Size (Bytes)',
+ int maxWidth = 0}) {
+ final table = AsciiTable(header: [
+ for (var col in histogram.bucketing.nameComponents) Text.left(col),
+ Text.right(sizeHeader),
+ Text.right('Percent'),
+ ], maxWidth: maxWidth);
+
+ String formatPercent(int value, int total) {
+ final p = value / total * 100.0;
+ return p.toStringAsFixed(2) + "%";
+ }
+
+ if (prefix.isNotEmpty) {
+ for (var key in prefix) {
+ table.addRow([
+ ...histogram.bucketing.namesFromBucket(key),
+ histogram.buckets[key].toString(),
+ formatPercent(histogram.buckets[key], histogram.totalSize),
+ ]);
+ }
+ table.addSeparator(
+ prefix.length < histogram.length ? Separator.Wave : Separator.Line);
+ }
+
+ final numRestRows = histogram.length - (suffix.length + prefix.length);
+ if (numRestRows > 0) {
+ final totalRestBytes = histogram.totalSize -
+ [prefix, suffix]
+ .expand((l) => l)
+ .fold(0, (sum, key) => sum + histogram.buckets[key]);
+ table.addTextSeparator(
+ '$numRestRows more rows accounting for ${totalRestBytes}'
+ ' (${formatPercent(totalRestBytes, histogram.totalSize)}) bytes');
+ final avg = (totalRestBytes / numRestRows).round();
+ table.addTextSeparator(
+ 'on average that is ${avg} (${formatPercent(avg, histogram.totalSize)})'
+ ' bytes per row');
+ table.addSeparator(suffix.isNotEmpty ? Separator.Wave : Separator.Line);
+ }
+
+ if (suffix.isNotEmpty) {
+ for (var key in suffix) {
+ table.addRow([
+ ...histogram.bucketing.namesFromBucket(key),
+ histogram.buckets[key].toString(),
+ formatPercent(histogram.buckets[key], histogram.totalSize),
+ ]);
+ }
+ table.addSeparator(Separator.Line);
+ }
+
+ table.render();
+ print('Total: ${histogram.totalSize} bytes');
+}
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index e8ad442..cc02953 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -216,6 +216,8 @@
final Map<NativeType, Procedure> storeMethods;
final Map<NativeType, Procedure> elementAtMethods;
final Procedure loadStructMethod;
+ final Procedure asFunctionTearoff;
+ final Procedure lookupFunctionTearoff;
/// Classes corresponding to [NativeType], indexed by [NativeType].
final List<Class> nativeTypesClasses;
@@ -274,7 +276,13 @@
final name = nativeTypeClassNames[t.index];
return index.getTopLevelMember('dart:ffi', "_elementAt$name");
}),
- loadStructMethod = index.getTopLevelMember('dart:ffi', '_loadStruct');
+ loadStructMethod = index.getTopLevelMember('dart:ffi', '_loadStruct'),
+ asFunctionTearoff = index.getMember('dart:ffi', 'NativeFunctionPointer',
+ LibraryIndex.tearoffPrefix + 'asFunction'),
+ lookupFunctionTearoff = index.getMember(
+ 'dart:ffi',
+ 'DynamicLibraryExtension',
+ LibraryIndex.tearoffPrefix + 'lookupFunction');
/// Computes the Dart type corresponding to a ffi.[NativeType], returns null
/// if it is not a valid NativeType.
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index 96830bf..f23c669 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -122,8 +122,15 @@
@override
visitProcedure(Procedure node) {
+ if (isFfiLibrary && node.isExtensionMember) {
+ if (node == asFunctionTearoff || node == lookupFunctionTearoff) {
+ // Skip static checks and transformation for the tearoffs.
+ return node;
+ }
+ }
+
_staticTypeContext = new StaticTypeContext(node, env);
- var result = super.visitProcedure(node);
+ final result = super.visitProcedure(node);
_staticTypeContext = null;
return result;
}
@@ -159,15 +166,16 @@
final Member target = node.target;
try {
- if (target == lookupFunctionMethod && !isFfiLibrary) {
+ if (target == lookupFunctionMethod) {
final DartType nativeType = InterfaceType(
nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
final DartType dartType = node.arguments.types[1];
_ensureNativeTypeValid(nativeType, node);
_ensureNativeTypeToDartType(nativeType, dartType, node);
+
return _replaceLookupFunction(node);
- } else if (target == asFunctionMethod && !isFfiLibrary) {
+ } else if (target == asFunctionMethod) {
final DartType dartType = node.arguments.types[1];
final DartType nativeType = InterfaceType(
nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
diff --git a/pkg/vm/lib/v8_snapshot_profile.dart b/pkg/vm/lib/v8_snapshot_profile.dart
index 2b1ad73..847836d 100644
--- a/pkg/vm/lib/v8_snapshot_profile.dart
+++ b/pkg/vm/lib/v8_snapshot_profile.dart
@@ -107,7 +107,7 @@
final Set<int> roots = <int>{};
for (final edge in _toEdges[root]) {
final int to = edge.nodeOffset;
- Expect.isTrue(!roots.contains(to));
+ Expect.isTrue(!roots.contains(to), "multiple root edges to node ${to}");
roots.add(to);
}
@@ -129,11 +129,15 @@
void _parseMetadata(Map meta) {
final List nodeFields = meta["node_fields"];
nodeFields.forEach(_nodeFields.add);
- Expect.isTrue(_kRequiredNodeFields.every(_nodeFields.contains));
+ for (final field in _kRequiredNodeFields) {
+ Expect.isTrue(nodeFields.contains(field), "missing node field ${field}");
+ }
final List edgeFields = meta["edge_fields"];
edgeFields.forEach(_edgeFields.add);
- Expect.isTrue(_kRequiredEdgeFields.every(_edgeFields.contains));
+ for (final field in _kRequiredEdgeFields) {
+ Expect.isTrue(edgeFields.contains(field), "missing edge field ${field}");
+ }
// First entry of "node_types" is an array with the actual node types. IDK
// what the other entries are for.
@@ -157,21 +161,23 @@
int offset = 0;
for (; offset < nodes.length; offset += _nodeFields.length) {
final int type = nodes[offset + typeIndex];
- Expect.isTrue(0 <= type && type < _nodeTypes.length);
+ Expect.isTrue(0 <= type && type < _nodeTypes.length,
+ "node type ${type} outside range [0, ${_nodeTypes.length})");
final int name = nodes[offset + nameIndex];
- Expect.isTrue(0 <= name && name < _strings.length);
+ Expect.isTrue(0 <= name && name < _strings.length,
+ "node name ${name} outside range [0, ${_strings.length})");
final int id = nodes[offset + idIndex];
- Expect.isTrue(id >= 0);
- Expect.isFalse(_ids.contains(id));
+ Expect.isTrue(id >= 0, "negative node ID ${id}");
+ Expect.isFalse(_ids.contains(id), "node ID ${id} already added");
_ids.add(id);
final int selfSize = nodes[offset + selfSizeIndex];
- Expect.isTrue(selfSize >= 0);
+ Expect.isTrue(selfSize >= 0, "negative node selfSize ${selfSize}");
final int edgeCount = nodes[offset + edgeCountIndex];
- Expect.isTrue(edgeCount >= 0);
+ Expect.isTrue(edgeCount >= 0, "negative node edgeCount ${edgeCount}");
_nodes[offset] = _NodeInfo(type, name, id, selfSize, edgeCount);
}
@@ -193,14 +199,16 @@
final List<_EdgeInfo> nodeEdges = List<_EdgeInfo>(edgeCount);
for (int i = 0; i < edgeCount; ++i, edgeOffset += _edgeFields.length) {
final int type = edges[edgeOffset + typeIndex];
- Expect.isTrue(0 <= type && type < _edgeTypes.length);
+ Expect.isTrue(0 <= type && type < _edgeTypes.length,
+ "edge type ${type} outside range [0, ${_edgeTypes.length}");
final int nameOrIndex = edges[edgeOffset + nameOrIndexIndex];
if (_edgeTypes[type] == "property") {
- Expect.isTrue(0 <= nameOrIndex && nameOrIndex < _strings.length);
+ Expect.isTrue(0 <= nameOrIndex && nameOrIndex < _strings.length,
+ "edge name ${nameOrIndex} outside range [0, ${_strings.length}");
} else if (_edgeTypes[type] == "element" ||
_edgeTypes[type] == "context") {
- Expect.isTrue(nameOrIndex >= 0);
+ Expect.isTrue(nameOrIndex >= 0, "negative edge index ${nameOrIndex}");
}
final int toNode = edges[edgeOffset + toNodeIndex];
@@ -215,9 +223,13 @@
}
void checkNode(int offset) {
- Expect.isTrue(offset >= 0 &&
- offset % _nodeFields.length == 0 &&
- offset ~/ _nodeFields.length < _nodes.length);
+ Expect.isTrue(offset >= 0, "negative offset ${offset}");
+ Expect.isTrue(offset % _nodeFields.length == 0,
+ "offset ${offset} not a multiple of ${_nodeFields.length}");
+ Expect.isTrue(
+ offset ~/ _nodeFields.length < _nodes.length,
+ "offset ${offset} divided by ${_nodeFields.length} is greater than or "
+ "equal to node count ${_nodes.length}");
}
void _calculateFromEdges() {
@@ -243,7 +255,8 @@
int get unknownCount {
final int unknownType = _nodeTypes.indexOf("Unknown");
- Expect.isTrue(unknownType >= 0);
+ Expect.isTrue(
+ unknownType >= 0, 'negative type index for "Unknown": ${unknownType}');
int count = 0;
for (final MapEntry<int, _NodeInfo> entry in _nodes.entries) {
diff --git a/pkg/vm/test/snapshot/instruction_sizes_test.dart b/pkg/vm/test/snapshot/instruction_sizes_test.dart
index 60bd343..a6ce2eb 100644
--- a/pkg/vm/test/snapshot/instruction_sizes_test.dart
+++ b/pkg/vm/test/snapshot/instruction_sizes_test.dart
@@ -9,6 +9,7 @@
import 'package:vm/snapshot/instruction_sizes.dart' as instruction_sizes;
import 'package:vm/snapshot/program_info.dart';
+import 'package:vm/snapshot/utils.dart';
final dart2native = () {
final sdkBin = path.dirname(Platform.executable);
@@ -171,7 +172,8 @@
test('basic-parsing', () async {
await withSymbolSizes('basic-parsing', testSource, (sizesJson) async {
- final symbols = await instruction_sizes.load(File(sizesJson));
+ final symbols =
+ instruction_sizes.fromJson(await loadJson(File(sizesJson)));
expect(symbols, isNotNull,
reason: 'Sizes file was successfully parsed');
expect(symbols.length, greaterThan(0),
@@ -243,21 +245,23 @@
test('program-info', () async {
await withSymbolSizes('program-info', testSource, (sizesJson) async {
- final info = await instruction_sizes.loadProgramInfo(File(sizesJson));
- expect(info.libraries, contains('dart:core'));
- expect(info.libraries, contains('dart:typed_data'));
- expect(info.libraries, contains('package:input/input.dart'));
+ final info = await loadProgramInfo(File(sizesJson));
+ expect(info.root.children, contains('dart:core'));
+ expect(info.root.children, contains('dart:typed_data'));
+ expect(info.root.children, contains('package:input'));
- final inputLib = info.libraries['package:input/input.dart'];
- expect(inputLib.classes, contains('')); // Top-level class.
- expect(inputLib.classes, contains('A'));
- expect(inputLib.classes, contains('B'));
- expect(inputLib.classes, contains('C'));
+ final inputLib = info.root.children['package:input']
+ .children['package:input/input.dart'];
+ expect(inputLib, isNotNull);
+ expect(inputLib.children, contains('')); // Top-level class.
+ expect(inputLib.children, contains('A'));
+ expect(inputLib.children, contains('B'));
+ expect(inputLib.children, contains('C'));
- final topLevel = inputLib.classes[''];
- expect(topLevel.functions, contains('makeSomeClosures'));
+ final topLevel = inputLib.children[''];
+ expect(topLevel.children, contains('makeSomeClosures'));
expect(
- topLevel.functions['makeSomeClosures'].closures.length, equals(3));
+ topLevel.children['makeSomeClosures'].children.length, equals(3));
for (var name in [
'[tear-off] tornOff',
@@ -265,8 +269,8 @@
'Allocate A',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.classes['A'].functions, contains(name));
- expect(inputLib.classes['A'].functions[name].closures, isEmpty);
+ expect(inputLib.children['A'].children, contains(name));
+ expect(inputLib.children['A'].children[name].children, isEmpty);
}
for (var name in [
@@ -275,62 +279,62 @@
'Allocate B',
'[tear-off-extractor] get:tornOff'
]) {
- expect(inputLib.classes['B'].functions, contains(name));
- expect(inputLib.classes['B'].functions[name].closures, isEmpty);
+ expect(inputLib.children['B'].children, contains(name));
+ expect(inputLib.children['B'].children[name].children, isEmpty);
}
for (var name in ['tornOff{body}', 'tornOff', '[tear-off] tornOff']) {
- expect(inputLib.classes['C'].functions, contains(name));
- expect(inputLib.classes['C'].functions[name].closures, isEmpty);
+ expect(inputLib.children['C'].children, contains(name));
+ expect(inputLib.children['C'].children[name].children, isEmpty);
}
});
});
test('histograms', () async {
await withSymbolSizes('histograms', testSource, (sizesJson) async {
- final info = await instruction_sizes.loadProgramInfo(File(sizesJson));
- final bySymbol =
- SizesHistogram.from(info, (size) => size, HistogramType.bySymbol);
+ final info = await loadProgramInfo(File(sizesJson));
+ final bySymbol = SizesHistogram.from(info, HistogramType.bySymbol);
expect(
bySymbol.buckets,
- contains(bySymbol.bucketing
- .bucketFor('package:input/input.dart', 'A', 'tornOff')));
+ contains(bySymbol.bucketing.bucketFor(
+ 'package:input', 'package:input/input.dart', 'A', 'tornOff')));
expect(
bySymbol.buckets,
- contains(bySymbol.bucketing
- .bucketFor('package:input/input.dart', 'B', 'tornOff')));
+ contains(bySymbol.bucketing.bucketFor(
+ 'package:input', 'package:input/input.dart', 'B', 'tornOff')));
expect(
bySymbol.buckets,
- contains(bySymbol.bucketing
- .bucketFor('package:input/input.dart', 'C', 'tornOff')));
+ contains(bySymbol.bucketing.bucketFor(
+ 'package:input', 'package:input/input.dart', 'C', 'tornOff')));
- final byClass =
- SizesHistogram.from(info, (size) => size, HistogramType.byClass);
+ final byClass = SizesHistogram.from(info, HistogramType.byClass);
expect(
byClass.buckets,
- contains(byClass.bucketing.bucketFor(
+ contains(byClass.bucketing.bucketFor('package:input',
'package:input/input.dart', 'A', 'does-not-matter')));
expect(
byClass.buckets,
- contains(byClass.bucketing.bucketFor(
+ contains(byClass.bucketing.bucketFor('package:input',
'package:input/input.dart', 'B', 'does-not-matter')));
expect(
byClass.buckets,
- contains(byClass.bucketing.bucketFor(
+ contains(byClass.bucketing.bucketFor('package:input',
'package:input/input.dart', 'C', 'does-not-matter')));
- final byLibrary =
- SizesHistogram.from(info, (size) => size, HistogramType.byLibrary);
+ final byLibrary = SizesHistogram.from(info, HistogramType.byLibrary);
expect(
byLibrary.buckets,
- contains(byLibrary.bucketing.bucketFor('package:input/input.dart',
- 'does-not-matter', 'does-not-matter')));
+ contains(byLibrary.bucketing.bucketFor(
+ 'package:input',
+ 'package:input/input.dart',
+ 'does-not-matter',
+ 'does-not-matter')));
- final byPackage =
- SizesHistogram.from(info, (size) => size, HistogramType.byPackage);
+ final byPackage = SizesHistogram.from(info, HistogramType.byPackage);
expect(
byPackage.buckets,
contains(byPackage.bucketing.bucketFor(
+ 'package:input',
'package:input/does-not-matter.dart',
'does-not-matter',
'does-not-matter')));
@@ -340,10 +344,9 @@
// On Windows there is some issue with interpreting entry point URI as a package URI
// it instead gets interpreted as a file URI - which breaks comparison. So we
// simply ignore entry point library (main.dart).
- Map<String, dynamic> diffToJson(ProgramInfo<SymbolDiff> diff) {
- final diffJson = diff.toJson((diff) => diff.inBytes);
- final libraries = diffJson['libraries'] as Map<String, dynamic>;
- libraries.removeWhere((key, _) => key.endsWith('main.dart'));
+ Map<String, dynamic> diffToJson(ProgramInfo diff) {
+ final diffJson = diff.toJson();
+ diffJson.removeWhere((key, _) => key.startsWith('file:'));
return diffJson;
}
@@ -351,33 +354,40 @@
await withSymbolSizes('diff-1', testSource, (sizesJson) async {
await withSymbolSizes('diff-2', testSourceModified,
(modifiedSizesJson) async {
- final info = await instruction_sizes.loadProgramInfo(File(sizesJson));
- final modifiedInfo =
- await instruction_sizes.loadProgramInfo(File(modifiedSizesJson));
+ final info = await loadProgramInfo(File(sizesJson));
+ final modifiedInfo = await loadProgramInfo(File(modifiedSizesJson));
final diff = computeDiff(info, modifiedInfo);
expect(
diffToJson(diff),
equals({
- 'stubs': {},
- 'libraries': {
+ '#type': 'library',
+ '@stubs': {'#type': 'library'},
+ '@unknown': {'#type': 'library'},
+ 'package:input': {
+ '#type': 'package',
'package:input/input.dart': {
+ '#type': 'library',
'': {
+ '#type': 'class',
'makeSomeClosures': {
- 'info': greaterThan(0), // We added code here.
- 'closures': {
- '<anonymous closure @118>': {
- 'info': greaterThan(0),
- },
+ '#type': 'function',
+ '#size': greaterThan(0), // We added code here.
+ '<anonymous closure @118>': {
+ '#type': 'function',
+ '#size': greaterThan(0),
},
},
'main': {
- 'info': lessThan(0), // We removed code from main.
+ '#type': 'function',
+ '#size': lessThan(0), // We removed code from main.
},
},
'A': {
+ '#type': 'class',
'tornOff': {
- 'info': greaterThan(0),
+ '#type': 'function',
+ '#size': greaterThan(0),
},
}
}
@@ -391,29 +401,33 @@
await withSymbolSizes('diff-collapsed-1', testSource, (sizesJson) async {
await withSymbolSizes('diff-collapsed-2', testSourceModified2,
(modifiedSizesJson) async {
- final info = await instruction_sizes.loadProgramInfo(File(sizesJson),
+ final info = await loadProgramInfo(File(sizesJson),
collapseAnonymousClosures: true);
- final modifiedInfo = await instruction_sizes.loadProgramInfo(
- File(modifiedSizesJson),
+ final modifiedInfo = await loadProgramInfo(File(modifiedSizesJson),
collapseAnonymousClosures: true);
final diff = computeDiff(info, modifiedInfo);
expect(
diffToJson(diff),
equals({
- 'stubs': {},
- 'libraries': {
+ '#type': 'library',
+ '@stubs': {'#type': 'library'},
+ '@unknown': {'#type': 'library'},
+ 'package:input': {
+ '#type': 'package',
'package:input/input.dart': {
+ '#type': 'library',
'': {
+ '#type': 'class',
'makeSomeClosures': {
- 'info': lessThan(0), // We removed code here.
- 'closures': {
- '<anonymous closure>': {
- 'info': lessThan(0),
- },
- },
- },
- },
+ '#size': lessThan(0),
+ '#type': 'function',
+ '<anonymous closure>': {
+ '#size': lessThan(0),
+ '#type': 'function'
+ }
+ }
+ }
}
}
}));
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 34e1238..6bf8c39 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -40,8 +40,16 @@
# If a DEBUG build has been specified it will be ignored.
config("dart_product_config") {
defines = []
+ cflags = []
if (!dart_debug) {
defines += [ "PRODUCT" ]
+ if (is_posix) {
+ cflags = [
+ # This is the equivalent from `build/config/BUILDCONFIG.gn` which includes
+ # `build/config/gcc:symbol_visibility_hidden` in product mode.
+ "-fvisibility=hidden",
+ ]
+ }
}
}
@@ -128,7 +136,10 @@
}
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ lib_dirs = [ "../out/DebugFuchsiaX64/lib" ]
+ }
+ if (using_fuchsia_gn_sdk || using_fuchsia_sdk) {
# TODO(chinmaygarde): Currenty these targets need to be build in the
# Fuchsia tree as well as outside it using the SDK. However, not all
# Fuchsia features are available in the SDK. As these features are added,
@@ -199,8 +210,11 @@
public_configs = [ ":dart_public_config" ]
sources = [
"include/dart_api.h",
+ "include/dart_api_dl.h",
"include/dart_native_api.h",
"include/dart_tools_api.h",
+ "include/dart_version.h",
+ "include/internal/dart_api_dl_impl.h",
]
}
@@ -215,7 +229,12 @@
defines = [ "DART_ENABLE_WASM" ]
}
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ extra_deps += [
+ "$fuchsia_sdk_root/pkg/fdio",
+ "$fuchsia_sdk_root/pkg/trace-engine",
+ ]
+ } else if (using_fuchsia_sdk) {
extra_deps += [
"$fuchsia_sdk_root/pkg:fdio",
"$fuchsia_sdk_root/pkg:trace-engine",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 50a155d..0fd5acd 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -42,7 +42,9 @@
public_configs = [ ":libdart_builtin_config" ]
deps = []
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ public_deps = [ "$fuchsia_sdk_root/pkg/fdio" ]
+ } else if (using_fuchsia_sdk) {
public_deps = [ "$fuchsia_sdk_root/pkg:fdio" ]
} else {
public_deps = [ "//zircon/public/lib/fdio" ]
@@ -69,6 +71,7 @@
extra_configs = [
"..:dart_product_config",
"..:dart_os_config",
+ "..:dart_arch_config",
]
}
@@ -313,7 +316,13 @@
deps = []
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ deps += [
+ "$fuchsia_sdk_root/fidl/fuchsia.netstack",
+ "$fuchsia_sdk_root/pkg/sys_cpp",
+ ]
+ public_deps = [ "$fuchsia_sdk_root/pkg/fdio" ]
+ } else if (using_fuchsia_sdk) {
deps += [
"$fuchsia_sdk_root/fidl:fuchsia.netstack",
"$fuchsia_sdk_root/pkg:sys_cpp",
@@ -449,7 +458,13 @@
deps += [ "//third_party/boringssl" ]
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ deps += [
+ "$fuchsia_sdk_root/fidl/fuchsia.netstack",
+ "$fuchsia_sdk_root/pkg/sys_cpp",
+ ]
+ public_deps = [ "$fuchsia_sdk_root/pkg/fdio" ]
+ } else if (using_fuchsia_sdk) {
deps += [
"$fuchsia_sdk_root/fidl:fuchsia.netstack",
"$fuchsia_sdk_root/pkg:sys_cpp",
@@ -512,6 +527,12 @@
extra_deps = [ ":libdart_builtin" ]
}
+dart_io("standalone_dart_io_product") {
+ extra_configs = [ "..:dart_product_config" ]
+ extra_sources = []
+ extra_deps = [ ":libdart_builtin_product" ]
+}
+
gen_snapshot_action("generate_snapshot_bin") {
deps = [ "../vm:vm_platform_stripped" ]
vm_snapshot_data = "$target_gen_dir/vm_snapshot_data.bin"
@@ -727,6 +748,11 @@
}
template("dart_executable") {
+ use_product_mode = dart_runtime_mode == "release"
+ if (defined(invoker.use_product_mode)) {
+ use_product_mode = invoker.use_product_mode
+ }
+
extra_configs = []
if (defined(invoker.extra_configs)) {
extra_configs += invoker.extra_configs
@@ -756,26 +782,37 @@
"..:dart_arch_config",
"..:dart_config",
"..:dart_os_config",
- "..:dart_maybe_product_config",
] + extra_configs
+ if (use_product_mode) {
+ configs += [ "..:dart_product_config" ]
+ } else {
+ configs += [ "..:dart_maybe_product_config" ]
+ }
if (target_os != current_os && target_os == "fuchsia") {
# We already have these in the standalone build, but Fuchsia doesn't
# have them. They are needed for running Fuchsia binaries built for the
# host.
if (is_linux) {
- configs += [ "../../build/config/gcc:executable_ldconfig" ]
+ # TODO(liama): Commenting this line out because it causes problems for
+ # --os=fuchsia. If no one complains, remove it.
+ # configs += [ "../../build/config/gcc:executable_ldconfig" ]
} else if (is_mac) {
configs += [ "../../build/config/mac:mac_dynamic_flags" ]
}
}
deps = [
- ":standalone_dart_io",
- "//third_party/boringssl",
- "//third_party/zlib",
- ":crashpad",
- ":generate_abi_version_cc_file",
- ] + extra_deps
+ ":crashpad",
+ ":generate_abi_version_cc_file",
+ "//third_party/boringssl",
+ "//third_party/zlib",
+ ]
+ if (use_product_mode) {
+ deps += [ ":standalone_dart_io_product" ]
+ } else {
+ deps += [ ":standalone_dart_io" ]
+ }
+ deps += extra_deps
defines = extra_defines
if (exclude_kernel_service) {
@@ -876,13 +913,38 @@
"snapshot_empty.cc",
]
- extra_deps += [ ":elf_loader" ]
+ if (dart_runtime_mode == "release") {
+ extra_deps += [ ":elf_loader_product" ]
+ } else {
+ extra_deps += [ ":elf_loader" ]
+ }
if (dart_runtime_mode == "release") {
extra_sources += [ "observatory_assets_empty.cc" ]
}
}
+dart_executable("dart_precompiled_runtime_product") {
+ use_product_mode = true
+ extra_configs = [ "..:dart_precompiled_runtime_config" ]
+ extra_deps = [
+ "..:libdart_precompiled_runtime_product",
+ "../platform:libdart_platform_precompiled_runtime_product",
+ ]
+ extra_sources = [
+ "builtin.cc",
+ "gzip.cc",
+ "gzip.h",
+ "loader.cc",
+ "loader.h",
+ "main.cc",
+ "observatory_assets_empty.cc",
+ "snapshot_empty.cc",
+ ]
+
+ extra_deps += [ ":elf_loader_product" ]
+}
+
executable("process_test") {
sources = [ "process_test.cc" ]
}
@@ -961,7 +1023,11 @@
}
if (is_fuchsia) {
- if (!using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ include_dirs += [ "$fuchsia_sdk_path/pkg/trace-engine/include" ]
+ libs = [ "zircon" ]
+ }
+ if (!using_fuchsia_gn_sdk && !using_fuchsia_sdk) {
deps += [ "//zircon/system/ulib/trace" ]
}
}
@@ -1073,11 +1139,14 @@
shared_library("ffi_test_functions") {
deps = [ ":dart" ]
- # The two files here do not depend on each other.
- # flutter/flutter integration tests will only use `ffi_test_functions.cc` -
- # any test functionality using `dart_api.h` has to go into
- # `ffi_test_functions_vmspecific.cc`.
sources = [
+ # This file must be compiled in for dynamic linking.
+ "../include/dart_api_dl.cc",
+
+ # The two files here do not depend on each other.
+ # flutter/flutter integration tests will only use `ffi_test_functions.cc` -
+ # any test functionality using `dart_api.h` has to go into
+ # `ffi_test_functions_vmspecific.cc`.
"ffi_test/ffi_test_functions.cc",
"ffi_test/ffi_test_functions_vmspecific.cc",
]
diff --git a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
index a80882b..05b8952 100644
--- a/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions_vmspecific.cc
@@ -35,6 +35,8 @@
#include "include/dart_api.h"
#include "include/dart_native_api.h"
+#include "include/dart_api_dl.h"
+
namespace dart {
#define CHECK(X) \
@@ -270,31 +272,9 @@
#endif // defined(TARGET_OS_LINUX)
////////////////////////////////////////////////////////////////////////////////
-// Dynamic linking of dart_native_api.h for the next two samples.
-typedef bool (*Dart_PostCObjectType)(Dart_Port port_id, Dart_CObject* message);
-Dart_PostCObjectType Dart_PostCObject_ = nullptr;
-
-DART_EXPORT void RegisterDart_PostCObject(
- Dart_PostCObjectType function_pointer) {
- Dart_PostCObject_ = function_pointer;
-}
-
-typedef Dart_Port (*Dart_NewNativePortType)(const char* name,
- Dart_NativeMessageHandler handler,
- bool handle_concurrently);
-Dart_NewNativePortType Dart_NewNativePort_ = nullptr;
-
-DART_EXPORT void RegisterDart_NewNativePort(
- Dart_NewNativePortType function_pointer) {
- Dart_NewNativePort_ = function_pointer;
-}
-
-typedef bool (*Dart_CloseNativePortType)(Dart_Port native_port_id);
-Dart_CloseNativePortType Dart_CloseNativePort_ = nullptr;
-
-DART_EXPORT void RegisterDart_CloseNativePort(
- Dart_CloseNativePortType function_pointer) {
- Dart_CloseNativePort_ = function_pointer;
+// Initialize `dart_api_dl.h`
+DART_EXPORT intptr_t InitDartApiDL(void* data) {
+ return Dart_InitializeApiDL(data);
}
////////////////////////////////////////////////////////////////////////////////
@@ -342,7 +322,7 @@
dart_object.type = Dart_CObject_kInt64;
dart_object.value.as_int64 = work_addr;
- const bool result = Dart_PostCObject_(send_port, &dart_object);
+ const bool result = Dart_PostCObject_DL(send_port, &dart_object);
if (!result) {
FATAL("C : Posting message to port failed.");
}
@@ -504,16 +484,16 @@
PendingCall(void** buffer, size_t* length)
: response_buffer_(buffer), response_length_(length) {
receive_port_ =
- Dart_NewNativePort_("cpp-response", &PendingCall::HandleResponse,
- /*handle_concurrently=*/false);
+ Dart_NewNativePort_DL("cpp-response", &PendingCall::HandleResponse,
+ /*handle_concurrently=*/false);
}
- ~PendingCall() { Dart_CloseNativePort_(receive_port_); }
+ ~PendingCall() { Dart_CloseNativePort_DL(receive_port_); }
Dart_Port port() const { return receive_port_; }
void PostAndWait(Dart_Port port, Dart_CObject* object) {
std::unique_lock<std::mutex> lock(mutex);
- const bool success = Dart_PostCObject_(send_port_, object);
+ const bool success = Dart_PostCObject_DL(send_port_, object);
if (!success) FATAL("Failed to send message, invalid port or isolate died");
printf("C : Waiting for result.\n");
@@ -668,7 +648,7 @@
printf("C : Dart_PostCObject_(request: %" Px ", call: %" Px ").\n",
reinterpret_cast<intptr_t>(&c_request),
reinterpret_cast<intptr_t>(&c_pending_call));
- Dart_PostCObject_(send_port_, &c_request);
+ Dart_PostCObject_DL(send_port_, &c_request);
}
// Simulated work for Thread #1.
@@ -793,7 +773,8 @@
////////////////////////////////////////////////////////////////////////////////
// Functions for handle tests.
//
-// vmspecific_handle_test.dart
+// vmspecific_handle_test.dart (statically linked).
+// vmspecific_handle_dynamically_linked_test.dart (dynamically linked).
static void RunFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
@@ -912,4 +893,46 @@
return Dart_True();
}
+DART_EXPORT Dart_Handle PassObjectToCUseDynamicLinking(Dart_Handle h) {
+ auto persistent_handle = Dart_NewPersistentHandle_DL(h);
+
+ Dart_Handle handle_2 = Dart_HandleFromPersistent_DL(persistent_handle);
+ Dart_SetPersistentHandle_DL(persistent_handle, h);
+ Dart_DeletePersistentHandle_DL(persistent_handle);
+
+ auto weak_handle = Dart_NewWeakPersistentHandle_DL(
+ handle_2, reinterpret_cast<void*>(0x1234), 64, RunFinalizer);
+ Dart_Handle return_value = Dart_HandleFromWeakPersistent_DL(weak_handle);
+
+ Dart_DeleteWeakPersistentHandle_DL(weak_handle);
+
+ return return_value;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Example for doing closure callbacks with help of `dart_api.h`.
+//
+// sample_ffi_functions_callbacks_closures.dart
+
+void (*callback_)(Dart_Handle);
+Dart_PersistentHandle closure_to_callback_;
+
+DART_EXPORT void RegisterClosureCallbackFP(void (*callback)(Dart_Handle)) {
+ callback_ = callback;
+}
+
+DART_EXPORT void RegisterClosureCallback(Dart_Handle h) {
+ closure_to_callback_ = Dart_NewPersistentHandle_DL(h);
+}
+
+DART_EXPORT void InvokeClosureCallback() {
+ Dart_Handle closure_handle =
+ Dart_HandleFromPersistent_DL(closure_to_callback_);
+ callback_(closure_handle);
+}
+
+DART_EXPORT void ReleaseClosureCallback() {
+ Dart_DeletePersistentHandle_DL(closure_to_callback_);
+}
+
} // namespace dart
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index d900b10..9e68346 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -15,6 +15,7 @@
#include "bin/namespace.h"
#include "bin/reference_counting.h"
#include "platform/syslog.h"
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -211,6 +212,9 @@
// the file. If conversion fails, uri is treated as a path.
static File* OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode);
+ // Attempts to convert the given [uri] to a file path.
+ static Utils::CStringUniquePtr UriToPath(const char* uri);
+
// Create a file object for the specified stdio file descriptor
// (stdin, stout or stderr).
static File* OpenStdio(int fd);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 2a3ffd4..8dcac15 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -241,7 +241,7 @@
return new File(new FileHandle(fd));
}
-static Utils::CStringUniquePtr DecodeUri(const char* uri) {
+Utils::CStringUniquePtr File::UriToPath(const char* uri) {
const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
? uri + 7 : uri;
UriDecoder uri_decoder(path);
@@ -253,7 +253,7 @@
}
File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return nullptr;
}
@@ -276,7 +276,7 @@
}
bool File::ExistsUri(Namespace* namespc, const char* uri) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return false;
}
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
index 89426c0..d1918b0 100644
--- a/runtime/bin/file_fuchsia.cc
+++ b/runtime/bin/file_fuchsia.cc
@@ -243,7 +243,7 @@
return OpenFD(fd);
}
-static Utils::CStringUniquePtr DecodeUri(const char* uri) {
+Utils::CStringUniquePtr File::UriToPath(const char* uri) {
const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
? uri + 7 : uri;
UriDecoder uri_decoder(path);
@@ -255,7 +255,7 @@
}
File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return nullptr;
}
@@ -277,7 +277,7 @@
}
bool File::ExistsUri(Namespace* namespc, const char* uri) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return false;
}
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 92ee4fa..2f6ca67 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -244,7 +244,7 @@
return OpenFD(fd);
}
-static Utils::CStringUniquePtr DecodeUri(const char* uri) {
+Utils::CStringUniquePtr File::UriToPath(const char* uri) {
const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
? uri + 7 : uri;
UriDecoder uri_decoder(path);
@@ -256,7 +256,7 @@
}
File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return nullptr;
}
@@ -279,7 +279,7 @@
}
bool File::ExistsUri(Namespace* namespc, const char* uri) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return false;
}
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index e87cced..b036ac8 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -287,7 +287,7 @@
return new File(new FileHandle(fd));
}
-static Utils::CStringUniquePtr DecodeUri(const char* uri) {
+Utils::CStringUniquePtr File::UriToPath(const char* uri) {
const char* path = (strlen(uri) >= 8 && strncmp(uri, "file:///", 8) == 0)
? uri + 7 : uri;
UriDecoder uri_decoder(path);
@@ -299,7 +299,7 @@
}
File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return nullptr;
}
@@ -321,7 +321,7 @@
}
bool File::ExistsUri(Namespace* namespc, const char* uri) {
- auto path = DecodeUri(uri);
+ auto path = UriToPath(uri);
if (path == nullptr) {
return false;
}
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index ff32a17..5ce4ae7 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -302,22 +302,35 @@
return file;
}
-File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+Utils::CStringUniquePtr File::UriToPath(const char* uri) {
UriDecoder uri_decoder(uri);
- if (uri_decoder.decoded() == NULL) {
+ if (uri_decoder.decoded() == nullptr) {
SetLastError(ERROR_INVALID_NAME);
- return NULL;
+ return Utils::CreateCStringUniquePtr(nullptr);
}
Utf8ToWideScope uri_w(uri_decoder.decoded());
if (!UrlIsFileUrlW(uri_w.wide())) {
- return FileOpenW(uri_w.wide(), mode);
+ return Utils::CreateCStringUniquePtr(strdup(uri_decoder.decoded()));
}
wchar_t filename_w[MAX_PATH];
DWORD filename_len = MAX_PATH;
- HRESULT result = PathCreateFromUrlW(uri_w.wide(),
- filename_w, &filename_len, /* dwFlags= */ NULL);
- return (result == S_OK) ? FileOpenW(filename_w, mode) : NULL;
+ HRESULT result = PathCreateFromUrlW(uri_w.wide(), filename_w, &filename_len,
+ /* dwFlags= */ 0);
+ if (result != S_OK) {
+ return Utils::CreateCStringUniquePtr(nullptr);
+ }
+
+ WideToUtf8Scope utf8_path(filename_w);
+ return utf8_path.release();
+}
+
+File* File::OpenUri(Namespace* namespc, const char* uri, FileOpenMode mode) {
+ auto path = UriToPath(uri);
+ if (path == nullptr) {
+ return nullptr;
+ }
+ return Open(namespc, path.get(), mode);
}
File* File::OpenStdio(int fd) {
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
index 8805d09..495eceb 100644
--- a/runtime/bin/process_fuchsia.cc
+++ b/runtime/bin/process_fuchsia.cc
@@ -744,7 +744,9 @@
}
actions[3] = {
.action = FDIO_SPAWN_ACTION_SET_NAME,
- .name.data = program_arguments_[0],
+ .name = {
+ .data = program_arguments_[0],
+ },
};
// Then fill in the namespace actions.
@@ -752,8 +754,10 @@
for (size_t i = 0; i < flat_ns->count; i++) {
actions[fixed_actions_cnt + i] = {
.action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY,
- .ns.prefix = flat_ns->path[i],
- .ns.handle = flat_ns->handle[i],
+ .ns = {
+ .prefix = flat_ns->path[i],
+ .handle = flat_ns->handle[i],
+ },
};
}
free(flat_ns);
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index 36f6293..7e8369a 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -201,7 +201,9 @@
*isolate_data_buffer = nullptr,
*isolate_instructions_buffer = nullptr;
Dart_LoadedElf* handle = nullptr;
+#if !defined(HOST_OS_FUCHSIA)
if (force_load_elf_from_memory) {
+#endif
File* const file =
File::Open(/*namespc=*/nullptr, script_name, File::kRead);
if (file == nullptr) return nullptr;
@@ -216,11 +218,13 @@
&isolate_data_buffer, &isolate_instructions_buffer);
delete memory;
file->Release();
+#if !defined(HOST_OS_FUCHSIA)
} else {
handle = Dart_LoadELF(script_name, file_offset, &error, &vm_data_buffer,
&vm_instructions_buffer, &isolate_data_buffer,
&isolate_instructions_buffer);
}
+#endif
if (handle == nullptr) {
Syslog::PrintErr("Loading failed: %s\n", error);
return nullptr;
@@ -329,8 +333,14 @@
#endif // defined(DART_PRECOMPILED_RUNTIME)
-AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_name,
+AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_uri,
bool force_load_elf_from_memory) {
+ auto decoded_path = File::UriToPath(script_uri);
+ if (decoded_path == nullptr) {
+ return nullptr;
+ }
+
+ const char* script_name = decoded_path.get();
if (File::GetType(nullptr, script_name, true) != File::kIsFile) {
// If 'script_name' refers to a pipe, don't read to check for an app
// snapshot since we cannot rewind if it isn't (and couldn't mmap it in
diff --git a/runtime/bin/snapshot_utils.h b/runtime/bin/snapshot_utils.h
index e84014c..1b8c666 100644
--- a/runtime/bin/snapshot_utils.h
+++ b/runtime/bin/snapshot_utils.h
@@ -36,7 +36,7 @@
static AppSnapshot* TryReadAppendedAppSnapshotElf(const char* container_path);
static AppSnapshot* TryReadAppSnapshot(
- const char* script_name,
+ const char* script_uri,
bool force_load_elf_from_memory = false);
static void WriteAppSnapshot(const char* filename,
uint8_t* vm_data_buffer,
diff --git a/runtime/bin/utils_win.h b/runtime/bin/utils_win.h
index fb01845..fdb4909 100644
--- a/runtime/bin/utils_win.h
+++ b/runtime/bin/utils_win.h
@@ -5,7 +5,9 @@
#ifndef RUNTIME_BIN_UTILS_WIN_H_
#define RUNTIME_BIN_UTILS_WIN_H_
-#include "platform/globals.h"
+#include <utility>
+
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -38,30 +40,29 @@
};
// These scopes provide strings converted as indicated by the scope names.
-// The provided strings are allocated with 'new' and have the same lifetime as
-// the scope.
+// The provided strings are allocated with 'malloc' and have the same lifetime
+// as the scope.
class WideToUtf8Scope {
public:
- explicit WideToUtf8Scope(const wchar_t* wide) {
+ explicit WideToUtf8Scope(const wchar_t* wide)
+ : utf8_(Utils::CreateCStringUniquePtr(nullptr)) {
intptr_t utf8_len =
WideCharToMultiByte(CP_UTF8, 0, wide, -1, NULL, 0, NULL, NULL);
- char* utf8 = new char[utf8_len];
+ char* utf8 = reinterpret_cast<char*>(malloc(utf8_len));
WideCharToMultiByte(CP_UTF8, 0, wide, -1, utf8, utf8_len, NULL, NULL);
length_ = utf8_len;
- utf8_ = utf8;
+ utf8_ = Utils::CreateCStringUniquePtr(utf8);
}
- ~WideToUtf8Scope() {
- delete[] utf8_;
- utf8_ = NULL;
- }
-
- char* utf8() const { return utf8_; }
+ char* utf8() const { return utf8_.get(); }
intptr_t length() const { return length_; }
+ // Release the ownership of the converted string and return it.
+ Utils::CStringUniquePtr release() { return std::move(utf8_); }
+
private:
intptr_t length_;
- char* utf8_;
+ Utils::CStringUniquePtr utf8_;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(WideToUtf8Scope);
@@ -69,23 +70,16 @@
class Utf8ToWideScope {
public:
- explicit Utf8ToWideScope(const char* utf8) {
- int wide_len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
- wchar_t* wide = new wchar_t[wide_len];
- MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, wide_len);
- length_ = wide_len;
- wide_ = wide;
- }
-
- Utf8ToWideScope(const char* utf8, intptr_t length) {
+ explicit Utf8ToWideScope(const char* utf8, intptr_t length = -1) {
int wide_len = MultiByteToWideChar(CP_UTF8, 0, utf8, length, NULL, 0);
- wchar_t* wide = new wchar_t[wide_len];
+ wchar_t* wide =
+ reinterpret_cast<wchar_t*>(malloc(sizeof(wchar_t) * wide_len));
MultiByteToWideChar(CP_UTF8, 0, utf8, length, wide, wide_len);
length_ = wide_len;
wide_ = wide;
}
- ~Utf8ToWideScope() { delete[] wide_; }
+ ~Utf8ToWideScope() { free(wide_); }
wchar_t* wide() const { return wide_; }
intptr_t length() const { return length_; }
diff --git a/runtime/configs.gni b/runtime/configs.gni
index 971d242..94ee5d3 100644
--- a/runtime/configs.gni
+++ b/runtime/configs.gni
@@ -66,66 +66,77 @@
configs = _jit_config
snapshot = true
compiler = true
+ is_product = false
},
{
suffix = "_jit_product"
configs = _jit_product_config
snapshot = true
compiler = true
+ is_product = true
},
{
suffix = "_precompiled_runtime"
configs = _precompiled_runtime_config
snapshot = true
compiler = false
+ is_product = false
},
{
suffix = "_precompiled_runtime_product"
configs = _precompiled_runtime_product_config
snapshot = true
compiler = false
+ is_product = true
},
{
suffix = "_precompiler"
configs = _precompiler_config
snapshot = false
compiler = true
+ is_product = false
},
{
suffix = "_precompiler_product"
configs = _precompiler_product_config
snapshot = false
compiler = true
+ is_product = true
},
{
suffix = "_precompiler_fuchsia"
configs = _precompiler_fuchsia_config
snapshot = false
compiler = true
+ is_product = false
},
{
suffix = "_precompiler_product_fuchsia"
configs = _precompiler_product_fuchsia_config
snapshot = false
compiler = true
+ is_product = true
},
{
suffix = "_precompiler_host_targeting_host"
configs = _precompiler_host_targeting_host_config
snapshot = false
compiler = true
+ is_product = false
},
{
suffix = "_precompiler_product_host_targeting_host"
configs = _precompiler_product_host_targeting_host_config
snapshot = false
compiler = true
+ is_product = true
},
{
suffix = "_libfuzzer"
configs = _libfuzzer_config
snapshot = true
compiler = true
+ is_product = false
},
]
@@ -174,6 +185,14 @@
if (defined(invoker.extra_deps)) {
extra_deps += invoker.extra_deps
}
+ extra_product_deps = []
+ if (defined(invoker.extra_product_deps)) {
+ extra_product_deps += invoker.extra_product_deps
+ }
+ extra_nonproduct_deps = []
+ if (defined(invoker.extra_nonproduct_deps)) {
+ extra_nonproduct_deps += invoker.extra_nonproduct_deps
+ }
foreach(conf, _all_configs) {
target(invoker.target_type, "${target_name}${conf.suffix}") {
forward_variables_from(invoker,
@@ -196,6 +215,11 @@
}
}
deps = configured_deps + extra_deps
+ if (conf.is_product) {
+ deps += extra_product_deps
+ } else {
+ deps += extra_nonproduct_deps
+ }
if (conf.snapshot) {
if (defined(snapshot_sources)) {
sources += snapshot_sources
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 56120e7..a58095c 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -243,6 +243,8 @@
typedef struct _Dart_Handle* Dart_Handle;
typedef Dart_Handle Dart_PersistentHandle;
typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle;
+// These three structs are versioned by DART_API_DL_MAJOR_VERSION, bump the
+// version when changing this struct.
typedef void (*Dart_WeakPersistentHandleFinalizer)(
void* isolate_callback_data,
diff --git a/runtime/include/dart_api_dl.cc b/runtime/include/dart_api_dl.cc
new file mode 100644
index 0000000..5ab685d
--- /dev/null
+++ b/runtime/include/dart_api_dl.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#include "include/dart_api_dl.h"
+#include "include/dart_version.h"
+#include "include/internal/dart_api_dl_impl.h"
+
+#include <string.h>
+
+#define DART_API_DL_DEFINITIONS(name) \
+ using name##Type = decltype(&name); \
+ name##Type name##_DL = nullptr;
+DART_API_ALL_DL_SYMBOLS(DART_API_DL_DEFINITIONS)
+#undef DART_API_DL_DEFINITIONS
+
+typedef void (*DartApiEntry_function)();
+
+DartApiEntry_function FindFunctionPointer(const DartApiEntry* entries,
+ const char* name) {
+ while (entries->name != nullptr) {
+ if (strcmp(entries->name, name) == 0) return entries->function;
+ entries++;
+ }
+ return nullptr;
+}
+
+intptr_t Dart_InitializeApiDL(void* data) {
+ DartApi* dart_api_data = reinterpret_cast<DartApi*>(data);
+
+ if (dart_api_data->major != DART_API_DL_MAJOR_VERSION) {
+ // If the DartVM we're running on does not have the same version as this
+ // file was compiled against, refuse to initialize. The symbols are not
+ // compatible.
+ return -1;
+ }
+ // Minor versions are allowed to be different.
+ // If the DartVM has a higher minor version, it will provide more symbols
+ // than we initialize here.
+ // If the DartVM has a lower minor version, it will not provide all symbols.
+ // In that case, we leave the missing symbols un-initialized. Those symbols
+ // should not be used by the Dart and native code. The client is responsible
+ // for checking the minor version number himself based on which symbols it
+ // is using.
+ // (If we would error out on this case, recompiling native code against a
+ // newer SDK would break all uses on older SDKs, which is too strict.)
+
+ const DartApiEntry* dart_api_function_pointers = dart_api_data->functions;
+
+#define DART_API_DL_INIT(name) \
+ name##_DL = reinterpret_cast<name##Type>( \
+ FindFunctionPointer(dart_api_function_pointers, #name));
+ DART_API_ALL_DL_SYMBOLS(DART_API_DL_INIT)
+#undef DART_API_DL_INIT
+
+ return 0;
+}
diff --git a/runtime/include/dart_api_dl.h b/runtime/include/dart_api_dl.h
new file mode 100644
index 0000000..ba8424d
--- /dev/null
+++ b/runtime/include/dart_api_dl.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_API_DL_H_
+#define RUNTIME_INCLUDE_DART_API_DL_H_
+
+#include "include/dart_api.h"
+#include "include/dart_native_api.h"
+
+/** \mainpage Dynamically Linked Dart API
+ *
+ * This exposes a subset of symbols from dart_api.h and dart_native_api.h
+ * available in every Dart embedder through dynamic linking.
+ *
+ * All symbols are postfixed with _DL to indicate that they are dynamically
+ * linked and to prevent conflicts with the original symbol.
+ *
+ * Link `dart_api_dl.cc` file into your library and invoke
+ * `Dart_InitializeApiDL` with `NativeApi.initializeApiDLData`.
+ */
+
+intptr_t Dart_InitializeApiDL(void* data);
+
+// IMPORTANT! Never update these signatures without properly updating
+// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
+//
+// Verbatim copy of `dart_native_api.h` and `dart_api.h` symbols to trigger
+// compile-time errors if the sybols in those files are updated without
+// updating these.
+//
+// Function signatures and typedefs are carbon copied. Structs are typechecked
+// nominally in C/C++, so they are not copied, instead a comment is added to
+// their definition.
+typedef int64_t Dart_Port_DL;
+
+typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
+ Dart_CObject* message);
+
+DART_EXTERN_C bool (*Dart_PostCObject_DL)(Dart_Port_DL port_id,
+ Dart_CObject* message);
+
+DART_EXTERN_C bool (*Dart_PostInteger_DL)(Dart_Port_DL port_id,
+ int64_t message);
+
+DART_EXTERN_C Dart_Port_DL (*Dart_NewNativePort_DL)(
+ const char* name,
+ Dart_NativeMessageHandler_DL handler,
+ bool handle_concurrently);
+
+DART_EXTERN_C bool (*Dart_CloseNativePort_DL)(Dart_Port_DL native_port_id);
+
+DART_EXTERN_C bool (*Dart_IsError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C bool (*Dart_IsApiError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C bool (*Dart_IsUnhandledExceptionError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C bool (*Dart_IsCompilationError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C bool (*Dart_IsFatalError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C const char* (*Dart_GetError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C bool (*Dart_ErrorHasException_DL)(Dart_Handle handle);
+
+DART_EXTERN_C Dart_Handle (*Dart_ErrorGetException_DL)(Dart_Handle handle);
+
+DART_EXTERN_C Dart_Handle (*Dart_ErrorGetStackTrace_DL)(Dart_Handle handle);
+
+DART_EXTERN_C Dart_Handle (*Dart_NewApiError_DL)(const char* error);
+
+DART_EXTERN_C Dart_Handle (*Dart_NewCompilationError_DL)(const char* error);
+
+DART_EXTERN_C Dart_Handle (*Dart_NewUnhandledExceptionError_DL)(
+ Dart_Handle exception);
+
+DART_EXTERN_C void (*Dart_PropagateError_DL)(Dart_Handle handle);
+
+DART_EXTERN_C Dart_Handle (*Dart_ToString_DL)(Dart_Handle object);
+
+DART_EXTERN_C bool (*Dart_IdentityEquals_DL)(Dart_Handle obj1,
+ Dart_Handle obj2);
+
+DART_EXTERN_C Dart_Handle (*Dart_HandleFromPersistent_DL)(
+ Dart_PersistentHandle object);
+
+DART_EXTERN_C Dart_Handle (*Dart_HandleFromWeakPersistent_DL)(
+ Dart_WeakPersistentHandle object);
+
+DART_EXTERN_C Dart_PersistentHandle (*Dart_NewPersistentHandle_DL)(
+ Dart_Handle object);
+
+DART_EXTERN_C void (*Dart_SetPersistentHandle_DL)(Dart_PersistentHandle obj1,
+ Dart_Handle obj2);
+
+DART_EXTERN_C void (*Dart_DeletePersistentHandle_DL)(
+ Dart_PersistentHandle object);
+
+DART_EXTERN_C Dart_WeakPersistentHandle (*Dart_NewWeakPersistentHandle_DL)(
+ Dart_Handle object,
+ void* peer,
+ intptr_t external_allocation_size,
+ Dart_WeakPersistentHandleFinalizer callback);
+
+DART_EXTERN_C void (*Dart_DeleteWeakPersistentHandle_DL)(
+ Dart_WeakPersistentHandle object);
+
+DART_EXTERN_C bool (*Dart_Post_DL)(Dart_Port_DL port_id, Dart_Handle object);
+
+DART_EXTERN_C Dart_Handle (*Dart_NewSendPort_DL)(Dart_Port_DL port_id);
+
+DART_EXTERN_C Dart_Handle (*Dart_SendPortGetId_DL)(Dart_Handle port,
+ Dart_Port_DL* port_id);
+
+DART_EXTERN_C void (*Dart_EnterScope_DL)();
+
+DART_EXTERN_C void (*Dart_ExitScope_DL)();
+// IMPORTANT! Never update these signatures without properly updating
+// DART_API_DL_MAJOR_VERSION and DART_API_DL_MINOR_VERSION.
+//
+// End of verbatim copy.
+
+#endif /* RUNTIME_INCLUDE_DART_API_DL_H_ */ /* NOLINT */
\ No newline at end of file
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index 7e94118..495d454 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -83,6 +83,8 @@
} as_external_typed_data;
} value;
} Dart_CObject;
+// This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when
+// changing this struct.
/**
* Posts a message on some port. The message will contain the Dart_CObject
diff --git a/runtime/include/dart_version.h b/runtime/include/dart_version.h
new file mode 100644
index 0000000..777620b
--- /dev/null
+++ b/runtime/include/dart_version.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_DART_VERSION_H_
+#define RUNTIME_INCLUDE_DART_VERSION_H_
+
+// On breaking changes the major version is increased.
+// On backwards compatible changes the minor version is increased.
+// The versioning covers the symbols exposed in dart_api_dl.h
+#define DART_API_DL_MAJOR_VERSION 1
+#define DART_API_DL_MINOR_VERSION 0
+
+#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */
diff --git a/runtime/include/internal/dart_api_dl_impl.h b/runtime/include/internal/dart_api_dl_impl.h
new file mode 100644
index 0000000..f77063d
--- /dev/null
+++ b/runtime/include/internal/dart_api_dl_impl.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+ * for details. All rights reserved. Use of this source code is governed by a
+ * BSD-style license that can be found in the LICENSE file.
+ */
+
+#ifndef RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
+#define RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_
+
+// dart_native_api.h symbols can be called on any thread.
+#define DART_NATIVE_API_DL_SYMBOLS(F) \
+ /***** dart_native_api.h *****/ \
+ /* Dart_Port */ \
+ F(Dart_PostCObject) \
+ F(Dart_PostInteger) \
+ F(Dart_NewNativePort) \
+ F(Dart_CloseNativePort)
+
+// dart_api.h symbols can only be called on Dart threads.
+#define DART_API_DL_SYMBOLS(F) \
+ /***** dart_api.h *****/ \
+ /* Errors */ \
+ F(Dart_IsError) \
+ F(Dart_IsApiError) \
+ F(Dart_IsUnhandledExceptionError) \
+ F(Dart_IsCompilationError) \
+ F(Dart_IsFatalError) \
+ F(Dart_GetError) \
+ F(Dart_ErrorHasException) \
+ F(Dart_ErrorGetException) \
+ F(Dart_ErrorGetStackTrace) \
+ F(Dart_NewApiError) \
+ F(Dart_NewCompilationError) \
+ F(Dart_NewUnhandledExceptionError) \
+ F(Dart_PropagateError) \
+ /* Dart_Handle, Dart_PersistentHandle, Dart_WeakPersistentHandle */ \
+ F(Dart_NewPersistentHandle) \
+ F(Dart_SetPersistentHandle) \
+ F(Dart_HandleFromPersistent) \
+ F(Dart_DeletePersistentHandle) \
+ F(Dart_NewWeakPersistentHandle) \
+ F(Dart_HandleFromWeakPersistent) \
+ F(Dart_DeleteWeakPersistentHandle) \
+ /* Dart_Port */ \
+ F(Dart_Post) \
+ F(Dart_NewSendPort) \
+ F(Dart_SendPortGetId) \
+ /* Scopes */ \
+ F(Dart_EnterScope) \
+ F(Dart_ExitScope)
+
+#define DART_API_ALL_DL_SYMBOLS(F) \
+ DART_NATIVE_API_DL_SYMBOLS(F) \
+ DART_API_DL_SYMBOLS(F)
+
+struct DartApiEntry {
+ const char* name;
+ void (*function)();
+};
+
+struct DartApi {
+ const int major;
+ const int minor;
+ const DartApiEntry* const functions;
+};
+
+#endif /* RUNTIME_INCLUDE_INTERNAL_DART_API_DL_IMPL_H_ */ /* NOLINT */
diff --git a/runtime/lib/errors.cc b/runtime/lib/errors.cc
index 8d9fb8d..2465c8b 100644
--- a/runtime/lib/errors.cc
+++ b/runtime/lib/errors.cc
@@ -107,6 +107,42 @@
return Object::null();
}
+// Allocate and throw a new AssertionError.
+// Arg0: Source code snippet of failed assertion.
+// Arg1: Line number.
+// Arg2: Column number.
+// Arg3: Message object or null.
+// Return value: none, throws an exception.
+DEFINE_NATIVE_ENTRY(AssertionError_throwNewSource, 0, 4) {
+ // No need to type check the arguments. This function can only be called
+ // internally from the VM.
+ const String& failed_assertion =
+ String::CheckedHandle(zone, arguments->NativeArgAt(0));
+ const intptr_t line =
+ Smi::CheckedHandle(zone, arguments->NativeArgAt(1)).Value();
+ const intptr_t column =
+ Smi::CheckedHandle(zone, arguments->NativeArgAt(2)).Value();
+ const Instance& message =
+ Instance::CheckedHandle(zone, arguments->NativeArgAt(3));
+
+ const Array& args = Array::Handle(zone, Array::New(5));
+
+ DartFrameIterator iterator(thread,
+ StackFrameIterator::kNoCrossThreadIteration);
+ iterator.NextFrame(); // Skip native call.
+ const Script& script = Script::Handle(zone, FindScript(&iterator));
+
+ args.SetAt(0, failed_assertion);
+ args.SetAt(1, String::Handle(zone, script.url()));
+ args.SetAt(2, Smi::Handle(zone, Smi::New(line)));
+ args.SetAt(3, Smi::Handle(zone, Smi::New(column)));
+ args.SetAt(4, message);
+
+ Exceptions::ThrowByType(Exceptions::kAssertion, args);
+ UNREACHABLE();
+ return Object::null();
+}
+
// Allocate and throw a new TypeError or CastError.
// Arg0: index of the token of the failed type check.
// Arg1: src value.
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index d4c6c43..1a8bc20 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -4,6 +4,8 @@
#include "include/dart_api.h"
#include "include/dart_native_api.h"
+#include "include/dart_version.h"
+#include "include/internal/dart_api_dl_impl.h"
#include "platform/globals.h"
#include "vm/bootstrap_natives.h"
#include "vm/class_finalizer.h"
@@ -495,21 +497,41 @@
return Pointer::New(type_arg, entry_point);
}
-DEFINE_NATIVE_ENTRY(NativeApiFunctionPointer, 0, 1) {
+DEFINE_NATIVE_ENTRY(DartNativeApiFunctionPointer, 0, 1) {
GET_NON_NULL_NATIVE_ARGUMENT(String, name_dart, arguments->NativeArgAt(0));
const char* name = name_dart.ToCString();
- if (strcmp(name, "Dart_PostCObject") == 0) {
- return Integer::New(reinterpret_cast<int64_t>(Dart_PostCObject));
- } else if (strcmp(name, "Dart_NewNativePort") == 0) {
- return Integer::New(reinterpret_cast<int64_t>(Dart_NewNativePort));
- } else if (strcmp(name, "Dart_CloseNativePort") == 0) {
- return Integer::New(reinterpret_cast<int64_t>(Dart_CloseNativePort));
+#define RETURN_FUNCTION_ADDRESS(function_name) \
+ if (strcmp(name, #function_name) == 0) { \
+ return Integer::New(reinterpret_cast<intptr_t>(function_name)); \
}
+ DART_NATIVE_API_DL_SYMBOLS(RETURN_FUNCTION_ADDRESS)
+#undef RETURN_FUNCTION_ADDRESS
const String& error = String::Handle(
String::NewFormatted("Unknown dart_native_api.h symbol: %s.", name));
Exceptions::ThrowArgumentError(error);
}
+DEFINE_NATIVE_ENTRY(DartApiDLMajorVersion, 0, 0) {
+ return Integer::New(DART_API_DL_MAJOR_VERSION);
+}
+
+DEFINE_NATIVE_ENTRY(DartApiDLMinorVersion, 0, 0) {
+ return Integer::New(DART_API_DL_MINOR_VERSION);
+}
+
+static const DartApiEntry dart_api_entries[] = {
+#define ENTRY(name) DartApiEntry{#name, reinterpret_cast<void (*)()>(name)},
+ DART_API_ALL_DL_SYMBOLS(ENTRY)
+#undef ENTRY
+ DartApiEntry{nullptr, nullptr}};
+
+static const DartApi dart_api_data = {
+ DART_API_DL_MAJOR_VERSION, DART_API_DL_MINOR_VERSION, dart_api_entries};
+
+DEFINE_NATIVE_ENTRY(DartApiDLInitializeData, 0, 0) {
+ return Integer::New(reinterpret_cast<intptr_t>(&dart_api_data));
+}
+
} // namespace dart
diff --git a/runtime/platform/BUILD.gn b/runtime/platform/BUILD.gn
index 012421d..c727eea 100644
--- a/runtime/platform/BUILD.gn
+++ b/runtime/platform/BUILD.gn
@@ -17,7 +17,9 @@
extra_deps = []
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ extra_deps += [ "$fuchsia_sdk_root/pkg/sys_cpp" ]
+ } else if (using_fuchsia_sdk) {
extra_deps += [ "$fuchsia_sdk_root/pkg:sys_cpp" ]
} else {
extra_deps += [ "//sdk/lib/sys/cpp" ]
diff --git a/runtime/tests/vm/dart/appjit_spawnuri_test.dart b/runtime/tests/vm/dart/appjit_spawnuri_test.dart
new file mode 100644
index 0000000..88ea2fc
--- /dev/null
+++ b/runtime/tests/vm/dart/appjit_spawnuri_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that using spawnUri to spawn an isolate from app-jit snapshot works.
+
+import 'dart:io';
+import 'dart:isolate';
+
+import 'snapshot_test_helper.dart';
+
+Future<void> main() =>
+ runAppJitTest(Platform.script.resolve('appjit_spawnuri_test_body.dart'),
+ runSnapshot: (snapshotPath) async {
+ final exitPort = ReceivePort();
+ final messagePort = ReceivePort();
+ await Isolate.spawnUri(Uri.file(snapshotPath), [], messagePort.sendPort,
+ onExit: exitPort.sendPort);
+ final result = await Future.wait([messagePort.first, exitPort.first]);
+ print('DONE (${result[0]})');
+ return Result('Isolate.spawnUri(${Uri.file(snapshotPath)})',
+ ProcessResult(0, 0, result[0], ''));
+ });
diff --git a/runtime/tests/vm/dart/appjit_spawnuri_test_body.dart b/runtime/tests/vm/dart/appjit_spawnuri_test_body.dart
new file mode 100644
index 0000000..ce193aa
--- /dev/null
+++ b/runtime/tests/vm/dart/appjit_spawnuri_test_body.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that using spawnUri to spawn an isolate from app-jit snapshot works.
+
+import 'dart:isolate';
+
+import 'package:expect/expect.dart';
+
+int computation(int n) =>
+ List.generate(n, (i) => i == 0 ? 1 : 0).fold(0, (a, b) => a + b);
+
+Future<void> main(List<String> args, [dynamic sendPort]) async {
+ final isTraining = args.contains('--train');
+
+ var result = 0;
+ for (var i = 0; i < 1000; i++) {
+ result += computation(i);
+ }
+ Expect.equals(999, result);
+ if (isTraining) {
+ print('OK(Trained)');
+ } else {
+ (sendPort as SendPort).send('OK(Run)');
+ }
+}
diff --git a/runtime/tests/vm/dart/regress_flutter_57398_test.dart b/runtime/tests/vm/dart/regress_flutter_57398_test.dart
index a2a93ab..c98d96c 100644
--- a/runtime/tests/vm/dart/regress_flutter_57398_test.dart
+++ b/runtime/tests/vm/dart/regress_flutter_57398_test.dart
@@ -9,7 +9,7 @@
import 'package:expect/expect.dart';
class W<T> {
- final FutureOr<T> v;
+ final FutureOr<T>? v;
W({this.v});
@pragma('vm:never-inline')
diff --git a/runtime/tests/vm/dart/snapshot_test_helper.dart b/runtime/tests/vm/dart/snapshot_test_helper.dart
index b0cf664..853fc33 100644
--- a/runtime/tests/vm/dart/snapshot_test_helper.dart
+++ b/runtime/tests/vm/dart/snapshot_test_helper.dart
@@ -158,7 +158,11 @@
});
}
-runAppJitTest(Uri testScriptUri) async {
+runAppJitTest(Uri testScriptUri,
+ {Future<Result> Function(String snapshotPath)? runSnapshot}) async {
+ runSnapshot ??=
+ (snapshotPath) => runDart('RUN FROM SNAPSHOT', [snapshotPath]);
+
await withTempDir((String temp) async {
final snapshotPath = p.join(temp, 'app.jit');
final testPath = testScriptUri.toFilePath();
@@ -170,7 +174,7 @@
'--train'
]);
expectOutput("OK(Trained)", trainingResult);
- final runResult = await runDart('RUN FROM SNAPSHOT', [snapshotPath]);
+ final runResult = await runSnapshot!(snapshotPath);
expectOutput("OK(Run)", runResult);
});
}
diff --git a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
index 2ecfcc8..ea385af 100644
--- a/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart/v8_snapshot_profile_writer_test.dart
@@ -16,7 +16,12 @@
required bool useAsm,
required bool useBare,
required bool stripFlag,
- required bool stripUtil}) async {
+ required bool stripUtil,
+ bool disassemble = false}) async {
+ // We don't assume forced disassembler support in Product mode, so skip any
+ // disassembly test.
+ if (!const bool.fromEnvironment('dart.vm.product') && disassemble) return;
+
// The assembler may add extra unnecessary information to the compiled
// snapshot whether or not we generate DWARF information in the assembly, so
// we force the use of a utility when generating assembly.
@@ -30,7 +35,8 @@
(useAsm ? '-assembly' : '-elf') +
(useBare ? '-bare' : '-nonbare') +
(stripFlag ? '-intstrip' : '') +
- (stripUtil ? '-extstrip' : '');
+ (stripUtil ? '-extstrip' : '') +
+ (disassemble ? '-disassembled' : '');
await withTempDir(tempDirPrefix, (String tempDir) async {
// Generate the snapshot profile.
@@ -40,9 +46,7 @@
if (stripFlag) '--strip',
useBare ? '--use-bare-instructions' : '--no-use-bare-instructions',
"--write-v8-snapshot-profile-to=$profilePath",
- // Regression test for dartbug.com/41149. We don't assume forced
- // disassembler support in Product mode.
- if (!const bool.fromEnvironment('dart.vm.product')) '--disassemble',
+ if (disassemble) '--disassemble',
'--ignore-unrecognized-flags',
dillPath,
];
@@ -242,6 +246,15 @@
useAsm: false,
useBare: true);
+ // Regression test for dartbug.com/41149.
+ await test(
+ dillPath: dillPath,
+ stripFlag: true,
+ stripUtil: false,
+ useAsm: false,
+ useBare: false,
+ disassemble: true);
+
// We neither generate assembly nor have a stripping utility on Windows.
if (Platform.isWindows) {
printSkip('external stripping and assembly tests');
diff --git a/runtime/tests/vm/dart_2/appjit_spawnuri_test.dart b/runtime/tests/vm/dart_2/appjit_spawnuri_test.dart
new file mode 100644
index 0000000..88ea2fc
--- /dev/null
+++ b/runtime/tests/vm/dart_2/appjit_spawnuri_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that using spawnUri to spawn an isolate from app-jit snapshot works.
+
+import 'dart:io';
+import 'dart:isolate';
+
+import 'snapshot_test_helper.dart';
+
+Future<void> main() =>
+ runAppJitTest(Platform.script.resolve('appjit_spawnuri_test_body.dart'),
+ runSnapshot: (snapshotPath) async {
+ final exitPort = ReceivePort();
+ final messagePort = ReceivePort();
+ await Isolate.spawnUri(Uri.file(snapshotPath), [], messagePort.sendPort,
+ onExit: exitPort.sendPort);
+ final result = await Future.wait([messagePort.first, exitPort.first]);
+ print('DONE (${result[0]})');
+ return Result('Isolate.spawnUri(${Uri.file(snapshotPath)})',
+ ProcessResult(0, 0, result[0], ''));
+ });
diff --git a/runtime/tests/vm/dart_2/appjit_spawnuri_test_body.dart b/runtime/tests/vm/dart_2/appjit_spawnuri_test_body.dart
new file mode 100644
index 0000000..ce193aa
--- /dev/null
+++ b/runtime/tests/vm/dart_2/appjit_spawnuri_test_body.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that using spawnUri to spawn an isolate from app-jit snapshot works.
+
+import 'dart:isolate';
+
+import 'package:expect/expect.dart';
+
+int computation(int n) =>
+ List.generate(n, (i) => i == 0 ? 1 : 0).fold(0, (a, b) => a + b);
+
+Future<void> main(List<String> args, [dynamic sendPort]) async {
+ final isTraining = args.contains('--train');
+
+ var result = 0;
+ for (var i = 0; i < 1000; i++) {
+ result += computation(i);
+ }
+ Expect.equals(999, result);
+ if (isTraining) {
+ print('OK(Trained)');
+ } else {
+ (sendPort as SendPort).send('OK(Run)');
+ }
+}
diff --git a/runtime/tests/vm/dart_2/snapshot_test_helper.dart b/runtime/tests/vm/dart_2/snapshot_test_helper.dart
index a66c247..9be810a 100644
--- a/runtime/tests/vm/dart_2/snapshot_test_helper.dart
+++ b/runtime/tests/vm/dart_2/snapshot_test_helper.dart
@@ -158,7 +158,11 @@
});
}
-runAppJitTest(Uri testScriptUri) async {
+runAppJitTest(Uri testScriptUri,
+ {Future<Result> Function(String snapshotPath) runSnapshot}) async {
+ runSnapshot ??=
+ (snapshotPath) => runDart('RUN FROM SNAPSHOT', [snapshotPath]);
+
await withTempDir((String temp) async {
final snapshotPath = p.join(temp, 'app.jit');
final testPath = testScriptUri.toFilePath();
@@ -170,7 +174,7 @@
'--train'
]);
expectOutput("OK(Trained)", trainingResult);
- final runResult = await runDart('RUN FROM SNAPSHOT', [snapshotPath]);
+ final runResult = await runSnapshot(snapshotPath);
expectOutput("OK(Run)", runResult);
});
}
diff --git a/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart b/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
index de3795c..de5facf 100644
--- a/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
+++ b/runtime/tests/vm/dart_2/v8_snapshot_profile_writer_test.dart
@@ -16,7 +16,12 @@
bool useAsm,
bool useBare,
bool stripFlag,
- bool stripUtil}) async {
+ bool stripUtil,
+ bool disassemble = false}) async {
+ // We don't assume forced disassembler support in Product mode, so skip any
+ // disassembly test.
+ if (!const bool.fromEnvironment('dart.vm.product') && disassemble) return;
+
// The assembler may add extra unnecessary information to the compiled
// snapshot whether or not we generate DWARF information in the assembly, so
// we force the use of a utility when generating assembly.
@@ -30,7 +35,8 @@
(useAsm ? '-assembly' : '-elf') +
(useBare ? '-bare' : '-nonbare') +
(stripFlag ? '-intstrip' : '') +
- (stripUtil ? '-extstrip' : '');
+ (stripUtil ? '-extstrip' : '') +
+ (disassemble ? '-disassembled' : '');
await withTempDir(tempDirPrefix, (String tempDir) async {
// Generate the snapshot profile.
@@ -40,10 +46,7 @@
if (stripFlag) '--strip',
useBare ? '--use-bare-instructions' : '--no-use-bare-instructions',
"--write-v8-snapshot-profile-to=$profilePath",
- // Regression test for dartbug.com/41149. We don't assume forced
- // disassembler support in Product mode.
- if (!const bool.fromEnvironment('dart.vm.product'))
- '--disassemble',
+ if (disassemble) '--disassemble',
'--ignore-unrecognized-flags',
dillPath,
];
@@ -239,6 +242,15 @@
useAsm: false,
useBare: true);
+ // Regression test for dartbug.com/41149.
+ await test(
+ dillPath: dillPath,
+ stripFlag: true,
+ stripUtil: false,
+ useAsm: false,
+ useBare: false,
+ disassemble: true);
+
// We neither generate assembly nor have a stripping utility on Windows.
if (Platform.isWindows) {
printSkip('external stripping and assembly tests');
diff --git a/runtime/third_party/double-conversion/src/BUILD.gn b/runtime/third_party/double-conversion/src/BUILD.gn
index e790868..b16ec11 100644
--- a/runtime/third_party/double-conversion/src/BUILD.gn
+++ b/runtime/third_party/double-conversion/src/BUILD.gn
@@ -3,6 +3,12 @@
# BSD-style license that can be found in the LICENSE file.
source_set("libdouble_conversion") {
+ # We are only interested in exposing the exported symbols (for size reasons).
+ cflags = []
+ if (is_posix) {
+ cflags += [ "-fvisibility=hidden" ]
+ }
+
configs += [
"../../..:dart_arch_config",
"../../..:dart_config",
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 3888a2b..1716f3d 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -63,10 +63,26 @@
library_for_all_configs("libdart_vm") {
target_type = "source_set"
- extra_deps = [ "//third_party/icu" ]
+ extra_product_deps = [
+ "//third_party/icu:icui18n_hidden_visibility",
+ "//third_party/icu:icuuc_hidden_visibility",
+ ]
+ extra_nonproduct_deps = [
+ "//third_party/icu:icui18n",
+ "//third_party/icu:icuuc",
+ ]
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
- extra_deps += [
+ if (using_fuchsia_gn_sdk) {
+ extra_deps = [
+ "$fuchsia_sdk_root/fidl/fuchsia.deprecatedtimezone",
+ "$fuchsia_sdk_root/pkg/inspect",
+ "$fuchsia_sdk_root/pkg/inspect_service_cpp",
+ "$fuchsia_sdk_root/pkg/sys_cpp",
+ "$fuchsia_sdk_root/pkg/sys_inspect_cpp",
+ "$fuchsia_sdk_root/pkg/trace-engine",
+ ]
+ } else if (using_fuchsia_sdk) {
+ extra_deps = [
"$fuchsia_sdk_root/fidl:fuchsia.deprecatedtimezone",
"$fuchsia_sdk_root/pkg:inspect",
"$fuchsia_sdk_root/pkg:inspect_service_cpp",
@@ -75,7 +91,7 @@
"$fuchsia_sdk_root/pkg:trace-engine",
]
} else {
- extra_deps += [
+ extra_deps = [
# TODO(US-399): Remove time_service specific code when it is no longer
# necessary.
"//sdk/fidl/fuchsia.deprecatedtimezone",
@@ -107,7 +123,9 @@
sources = rebase_path(compiler_sources, ".", "./compiler/")
include_dirs = [ ".." ]
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ extra_deps = [ "$fuchsia_sdk_root/pkg/trace-engine" ]
+ } else if (using_fuchsia_sdk) {
extra_deps = [ "$fuchsia_sdk_root/pkg:trace-engine" ]
} else {
extra_deps = [
@@ -121,7 +139,9 @@
library_for_all_configs("libdart_lib") {
target_type = "source_set"
if (is_fuchsia) {
- if (using_fuchsia_sdk) {
+ if (using_fuchsia_gn_sdk) {
+ extra_deps = [ "$fuchsia_sdk_root/pkg/trace-engine" ]
+ } else if (using_fuchsia_sdk) {
extra_deps = [ "$fuchsia_sdk_root/pkg:trace-engine" ]
} else {
extra_deps = [
@@ -147,6 +167,10 @@
template("gen_vm_platform") {
assert(defined(invoker.output_postfix),
"Must define output postfix (e.g., '_strong'")
+ is_product_flag = dart_runtime_mode == "release"
+ if (defined(invoker.product_mode)) {
+ is_product_flag = invoker.product_mode
+ }
compile_platform(target_name) {
output_postfix = invoker.output_postfix
if (defined(invoker.add_implicit_vm_platform_dependency)) {
@@ -161,7 +185,6 @@
"$root_out_dir/vm_outline" + output_postfix + ".dill",
]
args = [ "dart:core" ]
- is_product_flag = dart_runtime_mode == "release"
allow_causal_async_stacks = !is_product_flag
args += [
"-Ddart.vm.product=$is_product_flag",
@@ -186,6 +209,16 @@
output_postfix = "_strong"
}
+gen_vm_platform("vm_platform_product") {
+ add_implicit_vm_platform_dependency = false
+ exclude_source = false
+ output_postfix = "_strong_product"
+
+ # In Debug mode we use debug binaries for dart2native.
+ # (see also the "dart_product_config" config)
+ product_mode = !is_debug
+}
+
gen_vm_platform("vm_platform_stripped") {
add_implicit_vm_platform_dependency = false
exclude_source = true
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 6ce5668..a805629 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -158,6 +158,7 @@
V(DateTime_timeZoneOffsetInSeconds, 1) \
V(DateTime_localTimeZoneAdjustmentInSeconds, 0) \
V(AssertionError_throwNew, 3) \
+ V(AssertionError_throwNewSource, 4) \
V(Async_rethrow, 2) \
V(StackTrace_asyncStackTraceHelper, 1) \
V(StackTrace_clearAsyncThreadStackTrace, 0) \
@@ -413,7 +414,10 @@
V(Ffi_asExternalTypedData, 2) \
V(Ffi_dl_processLibrary, 0) \
V(Ffi_dl_executableLibrary, 0) \
- V(NativeApiFunctionPointer, 1) \
+ V(DartApiDLInitializeData, 0) \
+ V(DartApiDLMajorVersion, 0) \
+ V(DartApiDLMinorVersion, 0) \
+ V(DartNativeApiFunctionPointer, 1) \
V(TransferableTypedData_factory, 2) \
V(TransferableTypedData_materialize, 1) \
V(Wasm_initModule, 2) \
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 25a8d76..f3ca74d 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -27,6 +27,7 @@
#include "vm/symbols.h"
#include "vm/timeline.h"
#include "vm/version.h"
+#include "vm/zone_text_buffer.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/backend/code_statistics.h"
@@ -602,7 +603,7 @@
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
FunctionPtr func = objects_[i];
- AutoTraceObjectName(func, func->ptr()->name_);
+ AutoTraceObjectName(func, MakeDisambiguatedFunctionName(s, func));
WriteFromTo(func);
if (kind == Snapshot::kFull) {
NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
@@ -626,6 +627,22 @@
}
}
+ static const char* MakeDisambiguatedFunctionName(Serializer* s,
+ FunctionPtr f) {
+ if (s->profile_writer() == nullptr) {
+ return nullptr;
+ }
+
+ REUSABLE_FUNCTION_HANDLESCOPE(s->thread());
+ Function& fun = reused_function_handle.Handle();
+ fun = f;
+ ZoneTextBuffer printer(s->thread()->zone());
+ fun.PrintName(NameFormattingParams::DisambiguatedUnqualified(
+ Object::NameVisibility::kInternalName),
+ &printer);
+ return printer.buffer();
+ }
+
private:
GrowableArray<FunctionPtr> objects_;
};
@@ -1561,7 +1578,7 @@
const intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
CodePtr code = objects_[i];
- AutoTraceObject(code);
+ AutoTraceObjectName(code, MakeDisambiguatedCodeName(s, code));
intptr_t pointer_offsets_length =
Code::PtrOffBits::decode(code->ptr()->state_bits_);
@@ -1652,6 +1669,19 @@
}
private:
+ static const char* MakeDisambiguatedCodeName(Serializer* s, CodePtr c) {
+ if (s->profile_writer() == nullptr) {
+ return nullptr;
+ }
+
+ REUSABLE_CODE_HANDLESCOPE(s->thread());
+ Code& code = reused_code_handle.Handle();
+ code = c;
+ return code.QualifiedName(
+ NameFormattingParams::DisambiguatedWithoutClassName(
+ Object::NameVisibility::kInternalName));
+ }
+
GrowableArray<CodePtr> objects_;
};
#endif // !DART_PRECOMPILED_RUNTIME
@@ -4812,6 +4842,22 @@
StringPtr name) {
if (profile_writer_ == nullptr) return;
+ const char* name_str = nullptr;
+ if (name != nullptr) {
+ REUSABLE_STRING_HANDLESCOPE(thread());
+ String& str = reused_string_handle.Handle();
+ str = name;
+ name_str = str.ToCString();
+ }
+
+ TraceStartWritingObject(type, obj, name_str);
+}
+
+void Serializer::TraceStartWritingObject(const char* type,
+ ObjectPtr obj,
+ const char* name) {
+ if (profile_writer_ == nullptr) return;
+
intptr_t cid = -1;
intptr_t id = 0;
if (obj->IsHeapObject()) {
@@ -4826,20 +4872,13 @@
}
ASSERT(IsAllocatedReference(id));
- const char* name_str = nullptr;
- if (name != nullptr) {
- String& str = thread()->StringHandle();
- str = name;
- name_str = str.ToCString();
- }
-
FlushBytesWrittenToRoot();
object_currently_writing_.object_ = obj;
object_currently_writing_.id_ = id;
object_currently_writing_.stream_start_ = stream_.Position();
object_currently_writing_.cid_ = cid;
profile_writer_->SetObjectTypeAndName(
- {V8SnapshotProfileWriter::kSnapshot, id}, type, name_str);
+ {V8SnapshotProfileWriter::kSnapshot, id}, type, name);
}
void Serializer::TraceEndWritingObject() {
@@ -4853,6 +4892,7 @@
}
}
+#if !defined(DART_PRECOMPILED_RUNTIME)
bool Serializer::CreateArtificalNodeIfNeeded(ObjectPtr obj) {
ASSERT(profile_writer() != nullptr);
@@ -4867,14 +4907,16 @@
id = AssignArtificialRef(obj);
const char* type = nullptr;
- StringPtr name = nullptr;
+ StringPtr name_string = nullptr;
+ const char* name = nullptr;
ObjectPtr owner = nullptr;
const char* owner_ref_name = nullptr;
switch (obj->GetClassId()) {
case kFunctionCid: {
FunctionPtr func = static_cast<FunctionPtr>(obj);
type = "Function";
- name = func->ptr()->name_;
+ name = FunctionSerializationCluster::MakeDisambiguatedFunctionName(this,
+ func);
owner_ref_name = "owner_";
owner = func->ptr()->owner_;
break;
@@ -4882,7 +4924,7 @@
case kClassCid: {
ClassPtr cls = static_cast<ClassPtr>(obj);
type = "Class";
- name = cls->ptr()->name_;
+ name_string = cls->ptr()->name_;
owner_ref_name = "library_";
owner = cls->ptr()->library_;
break;
@@ -4897,13 +4939,20 @@
case kLibraryCid: {
LibraryPtr lib = static_cast<LibraryPtr>(obj);
type = "Library";
- name = lib->ptr()->url_;
+ name_string = lib->ptr()->url_;
break;
}
default:
UNREACHABLE();
}
+ if (name_string != nullptr) {
+ REUSABLE_STRING_HANDLESCOPE(thread());
+ String& str = reused_string_handle.Handle();
+ str = name_string;
+ name = str.ToCString();
+ }
+
TraceStartWritingObject(type, obj, name);
if (owner != nullptr) {
CreateArtificalNodeIfNeeded(owner);
@@ -4913,6 +4962,7 @@
TraceEndWritingObject();
return true;
}
+#endif // !defined(DART_PRECOMPILED_RUNTIME)
const char* Serializer::ReadOnlyObjectType(intptr_t cid) {
switch (cid) {
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 1827670..9adda50 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -255,6 +255,9 @@
void FlushBytesWrittenToRoot();
void TraceStartWritingObject(const char* type, ObjectPtr obj, StringPtr name);
+ void TraceStartWritingObject(const char* type,
+ ObjectPtr obj,
+ const char* name);
void TraceEndWritingObject();
// Writes raw data to the stream (basic type).
@@ -494,7 +497,8 @@
#define WriteField(obj, field) s->WritePropertyRef(obj->ptr()->field, #field)
-struct SerializerWritingObjectScope {
+class SerializerWritingObjectScope {
+ public:
SerializerWritingObjectScope(Serializer* serializer,
const char* type,
ObjectPtr object,
@@ -503,6 +507,14 @@
serializer_->TraceStartWritingObject(type, object, name);
}
+ SerializerWritingObjectScope(Serializer* serializer,
+ const char* type,
+ ObjectPtr object,
+ const char* name)
+ : serializer_(serializer) {
+ serializer_->TraceStartWritingObject(type, object, name);
+ }
+
~SerializerWritingObjectScope() { serializer_->TraceEndWritingObject(); }
private:
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 05913ac..833b344 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -170,6 +170,10 @@
bool Equals(Value* other) const;
+ // Returns true if this |Value| can evaluate to the given |value| during
+ // execution.
+ inline bool CanBe(const Object& value);
+
private:
friend class FlowGraphPrinter;
friend class FlowGraphDeserializer; // For setting reaching_type_ directly.
@@ -9392,6 +9396,11 @@
}
}
+inline bool Value::CanBe(const Object& value) {
+ ConstantInstr* constant = definition()->AsConstant();
+ return (constant == nullptr) || constant->value().raw() == value.raw();
+}
+
} // namespace dart
#endif // RUNTIME_VM_COMPILER_BACKEND_IL_H_
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 21d3060..de5924f 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -3490,13 +3490,18 @@
// type argument vector instantiated from null becomes a vector of dynamic,
// then use null as the type arguments.
compiler::Label type_arguments_instantiated;
+ const bool can_function_type_args_be_null =
+ function_type_arguments()->CanBe(Object::null_object());
const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawWhenInstantiatedFromRaw(len)) {
+ if (type_arguments().IsRawWhenInstantiatedFromRaw(len) &&
+ can_function_type_args_be_null) {
ASSERT(result_reg != instantiator_type_args_reg &&
result_reg != function_type_args_reg);
__ LoadObject(result_reg, Object::null_object());
__ cmp(instantiator_type_args_reg, compiler::Operand(result_reg));
- __ cmp(function_type_args_reg, compiler::Operand(result_reg), EQ);
+ if (!function_type_arguments()->BindsToConstant()) {
+ __ cmp(function_type_args_reg, compiler::Operand(result_reg), EQ);
+ }
__ b(&type_arguments_instantiated, EQ);
}
// Lookup cache in stub before calling runtime.
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 52ec9a8..158ec26 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -2989,14 +2989,19 @@
// then use null as the type arguments.
compiler::Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawWhenInstantiatedFromRaw(len)) {
+ const bool can_function_type_args_be_null =
+ function_type_arguments()->CanBe(Object::null_object());
+ if (type_arguments().IsRawWhenInstantiatedFromRaw(len) &&
+ can_function_type_args_be_null) {
compiler::Label non_null_type_args;
ASSERT(result_reg != instantiator_type_args_reg &&
result_reg != function_type_args_reg);
__ LoadObject(result_reg, Object::null_object());
__ CompareRegisters(instantiator_type_args_reg, result_reg);
- __ b(&non_null_type_args, NE);
- __ CompareRegisters(function_type_args_reg, result_reg);
+ if (!function_type_arguments()->BindsToConstant()) {
+ __ b(&non_null_type_args, NE);
+ __ CompareRegisters(function_type_args_reg, result_reg);
+ }
__ b(&type_arguments_instantiated, EQ);
__ Bind(&non_null_type_args);
}
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 956c45f..239824f 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -2743,14 +2743,19 @@
// then use null as the type arguments.
compiler::Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawWhenInstantiatedFromRaw(len)) {
+ const bool can_function_type_args_be_null =
+ function_type_arguments()->CanBe(Object::null_object());
+ if (type_arguments().IsRawWhenInstantiatedFromRaw(len) &&
+ can_function_type_args_be_null) {
compiler::Label non_null_type_args;
ASSERT(result_reg != instantiator_type_args_reg &&
result_reg != function_type_args_reg);
__ LoadObject(result_reg, Object::null_object());
__ cmpl(instantiator_type_args_reg, result_reg);
- __ j(NOT_EQUAL, &non_null_type_args, compiler::Assembler::kNearJump);
- __ cmpl(function_type_args_reg, result_reg);
+ if (!function_type_arguments()->BindsToConstant()) {
+ __ j(NOT_EQUAL, &non_null_type_args, compiler::Assembler::kNearJump);
+ __ cmpl(function_type_args_reg, result_reg);
+ }
__ j(EQUAL, &type_arguments_instantiated, compiler::Assembler::kNearJump);
__ Bind(&non_null_type_args);
}
diff --git a/runtime/vm/compiler/backend/il_test_helper.cc b/runtime/vm/compiler/backend/il_test_helper.cc
index 3148b0d..316025e 100644
--- a/runtime/vm/compiler/backend/il_test_helper.cc
+++ b/runtime/vm/compiler/backend/il_test_helper.cc
@@ -126,7 +126,7 @@
BlockScheduler::AssignEdgeWeights(flow_graph_);
}
- SpeculativeInliningPolicy speculative_policy(/*enable_blacklist=*/false);
+ SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
pass_state_ = new CompilerPassState(thread, flow_graph_, &speculative_policy);
pass_state_->reorder_blocks = reorder_blocks;
@@ -163,7 +163,7 @@
Zone* zone = thread_->zone();
const bool optimized = true;
- SpeculativeInliningPolicy speculative_policy(/*enable_blacklist=*/false);
+ SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
const bool use_far_branches = false;
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 770eec1..449cfbd 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -3020,14 +3020,19 @@
// then use null as the type arguments.
compiler::Label type_arguments_instantiated;
const intptr_t len = type_arguments().Length();
- if (type_arguments().IsRawWhenInstantiatedFromRaw(len)) {
+ const bool can_function_type_args_be_null =
+ function_type_arguments()->CanBe(Object::null_object());
+ if (type_arguments().IsRawWhenInstantiatedFromRaw(len) &&
+ can_function_type_args_be_null) {
compiler::Label non_null_type_args;
ASSERT(result_reg != instantiator_type_args_reg &&
result_reg != function_type_args_reg);
__ LoadObject(result_reg, Object::null_object());
__ cmpq(instantiator_type_args_reg, result_reg);
- __ j(NOT_EQUAL, &non_null_type_args, compiler::Assembler::kNearJump);
- __ cmpq(function_type_args_reg, result_reg);
+ if (!function_type_arguments()->BindsToConstant()) {
+ __ j(NOT_EQUAL, &non_null_type_args, compiler::Assembler::kNearJump);
+ __ cmpq(function_type_args_reg, result_reg);
+ }
__ j(EQUAL, &type_arguments_instantiated, compiler::Assembler::kNearJump);
__ Bind(&non_null_type_args);
}
diff --git a/runtime/vm/compiler/backend/inliner.h b/runtime/vm/compiler/backend/inliner.h
index c31a954..10a404c 100644
--- a/runtime/vm/compiler/backend/inliner.h
+++ b/runtime/vm/compiler/backend/inliner.h
@@ -31,21 +31,22 @@
class SpeculativeInliningPolicy {
public:
- explicit SpeculativeInliningPolicy(bool enable_blacklist, intptr_t limit = -1)
- : enable_blacklist_(enable_blacklist), remaining_(limit) {}
+ explicit SpeculativeInliningPolicy(bool enable_suppression,
+ intptr_t limit = -1)
+ : enable_suppression_(enable_suppression), remaining_(limit) {}
bool AllowsSpeculativeInlining() const {
- return !enable_blacklist_ || remaining_ > 0;
+ return !enable_suppression_ || remaining_ > 0;
}
bool IsAllowedForInlining(intptr_t call_deopt_id) const {
- // If we are not blacklisting, we always enable optimistic inlining.
- if (!enable_blacklist_) {
+ // If we are not supressing, we always enable optimistic inlining.
+ if (!enable_suppression_) {
return true;
}
- // If we have already blacklisted the deopt-id we don't allow inlining it.
- if (IsBlacklisted(call_deopt_id)) {
+ // If we have already suppressed the deopt-id we don't allow inlining it.
+ if (IsSuppressed(call_deopt_id)) {
return false;
}
@@ -54,37 +55,37 @@
}
bool AddBlockedDeoptId(intptr_t id) {
- ASSERT(enable_blacklist_);
+ ASSERT(enable_suppression_);
#if defined(DEBUG)
- ASSERT(!IsBlacklisted(id));
+ ASSERT(!IsSuppressed(id));
#endif
- // If we exhausted the number of blacklist entries there is no point
- // in adding entries to the blacklist.
+ // If we exhausted the number of suppression entries there is no point
+ // in adding entries to the list.
if (remaining_ <= 0) return false;
- inlining_blacklist_.Add(id);
+ inlining_suppressions_.Add(id);
remaining_ -= 1;
return true;
}
- intptr_t length() const { return inlining_blacklist_.length(); }
+ intptr_t length() const { return inlining_suppressions_.length(); }
private:
- bool IsBlacklisted(intptr_t id) const {
- for (intptr_t i = 0; i < inlining_blacklist_.length(); ++i) {
- if (inlining_blacklist_[i] == id) return true;
+ bool IsSuppressed(intptr_t id) const {
+ for (intptr_t i = 0; i < inlining_suppressions_.length(); ++i) {
+ if (inlining_suppressions_[i] == id) return true;
}
return false;
}
- // Whether we enable blacklisting deopt-ids.
- const bool enable_blacklist_;
+ // Whether we enable supressing inlining at specific deopt-ids.
+ const bool enable_suppression_;
- // After we reach [remaining_] number of deopt-ids in [inlining_blacklist_]
- // in the black list, we'll disable speculative inlining entirely.
+ // After we reach [remaining_] number of deopt-ids in [inlining_suppressions_]
+ // list, we'll disable speculative inlining entirely.
intptr_t remaining_;
- GrowableArray<intptr_t> inlining_blacklist_;
+ GrowableArray<intptr_t> inlining_suppressions_;
};
class FlowGraphInliner : ValueObject {
diff --git a/runtime/vm/compiler/backend/inliner_test.cc b/runtime/vm/compiler/backend/inliner_test.cc
index f7dab8e..87e8029 100644
--- a/runtime/vm/compiler/backend/inliner_test.cc
+++ b/runtime/vm/compiler/backend/inliner_test.cc
@@ -194,4 +194,65 @@
RELEASE_ASSERT(unbox_instr->is_truncating());
}
+#if defined(DART_PRECOMPILER)
+
+// Verifies that all calls are inlined in List.generate call
+// with a simple closure.
+ISOLATE_UNIT_TEST_CASE(Inliner_List_generate) {
+ const char* kScript = R"(
+ foo(n) => List<int>.generate(n, (int x) => x, growable: false);
+ main() {
+ foo(100);
+ }
+ )";
+
+ const auto& root_library = Library::Handle(LoadTestScript(kScript));
+ const auto& function = Function::Handle(GetFunction(root_library, "foo"));
+
+ TestPipeline pipeline(function, CompilerPass::kAOT);
+ FlowGraph* flow_graph = pipeline.RunPasses({});
+
+ auto entry = flow_graph->graph_entry()->normal_entry();
+ ILMatcher cursor(flow_graph, entry);
+
+ RELEASE_ASSERT(cursor.TryMatch({
+ kMoveGlob,
+ kMatchAndMoveCreateArray,
+ kMoveParallelMoves,
+ kMatchAndMoveUnboxInt64,
+ kMatchAndMoveUnboxedConstant,
+ kMatchAndMoveUnboxedConstant,
+ kMoveParallelMoves,
+ kMatchAndMoveGoto,
+
+ // Loop header
+ kMatchAndMoveJoinEntry,
+ kMatchAndMoveCheckStackOverflow,
+ kMatchAndMoveBranchTrue,
+
+ // Loop body
+ kMatchAndMoveTargetEntry,
+ kMatchAndMoveBoxInt64,
+ kMatchAndMoveBoxInt64,
+ kMoveParallelMoves,
+ kMatchAndMoveStoreIndexed,
+ kMoveParallelMoves,
+ kMatchAndMoveBinaryInt64Op,
+ kMoveParallelMoves,
+ kMatchAndMoveGoto,
+
+ // Loop header once again
+ kMatchAndMoveJoinEntry,
+ kMatchAndMoveCheckStackOverflow,
+ kMatchAndMoveBranchFalse,
+
+ // After loop
+ kMatchAndMoveTargetEntry,
+ kMoveParallelMoves,
+ kMatchReturn,
+ }));
+}
+
+#endif // defined(DART_PRECOMPILER)
+
} // namespace dart
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 9bef093..d5e6297 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -237,6 +237,13 @@
// Run constant propagation to make sure we specialize for
// (optional) constant arguments passed into the inlined method.
INVOKE_PASS(ConstantPropagation);
+ // Constant propagation removes unreachable basic blocks and
+ // may open more opportunities for call specialization.
+ // Call specialization during inlining may cause more call
+ // sites to be discovered and more functions inlined.
+ if (mode == kAOT) {
+ INVOKE_PASS(ApplyClassIds);
+ }
// Optimize (a << b) & c patterns, merge instructions. Must occur
// before 'SelectRepresentations' which inserts conversion nodes.
INVOKE_PASS(TryOptimizePatterns);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 589ed9e..b68233d 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -988,7 +988,7 @@
// The RawParameter variables should be set to null to avoid retaining more
// objects than necessary during GC.
const Fragment body =
- ClearRawParameters(dart_function) +
+ ClearRawParameters(dart_function) + B->BuildNullAssertions() +
BuildFunctionBody(dart_function, first_parameter, is_constructor);
auto extra_entry_point_style = ChooseEntryPointStyle(
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 8ce6da1..1676b91 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -16,6 +16,7 @@
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/compiler/frontend/prologue_builder.h"
#include "vm/compiler/jit/compiler.h"
+#include "vm/kernel_isolate.h"
#include "vm/kernel_loader.h"
#include "vm/longjump.h"
#include "vm/native_entry.h"
@@ -2572,6 +2573,7 @@
body += CheckAssignable(setter_value->type(), setter_value->name(),
AssertAssignableInstr::kParameterCheck);
}
+ body += BuildNullAssertions();
if (field.is_late()) {
if (is_method) {
body += Drop();
@@ -3139,6 +3141,83 @@
: try_catch_block->try_index());
}
+bool FlowGraphBuilder::NeedsNullAssertion(const AbstractType& type) {
+ if (!type.IsNonNullable()) {
+ return false;
+ }
+ if (type.IsTypeParameter()) {
+ return NeedsNullAssertion(
+ AbstractType::Handle(Z, TypeParameter::Cast(type).bound()));
+ }
+ if (type.IsFutureOrType()) {
+ return NeedsNullAssertion(AbstractType::Handle(Z, type.UnwrapFutureOr()));
+ }
+ return true;
+}
+
+Fragment FlowGraphBuilder::NullAssertion(LocalVariable* variable) {
+ Fragment code;
+ if (!NeedsNullAssertion(variable->type())) {
+ return code;
+ }
+
+ TargetEntryInstr* then;
+ TargetEntryInstr* otherwise;
+
+ code += LoadLocal(variable);
+ code += NullConstant();
+ code += BranchIfEqual(&then, &otherwise);
+
+ if (throw_new_null_assertion_ == nullptr) {
+ const Class& klass = Class::ZoneHandle(
+ Z, Library::LookupCoreClass(Symbols::AssertionError()));
+ ASSERT(!klass.IsNull());
+ throw_new_null_assertion_ =
+ &Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
+ Symbols::ThrowNewNullAssertion()));
+ ASSERT(!throw_new_null_assertion_->IsNull());
+ }
+
+ const Script& script =
+ Script::Handle(Z, parsed_function_->function().script());
+ intptr_t line = -1;
+ intptr_t column = -1;
+ script.GetTokenLocation(variable->token_pos(), &line, &column);
+
+ // Build equivalent of `throw _AssertionError._throwNewNullAssertion(name)`
+ // expression. We build throw (even through _throwNewNullAssertion already
+ // throws) because call is not a valid last instruction for the block.
+ // Blocks can only terminate with explicit control flow instructions
+ // (Branch, Goto, Return or Throw).
+ Fragment null_code(then);
+ null_code += Constant(variable->name());
+ null_code += IntConstant(line);
+ null_code += IntConstant(column);
+ null_code += StaticCall(variable->token_pos(), *throw_new_null_assertion_, 3,
+ ICData::kStatic);
+ null_code += ThrowException(TokenPosition::kNoSource);
+ null_code += Drop();
+
+ return Fragment(code.entry, otherwise);
+}
+
+Fragment FlowGraphBuilder::BuildNullAssertions() {
+ Fragment code;
+ if (I->null_safety() || !I->asserts() || !FLAG_null_assertions ||
+ !KernelIsolate::GetExperimentalFlag("non-nullable")) {
+ return code;
+ }
+
+ const Function& dart_function = parsed_function_->function();
+ for (intptr_t i = dart_function.NumImplicitParameters(),
+ n = dart_function.NumParameters();
+ i < n; ++i) {
+ LocalVariable* variable = parsed_function_->ParameterVariable(i);
+ code += NullAssertion(variable);
+ }
+ return code;
+}
+
} // namespace kernel
} // namespace dart
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index c5ea5ee..0aff448 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -260,6 +260,16 @@
Fragment* implicit_checks,
Fragment* implicit_redefinitions);
+ // Returns true if null assertion is needed for
+ // a parameter of given type.
+ bool NeedsNullAssertion(const AbstractType& type);
+
+ // Builds null assertion for the given parameter.
+ Fragment NullAssertion(LocalVariable* variable);
+
+ // Builds null assertions for all parameters (if needed).
+ Fragment BuildNullAssertions();
+
// Builds flow graph for noSuchMethod forwarder.
//
// If throw_no_such_method_error is set to true, an
@@ -407,6 +417,9 @@
ActiveClass active_class_;
+ // Cached _AssertionError._throwNewNullAssertion.
+ Function* throw_new_null_assertion_ = nullptr;
+
friend class BreakableBlock;
friend class CatchBlock;
friend class ProgramState;
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 03cccf6..70215e2 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -521,8 +521,8 @@
volatile bool use_far_branches = false;
// In the JIT case we allow speculative inlining and have no need for a
- // blacklist, since we don't restart optimization.
- SpeculativeInliningPolicy speculative_policy(/* enable_blacklist= */ false);
+ // suppression, since we don't restart optimization.
+ SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
Code* volatile result = &Code::ZoneHandle(zone);
while (!done) {
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 74b2a15..f9f9346 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -115,6 +115,8 @@
"Dump megamorphic cache statistics") \
R(dump_symbol_stats, false, bool, false, "Dump symbol table statistics") \
R(enable_asserts, false, bool, false, "Enable assert statements.") \
+ R(null_assertions, false, bool, false, \
+ "Enable null assertions for parameters.") \
P(enable_kernel_expression_compilation, bool, true, \
"Compile expressions with the Kernel front-end.") \
P(enable_mirrors, bool, true, \
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 855ea7e..1eb27bf 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -532,6 +532,11 @@
return;
}
if (BeginOldSpaceGC(thread)) {
+ thread->isolate_group()->ForEachIsolate([&](Isolate* isolate) {
+ // Discard regexp backtracking stacks to further reduce memory usage.
+ isolate->CacheRegexpBacktrackStack(nullptr);
+ });
+
RecordBeforeGC(type, reason);
VMTagScope tagScope(thread, reason == kIdle ? VMTag::kGCIdleTagId
: VMTag::kGCOldSpaceTagId);
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 31cfccb..a1e906e 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -1299,8 +1299,8 @@
} else {
#ifndef PRODUCT
if (!Isolate::IsVMInternalIsolate(I)) {
- // Mark all the user isolates as white-listed for the simplified timeline
- // page of Observatory. The internal isolates will be filtered out from
+ // Mark all the user isolates as using a simplified timeline page of
+ // Observatory. The internal isolates will be filtered out from
// the Timeline due to absence of this argument. We still send them in
// order to maintain the original behavior of the full timeline and allow
// the developer to download complete dump files.
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 7aa57a0..d59d6fb 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -1295,6 +1295,14 @@
void RememberLiveTemporaries();
void DeferredMarkLiveTemporaries();
+ std::unique_ptr<VirtualMemory> TakeRegexpBacktrackStack() {
+ return std::move(regexp_backtracking_stack_cache_);
+ }
+
+ void CacheRegexpBacktrackStack(std::unique_ptr<VirtualMemory> stack) {
+ regexp_backtracking_stack_cache_ = std::move(stack);
+ }
+
private:
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
@@ -1528,6 +1536,8 @@
// This is protected by [isolate_creation_monitor_].
bool accepts_messages_ = false;
+ std::unique_ptr<VirtualMemory> regexp_backtracking_stack_cache_ = nullptr;
+
static Dart_IsolateGroupCreateCallback create_group_callback_;
static Dart_InitializeIsolateCallback initialize_callback_;
static Dart_IsolateShutdownCallback shutdown_callback_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 04f500e..8e58e0f 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -8853,19 +8853,19 @@
StringPtr Function::QualifiedScrubbedName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
- PrintQualifiedName(NameFormattingParams(kScrubbedName), &printer);
+ PrintName(NameFormattingParams(kScrubbedName), &printer);
return Symbols::New(thread, printer.buffer());
}
StringPtr Function::QualifiedUserVisibleName() const {
Thread* thread = Thread::Current();
ZoneTextBuffer printer(thread->zone());
- PrintQualifiedName(NameFormattingParams(kUserVisibleName), &printer);
+ PrintName(NameFormattingParams(kUserVisibleName), &printer);
return Symbols::New(thread, printer.buffer());
}
-void Function::PrintQualifiedName(const NameFormattingParams& params,
- ZoneTextBuffer* printer) const {
+void Function::PrintName(const NameFormattingParams& params,
+ ZoneTextBuffer* printer) const {
// If |this| is the generated asynchronous body closure, use the
// name of the parent function.
Function& fun = Function::Handle(raw());
@@ -8902,9 +8902,11 @@
// the parent.
parent = parent.parent_function();
}
- parent.PrintQualifiedName(params, printer);
- // A function's scrubbed name and its user visible name are identical.
- printer->AddString(".");
+ if (params.include_parent_name) {
+ parent.PrintName(params, printer);
+ // A function's scrubbed name and its user visible name are identical.
+ printer->AddString(".");
+ }
if (params.disambiguate_names &&
fun.name() == Symbols::AnonymousClosure().raw()) {
printer->Printf("<anonymous closure @%" Pd ">", fun.token_pos().Pos());
@@ -16240,9 +16242,8 @@
Object::Handle(zone, WeakSerializationReference::UnwrapIfTarget(owner()));
if (obj.IsClass()) {
// Allocation stub.
- String& cls_name = String::Handle(zone, Class::Cast(obj).ScrubbedName());
- ASSERT(!cls_name.IsNull());
- return OS::SCreate(zone, "[Stub] Allocate %s", cls_name.ToCString());
+ return OS::SCreate(zone, "[Stub] Allocate %s",
+ Class::Cast(obj).ScrubbedNameCString());
} else if (obj.IsAbstractType()) {
// Type test stub.
return OS::SCreate(zone, "[Stub] Type Test %s",
@@ -16267,7 +16268,7 @@
if (obj.IsFunction()) {
ZoneTextBuffer printer(zone);
printer.AddString(is_optimized() ? "[Optimized] " : "[Unoptimized] ");
- Function::Cast(obj).PrintQualifiedName(params, &printer);
+ Function::Cast(obj).PrintName(params, &printer);
return printer.buffer();
}
return Name();
@@ -18737,7 +18738,7 @@
} else if (param.parameterized_function() != Function::null()) {
const Function& func =
Function::Handle(zone, param.parameterized_function());
- func.PrintQualifiedName(
+ func.PrintName(
NameFormattingParams(name_visibility, name_disambiguation),
printer);
printer->AddString("::");
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index bd5baa1..d87f411 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2424,17 +2424,24 @@
kAllFree = kMaxInt32,
};
-// Formatting configuration for Function::PrintQualifiedName.
+// Formatting configuration for Function::PrintName.
struct NameFormattingParams {
Object::NameVisibility name_visibility;
bool disambiguate_names;
// By default function name includes the name of the enclosing class if any.
- // However in some context this information is redundant and class name
+ // However in some contexts this information is redundant and class name
// is already known. In this case setting |include_class_name| to false
// allows you to exclude this information from the formatted name.
bool include_class_name = true;
+ // By default function name includes the name of the enclosing function if
+ // any. However in some contexts this information is redundant and
+ // the name of the enclosing function is already known. In this case
+ // setting |include_parent_name| to false allows to exclude this information
+ // from the formatted name.
+ bool include_parent_name = true;
+
NameFormattingParams(Object::NameVisibility visibility,
Object::NameDisambiguation name_disambiguation =
Object::NameDisambiguation::kNo)
@@ -2448,6 +2455,14 @@
params.include_class_name = false;
return params;
}
+
+ static NameFormattingParams DisambiguatedUnqualified(
+ Object::NameVisibility visibility) {
+ NameFormattingParams params(visibility, Object::NameDisambiguation::kYes);
+ params.include_class_name = false;
+ params.include_parent_name = false;
+ return params;
+ }
};
class Function : public Object {
@@ -2458,8 +2473,8 @@
const char* NameCString(NameVisibility name_visibility) const;
- void PrintQualifiedName(const NameFormattingParams& params,
- ZoneTextBuffer* printer) const;
+ void PrintName(const NameFormattingParams& params,
+ ZoneTextBuffer* printer) const;
StringPtr QualifiedScrubbedName() const;
StringPtr QualifiedUserVisibleName() const;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 1870288..c9875ca 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1350,7 +1350,7 @@
VISIT_FROM(ObjectPtr, library_);
LibraryPtr library_; // library with name dictionary.
ArrayPtr show_names_; // list of names that are exported.
- ArrayPtr hide_names_; // blacklist of names that are not exported.
+ ArrayPtr hide_names_; // list of names that are hidden.
FieldPtr metadata_field_; // remembers the token pos of metadata if any,
// and the metadata values if computed.
VISIT_TO(ObjectPtr, metadata_field_);
diff --git a/runtime/vm/regexp_interpreter.cc b/runtime/vm/regexp_interpreter.cc
index 111c7fe..5706ca9 100644
--- a/runtime/vm/regexp_interpreter.cc
+++ b/runtime/vm/regexp_interpreter.cc
@@ -6,6 +6,9 @@
#include "vm/regexp_interpreter.h"
+#include <memory>
+#include <utility>
+
#include "platform/unicode.h"
#include "vm/object.h"
#include "vm/regexp_assembler.h"
@@ -132,17 +135,36 @@
class BacktrackStack {
public:
explicit BacktrackStack(Zone* zone) {
- data_ = zone->Alloc<intptr_t>(kBacktrackStackSize);
+ memory_ = Isolate::Current()->TakeRegexpBacktrackStack();
+ // Note: using malloc here has a potential of triggering jemalloc/tcmalloc
+ // bugs which cause application to leak memory and eventually OOM.
+ // See https://github.com/dart-lang/sdk/issues/38820 and
+ // https://github.com/flutter/flutter/issues/29007 for examples.
+ // So intead we directly ask OS to provide us memory.
+ if (memory_ == nullptr) {
+ memory_ = std::unique_ptr<VirtualMemory>(VirtualMemory::Allocate(
+ sizeof(intptr_t) * kBacktrackStackSize, /*is_executable=*/false,
+ "regexp-backtrack-stack"));
+ }
+ if (memory_ == nullptr) {
+ OUT_OF_MEMORY();
+ }
}
- intptr_t* data() const { return data_; }
+ ~BacktrackStack() {
+ Isolate::Current()->CacheRegexpBacktrackStack(std::move(memory_));
+ }
+
+ intptr_t* data() const {
+ return reinterpret_cast<intptr_t*>(memory_->address());
+ }
intptr_t max_size() const { return kBacktrackStackSize; }
private:
static const intptr_t kBacktrackStackSize = 1 << 16;
- intptr_t* data_;
+ std::unique_ptr<VirtualMemory> memory_;
DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
};
diff --git a/runtime/vm/regexp_parser.cc b/runtime/vm/regexp_parser.cc
index d7f4235..edad22b 100644
--- a/runtime/vm/regexp_parser.cc
+++ b/runtime/vm/regexp_parser.cc
@@ -1546,7 +1546,7 @@
return true;
}
-// Explicitly whitelist supported binary properties. The spec forbids supporting
+// Explicitly list supported binary properties. The spec forbids supporting
// properties outside of this set to ensure interoperability.
bool IsSupportedBinaryProperty(UProperty property) {
switch (property) {
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index 8cf342c..fd012c6 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -124,7 +124,7 @@
// Variables marked as forced to stack are skipped and not captured by
// CaptureLocalVariables - which iterates scope chain between two scopes
// and indiscriminately marks all variables as captured.
- // TODO(27590) remove the hardcoded blacklist from CaptureLocalVariables
+ // TODO(27590) remove the hardcoded list of names from CaptureLocalVariables
bool is_forced_stack() const { return is_forced_stack_; }
void set_is_forced_stack() { is_forced_stack_ = true; }
@@ -499,9 +499,9 @@
LocalScope* parent_;
LocalScope* child_;
LocalScope* sibling_;
- int function_level_; // Reflects the nesting level of local functions.
- int loop_level_; // Reflects the loop nesting level.
- int context_level_; // Reflects the level of the runtime context.
+ int function_level_; // Reflects the nesting level of local functions.
+ int loop_level_; // Reflects the loop nesting level.
+ int context_level_; // Reflects the level of the runtime context.
TokenPosition begin_token_pos_; // Token index of beginning of scope.
TokenPosition end_token_pos_; // Token index of end of scope.
GrowableArray<LocalVariable*> variables_;
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index fb24834..8598430 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -273,6 +273,7 @@
V(SymbolCtor, "Symbol.") \
V(ThrowNew, "_throwNew") \
V(ThrowNewInvocation, "_throwNewInvocation") \
+ V(ThrowNewNullAssertion, "_throwNewNullAssertion") \
V(TopLevel, "::") \
V(TransferableTypedData, "TransferableTypedData") \
V(TruncDivOperator, "~/") \
diff --git a/runtime/vm/type_testing_stubs.h b/runtime/vm/type_testing_stubs.h
index f4a64ff..b602c6a 100644
--- a/runtime/vm/type_testing_stubs.h
+++ b/runtime/vm/type_testing_stubs.h
@@ -38,7 +38,7 @@
class TypeTestingStubGenerator {
public:
- // During bootstrapping it will return `null` for a whitelisted set of types,
+ // During bootstrapping it will return `null` for |void| and |dynamic| types,
// otherwise it will return a default stub which tail-calls
// subtypingtest/runtime code.
static CodePtr DefaultCodeForType(const AbstractType& type,
diff --git a/samples/ffi/async/sample_async_callback.dart b/samples/ffi/async/sample_async_callback.dart
index f9d8ea4..432a2eb 100644
--- a/samples/ffi/async/sample_async_callback.dart
+++ b/samples/ffi/async/sample_async_callback.dart
@@ -26,7 +26,11 @@
print("C T2 = Some C thread executing C.");
print("C = C T1 or C T2.");
print("Dart: Setup.");
- registerDart_PostCObject(NativeApi.postCObject);
+ Expect.isTrue(NativeApi.majorVersion == 1);
+ Expect.isTrue(NativeApi.minorVersion >= 0);
+ final initializeApi = dl.lookupFunction<IntPtr Function(Pointer<Void>),
+ int Function(Pointer<Void>)>("InitDartApiDL");
+ Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
final interactiveCppRequests = ReceivePort()..listen(requestExecuteCallback);
final int nativePort = interactiveCppRequests.sendPort.nativePort;
@@ -101,14 +105,6 @@
final executeCallback = dl.lookupFunction<Void Function(Pointer<Work>),
void Function(Pointer<Work>)>('ExecuteCallback');
-final registerDart_PostCObject = dl.lookupFunction<
- Void Function(
- Pointer<NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>>
- functionPointer),
- void Function(
- Pointer<NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>>
- functionPointer)>('RegisterDart_PostCObject');
-
class Work extends Struct {}
Future asyncSleep(int ms) {
diff --git a/samples/ffi/async/sample_native_port_call.dart b/samples/ffi/async/sample_native_port_call.dart
index 1e654ef..aa4b48e 100644
--- a/samples/ffi/async/sample_native_port_call.dart
+++ b/samples/ffi/async/sample_native_port_call.dart
@@ -35,9 +35,11 @@
print("C T2 = Some C thread executing C.");
print("C = C T1 or C T2.");
print("Dart: Setup.");
- registerDart_PostCObject(NativeApi.postCObject);
- registerDart_NewNativePort(NativeApi.newNativePort);
- registerDart_CloseNativePort(NativeApi.closeNativePort);
+ Expect.isTrue(NativeApi.majorVersion == 1);
+ Expect.isTrue(NativeApi.minorVersion >= 0);
+ final initializeApi = dl.lookupFunction<IntPtr Function(Pointer<Void>),
+ int Function(Pointer<Void>)>("InitDartApiDL");
+ Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
final interactiveCppRequests = ReceivePort()..listen(handleCppRequests);
final int nativePort = interactiveCppRequests.sendPort.nativePort;
@@ -130,39 +132,6 @@
final stopWorkSimulator2 =
dl.lookupFunction<Void Function(), void Function()>('StopWorkSimulator2');
-final registerDart_PostCObject = dl.lookupFunction<
- Void Function(
- Pointer<NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>>
- functionPointer),
- void Function(
- Pointer<NativeFunction<Int8 Function(Int64, Pointer<Dart_CObject>)>>
- functionPointer)>('RegisterDart_PostCObject');
-
-final registerDart_NewNativePort = dl.lookupFunction<
- Void Function(
- Pointer<
- NativeFunction<
- Int64 Function(
- Pointer<Uint8>,
- Pointer<NativeFunction<Dart_NativeMessageHandler>>,
- Int8)>>
- functionPointer),
- void Function(
- Pointer<
- NativeFunction<
- Int64 Function(
- Pointer<Uint8>,
- Pointer<NativeFunction<Dart_NativeMessageHandler>>,
- Int8)>>
- functionPointer)>('RegisterDart_NewNativePort');
-
-final registerDart_CloseNativePort = dl.lookupFunction<
- Void Function(
- Pointer<NativeFunction<Int8 Function(Int64)>> functionPointer),
- void Function(
- Pointer<NativeFunction<Int8 Function(Int64)>> functionPointer)>(
- 'RegisterDart_CloseNativePort');
-
Future asyncSleep(int ms) {
return new Future.delayed(Duration(milliseconds: ms), () => true);
}
diff --git a/samples/ffi/sample_ffi_functions_callbacks_closures.dart b/samples/ffi/sample_ffi_functions_callbacks_closures.dart
new file mode 100644
index 0000000..ba876da
--- /dev/null
+++ b/samples/ffi/sample_ffi_functions_callbacks_closures.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+import 'dylib_utils.dart';
+
+void main() {
+ print('start main');
+
+ doDynamicLinking();
+
+ int counter = 0;
+ void closure() {
+ counter++;
+ }
+
+ // C holds on to this closure through a `Dart_PersistenHandle`.
+ registerClosureCallback(closure);
+
+ // Some time later this closure can be invoked.
+ invokeClosureCallback();
+ Expect.equals(1, counter);
+
+ // When C is done it needs to stop holding on to the closure such that the
+ // Dart GC can collect the closure.
+ releaseClosureCallback();
+
+ print('end main');
+}
+
+final testLibrary = dlopenPlatformSpecific("ffi_test_functions");
+
+final registerClosureCallback =
+ testLibrary.lookupFunction<Void Function(Handle), void Function(Object)>(
+ "RegisterClosureCallback");
+
+final invokeClosureCallback = testLibrary
+ .lookupFunction<Void Function(), void Function()>("InvokeClosureCallback");
+
+final releaseClosureCallback = testLibrary
+ .lookupFunction<Void Function(), void Function()>("ReleaseClosureCallback");
+
+void doClosureCallback(Object callback) {
+ final callback_as_function = callback as void Function();
+ callback_as_function();
+}
+
+final closureCallbackPointer =
+ Pointer.fromFunction<Void Function(Handle)>(doClosureCallback);
+
+void doDynamicLinking() {
+ Expect.isTrue(NativeApi.majorVersion == 1);
+ Expect.isTrue(NativeApi.minorVersion >= 0);
+ final initializeApi = testLibrary.lookupFunction<
+ IntPtr Function(Pointer<Void>),
+ int Function(Pointer<Void>)>("InitDartApiDL");
+ Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
+
+ final registerClosureCallback = testLibrary.lookupFunction<
+ Void Function(Pointer),
+ void Function(Pointer)>("RegisterClosureCallbackFP");
+ registerClosureCallback(closureCallbackPointer);
+}
diff --git a/samples/ffi/samples_test.dart b/samples/ffi/samples_test.dart
index 9814463..954aa9c 100644
--- a/samples/ffi/samples_test.dart
+++ b/samples/ffi/samples_test.dart
@@ -6,20 +6,23 @@
//
// SharedObjects=ffi_test_dynamic_library ffi_test_functions
-import 'sample_ffi_bitfield.dart' as sample0;
-import 'sample_ffi_data.dart' as sample1;
-import 'sample_ffi_dynamic_library.dart' as sample2;
-import 'sample_ffi_functions_callbacks.dart' as sample3;
-import 'sample_ffi_functions_structs.dart' as sample4;
-import 'sample_ffi_functions.dart' as sample5;
-import 'sample_ffi_structs.dart' as sample6;
+import 'sample_ffi_bitfield.dart' as bitfield;
+import 'sample_ffi_data.dart' as data;
+import 'sample_ffi_dynamic_library.dart' as dynamic_library;
+import 'sample_ffi_functions_callbacks_closures.dart'
+ as functions_callbacks_closures;
+import 'sample_ffi_functions_callbacks.dart' as functions_callbacks;
+import 'sample_ffi_functions_structs.dart' as functions_structs;
+import 'sample_ffi_functions.dart' as functions;
+import 'sample_ffi_structs.dart' as structs;
main() {
- sample0.main();
- sample1.main();
- sample2.main();
- sample3.main();
- sample4.main();
- sample5.main();
- sample6.main();
+ bitfield.main();
+ data.main();
+ dynamic_library.main();
+ functions_callbacks_closures.main();
+ functions_callbacks.main();
+ functions_structs.main();
+ functions.main();
+ structs.main();
}
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 5354079..bd50f42 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -14,6 +14,7 @@
# fail.
import("../build/dart/copy_tree.gni")
+import("../build/executable_suffix.gni")
import("../runtime/runtime_args.gni")
import("../sdk_args.gni")
@@ -21,13 +22,10 @@
# Build a SDK with less stuff. It excludes dart2js, ddc, and web libraries.
dart_platform_sdk = true
- # Whether to include dart2native in the "create_sdk" target.
- include_dart2native = false
-
# Path to stripped dart binaries relative to build output directory.
dart_stripped_binary = "dart"
- dart_precompiled_runtime_stripped_binary = "dart_precompiled_runtime"
- gen_snapshot_stripped_binary = "gen_snapshot"
+ dart_precompiled_runtime_stripped_binary = "dart_precompiled_runtime_product"
+ gen_snapshot_stripped_binary = "gen_snapshot_product"
}
# The directory layout of the SDK is as follows:
@@ -39,11 +37,11 @@
# ......dartaotruntime or dartaotruntime.exe (executable)
# ......dartdoc
# ......dartfmt
-# ......dart2native (if `include_dart2native` and not on ia32)
+# ......dart2native (if not on ia32)
# ......dart2js
# ......dartanalyzer
# ......dartdevc
-# ......utils/gen_snapshot or utils/gen_snapshot.exe (if `include_dart2native` and not on ia32)
+# ......utils/gen_snapshot or utils/gen_snapshot.exe (if not on ia32)
# ......pub
# ......snapshots/
# ........analysis_server.dart.snapshot
@@ -53,8 +51,8 @@
# ........dartdoc.dart.snapshot
# ........dartfmt.dart.snapshot
# ........dartdevc.dart.snapshot
-# ........gen_kernel.dart.snapshot (if `include_dart2native` and not on ia32)
-# ........dart2native.dart.snapshot (if `include_dart2native` and not on ia32)
+# ........gen_kernel.dart.snapshot (if not on ia32)
+# ........dart2native.dart.snapshot (if not on ia32)
# ........kernel_worker.dart.snapshot
# ........pub.dart.snapshot
# ........frontend_server.dart.snapshot
@@ -140,7 +138,7 @@
"../utils/pub",
],
]
-if (include_dart2native && dart_target_arch != "ia32") {
+if (dart_target_arch != "ia32") {
_platform_sdk_snapshots += [ [
"dart2native",
"../utils/dart2native:generate_dart2native_snapshot",
@@ -197,7 +195,7 @@
"../utils/kernel-service:frontend_server",
],
]
-if (include_dart2native && dart_target_arch != "ia32") {
+if (dart_target_arch != "ia32") {
_full_sdk_snapshots += [ [
"dart2native",
"../utils/dart2native:generate_dart2native_snapshot",
@@ -334,7 +332,7 @@
ignore_patterns = "{}"
},
]
- if (is_linux || is_android) {
+ if (is_linux || is_android || is_fuchsia) {
copy_tree_specs += [
{
target = "copy_libtensorflowlite_c"
@@ -411,12 +409,8 @@
visibility = [ ":create_common_sdk" ]
deps = [ "../runtime/bin:dart" ]
dart_out = get_label_info("../runtime/bin:dart", "root_out_dir")
- if (is_win) {
- sources = [ "$dart_out/dart.exe" ]
- } else {
- sources = [ "$dart_out/$dart_stripped_binary" ]
- }
- if (is_win) {
+ sources = [ "$dart_out/${dart_stripped_binary}${executable_suffix}" ]
+ if (is_win && dart_lib_export_symbols) {
sources += [ "$dart_out/dart.lib" ]
}
outputs = [ "$root_out_dir/dart-sdk/bin/{{source_file_part}}" ]
@@ -424,29 +418,32 @@
}
copy("copy_dartaotruntime") {
- deps = [ "../runtime/bin:dart_precompiled_runtime" ]
- dartaotruntime_out =
- get_label_info("../runtime/bin:dart_precompiled_runtime", "root_out_dir")
- if (is_win) {
- sources = [ "$dartaotruntime_out/dart_precompiled_runtime.exe" ]
- outputs = [ "$root_out_dir/dart-sdk/bin/dartaotruntime.exe" ]
- } else {
- sources =
- [ "$dartaotruntime_out/$dart_precompiled_runtime_stripped_binary" ]
- outputs = [ "$root_out_dir/dart-sdk/bin/dartaotruntime" ]
- }
+ visibility = [ ":copy_dart2native" ]
+ deps = [ "../runtime/bin:dart_precompiled_runtime_product" ]
+ src_dir = get_label_info("../runtime/bin:dart_precompiled_runtime_product",
+ "root_out_dir")
+ sources = [
+ "$src_dir/${dart_precompiled_runtime_stripped_binary}${executable_suffix}",
+ ]
+ outputs = [ "$root_out_dir/dart-sdk/bin/dartaotruntime${executable_suffix}" ]
}
copy("copy_gen_snapshot") {
- deps = [ "../runtime/bin:gen_snapshot" ]
- gen_snapshot_out =
- get_label_info("../runtime/bin:gen_snapshot", "root_out_dir")
- if (is_win) {
- sources = [ "$gen_snapshot_out/gen_snapshot.exe" ]
- } else {
- sources = [ "$gen_snapshot_out/$gen_snapshot_stripped_binary" ]
- }
- outputs = [ "$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}" ]
+ visibility = [ ":copy_dart2native" ]
+ deps = [ "../runtime/bin:gen_snapshot_product" ]
+ src_dir =
+ get_label_info("../runtime/bin:gen_snapshot_product", "root_out_dir")
+ sources = [ "$src_dir/${gen_snapshot_stripped_binary}${executable_suffix}" ]
+ outputs =
+ [ "$root_out_dir/dart-sdk/bin/utils/gen_snapshot${executable_suffix}" ]
+}
+
+copy("copy_vm_platform_strong_product") {
+ visibility = [ ":copy_dart2native" ]
+ deps = [ "../runtime/vm:vm_platform_product" ]
+ src_dir = get_label_info("../runtime/vm:vm_platform_product", "root_out_dir")
+ sources = [ "$src_dir/vm_platform_strong_product.dill" ]
+ outputs = [ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}" ]
}
copy("copy_dart2native") {
@@ -454,6 +451,7 @@
":copy_dartaotruntime",
":copy_gen_kernel_snapshot",
":copy_gen_snapshot",
+ ":copy_vm_platform_strong_product",
]
ext = ""
if (is_win) {
@@ -464,6 +462,7 @@
}
copy("copy_gen_kernel_snapshot") {
+ visibility = [ ":copy_dart2native" ]
deps = [ "../utils/gen_kernel" ]
sources = [ "$root_gen_dir/gen_kernel.dart.snapshot" ]
outputs = [ "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}" ]
@@ -743,8 +742,11 @@
visibility = [ ":create_common_sdk" ]
sources = [
"../runtime/include/dart_api.h",
+ "../runtime/include/dart_api_dl.h",
"../runtime/include/dart_native_api.h",
"../runtime/include/dart_tools_api.h",
+ "../runtime/include/dart_version.h",
+ "../runtime/include/internal/dart_api_dl_impl.h",
]
outputs = [ "$root_out_dir/dart-sdk/include/{{source_file_part}}" ]
}
@@ -890,7 +892,7 @@
# We do not support AOT on ia32 and should therefore not add the
# dart2native script (since there is no AOT compiler/runtime available)
- if (include_dart2native && dart_target_arch != "ia32") {
+ if (dart_target_arch != "ia32") {
public_deps += [ ":copy_dart2native" ]
}
diff --git a/sdk/lib/_internal/allowed_experiments.json b/sdk/lib/_internal/allowed_experiments.json
index 01da114..a1ff760 100644
--- a/sdk/lib/_internal/allowed_experiments.json
+++ b/sdk/lib/_internal/allowed_experiments.json
@@ -1,7 +1,9 @@
{
"version": 1,
"experimentSets": {
- "nullSafety": ["non-nullable"]
+ "nullSafety": [
+ "non-nullable"
+ ]
},
"sdk": {
"default": {
@@ -13,9 +15,90 @@
}
}
},
- "_example_packages": {
+ "packages": {
+ "async": {
+ "experimentSet": "nullSafety"
+ },
+ "boolean_selector": {
+ "experimentSet": "nullSafety"
+ },
+ "characters": {
+ "experimentSet": "nullSafety"
+ },
+ "charcode": {
+ "experimentSet": "nullSafety"
+ },
+ "clock": {
+ "experimentSet": "nullSafety"
+ },
"collection": {
"experimentSet": "nullSafety"
+ },
+ "fake_async": {
+ "experimentSet": "nullSafety"
+ },
+ "fixnum": {
+ "experimentSet": "nullSafety"
+ },
+ "flutter": {
+ "experimentSet": "nullSafety"
+ },
+ "js": {
+ "experimentSet": "nullSafety"
+ },
+ "matcher": {
+ "experimentSet": "nullSafety"
+ },
+ "meta": {
+ "experimentSet": "nullSafety"
+ },
+ "path": {
+ "experimentSet": "nullSafety"
+ },
+ "pedantic": {
+ "experimentSet": "nullSafety"
+ },
+ "pool": {
+ "experimentSet": "nullSafety"
+ },
+ "sky_engine": {
+ "experimentSet": "nullSafety"
+ },
+ "source_maps": {
+ "experimentSet": "nullSafety"
+ },
+ "source_map_stack_trace": {
+ "experimentSet": "nullSafety"
+ },
+ "source_span": {
+ "experimentSet": "nullSafety"
+ },
+ "stack_trace": {
+ "experimentSet": "nullSafety"
+ },
+ "stream_channel": {
+ "experimentSet": "nullSafety"
+ },
+ "string_scanner": {
+ "experimentSet": "nullSafety"
+ },
+ "term_glyph": {
+ "experimentSet": "nullSafety"
+ },
+ "test": {
+ "experimentSet": "nullSafety"
+ },
+ "test_api": {
+ "experimentSet": "nullSafety"
+ },
+ "test_core": {
+ "experimentSet": "nullSafety"
+ },
+ "typed_data": {
+ "experimentSet": "nullSafety"
+ },
+ "vector_math": {
+ "experimentSet": "nullSafety"
}
}
}
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 6ffa92e..3d4b5e3 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -25,11 +25,10 @@
RuntimeError;
import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
-
import 'dart:_native_typed_data' show NativeUint8List;
+import 'dart:_rti' show getRuntimeType;
import "dart:convert" show Encoding, utf8;
-
import 'dart:typed_data' show Endian, Uint8List, Uint16List;
String _symbolToString(Symbol symbol) =>
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index fc97282..189bb8c 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
@@ -24,7 +24,6 @@
defineProperty,
diagnoseIndexError,
getIsolateAffinityTag,
- getRuntimeType,
initNativeDispatch,
initNativeDispatchFlag,
regExpGetNative,
@@ -52,6 +51,9 @@
JS_EMBEDDED_GLOBAL,
JS_INTERCEPTOR_CONSTANT,
JS_STRING_CONCAT;
+
+import 'dart:_rti' show getRuntimeType;
+
import 'dart:math' show Random, ln2;
part 'js_array.dart';
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index db4ef1be..bf335946 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -76,7 +76,6 @@
part 'native_helper.dart';
part 'regexp_helper.dart';
part 'string_helper.dart';
-part 'js_rti.dart';
part 'linked_hash_map.dart';
/// Marks the internal map in dart2js, so that internal libraries can is-check
@@ -91,34 +90,6 @@
JsBuiltin.isCheckPropertyToJsConstructorName, isCheckProperty);
}
-/// Returns true if the given [type] is a function type object.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isDartFunctionType(Object type) {
- // Function type test is using the `in` operator which doesn't work on
- // primitive types.
- assert(!(type == null || type is num || type is String));
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none', JsBuiltin.isFunctionType, type);
-}
-
-/// Returns true if the given [type] is a FutureOr type object.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isDartFutureOrType(Object type) {
- // FutureOr test is using the `in` operator which doesn't work on primitive
- // types.
- assert(!(type == null || type is num || type is String));
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none', JsBuiltin.isFutureOrType, type);
-}
-
-@pragma('dart2js:tryInline')
-bool isDartVoidTypeRti(Object type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none', JsBuiltin.isVoidType, type);
-}
-
/// Retrieves the class name from type information stored on the constructor of
/// [type].
// TODO(floitsch): move this to foreign_helper.dart or similar.
@@ -155,73 +126,6 @@
return JS_BUILTIN('', JsBuiltin.rawRuntimeType, o);
}
-/// Returns whether the given [type] is a subtype of [other].
-///
-/// The argument [other] is the name of the other type, as computed by
-/// [runtimeTypeToString].
-@pragma('dart2js:tryInline')
-bool builtinIsSubtype(type, String other) {
- return JS_BUILTIN('returns:bool;effects:none;depends:none',
- JsBuiltin.isSubtype, other, type);
-}
-
-/// Returns true if the given [type] is _the_ `Function` type.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isDartFunctionTypeRti(Object type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none',
- JsBuiltin.isGivenTypeRti,
- type,
- JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME));
-}
-
-/// Returns true if the given [type] is _the_ `Null` type.
-@pragma('dart2js:tryInline')
-bool isNullType(Object type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none',
- JsBuiltin.isGivenTypeRti,
- type,
- JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
-}
-
-/// Returns whether the given type is the dynamic type.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isDartDynamicTypeRti(type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none', JsBuiltin.isDynamicType, type);
-}
-
-@pragma('dart2js:tryInline')
-bool isDartJsInteropTypeArgumentRti(type) {
- return JS_BUILTIN('returns:bool;effects:none;depends:none',
- JsBuiltin.isJsInteropTypeArgument, type);
-}
-
-/// Returns whether the given type is _the_ Dart Object type.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isDartObjectTypeRti(type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none',
- JsBuiltin.isGivenTypeRti,
- type,
- JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME));
-}
-
-/// Returns whether the given type is _the_ null type.
-// TODO(floitsch): move this to foreign_helper.dart or similar.
-@pragma('dart2js:tryInline')
-bool isNullTypeRti(type) {
- return JS_BUILTIN(
- 'returns:bool;effects:none;depends:none',
- JsBuiltin.isGivenTypeRti,
- type,
- JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME));
-}
-
/// Returns the metadata of the given [index].
// TODO(floitsch): move this to foreign_helper.dart or similar.
@pragma('dart2js:tryInline')
@@ -2011,6 +1915,16 @@
return result;
}
+/// Returns the property [index] of the JavaScript array [array].
+getIndex(var array, int index) {
+ return JS('var', r'#[#]', array, index);
+}
+
+/// Returns the length of the JavaScript array [array].
+int getLength(var array) {
+ return JS('int', r'#.length', array);
+}
+
invokeClosure(Function closure, int numberOfArguments, var arg1, var arg2,
var arg3, var arg4) {
switch (numberOfArguments) {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
deleted file mode 100644
index 9b850c9..0000000
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ /dev/null
@@ -1,554 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// This part contains helpers for supporting runtime type information.
-///
-/// The helper use a mixture of Dart and JavaScript objects. To indicate which
-/// is used where we adopt the scheme of using explicit type annotation for Dart
-/// objects and 'var' or omitted return type for JavaScript objects.
-///
-/// Since bool, int, and String values are represented by the same JavaScript
-/// primitives, type annotations are used for these types in all cases.
-///
-/// Several methods use a common JavaScript encoding of runtime type
-/// information. This encoding is referred to as the type representation which
-/// is one of these:
-/// 1) a JavaScript constructor for a class C: the represented type is the raw
-/// type C.
-/// 2) a JavaScript array: the first entry is of type 1 and contains the
-/// subtyping flags and the substitution of the type and the rest of the
-/// array are the type arguments.
-/// 3) `null`: the dynamic type.
-/// 4) a JavaScript object representing the function type. For instance, it has
-/// the form {ret: rti, args: [rti], opt: [rti], named: {name: rti}} for a
-/// function with a return type, regular, optional and named arguments.
-/// Generic function types have a 'bounds' property.
-///
-/// To check subtype relations between generic classes we use a JavaScript
-/// expression that describes the necessary substitution for type arguments.
-/// Such a substitution expression can be:
-/// 1) `null`, if no substituted check is necessary, because the
-/// type variables are the same or there are no type variables in the class
-/// that is checked for.
-/// 2) A list expression describing the type arguments to be used in the
-/// subtype check, if the type arguments to be used in the check do not
-/// depend on the type arguments of the object.
-/// 3) A function mapping the type variables of the object to be checked to a
-/// list expression. The function may also return null, which is equivalent
-/// to an array containing only null values.
-
-part of _js_helper;
-
-/// Represents a type variable.
-///
-/// This class holds the information needed when reflecting on generic classes
-/// and their members.
-class TypeVariable {
- final Type owner;
- final String name;
- final int bound;
-
- const TypeVariable(this.owner, this.name, this.bound);
-}
-
-/// Sets the runtime type information on [target]. [rti] is a type
-/// representation of type 4 or 5, that is, either a JavaScript array or `null`.
-///
-/// Called from generated code.
-///
-/// This is used only for marking JavaScript Arrays (JSArray) with the element
-/// type.
-// Don't inline. Let the JS engine inline this. The call expression is much
-// more compact that the inlined expansion.
-@pragma('dart2js:noInline')
-Object setRuntimeTypeInfo(Object target, var rti) {
- assert(rti != null);
- var rtiProperty = JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY);
- JS('var', r'#[#] = #', target, rtiProperty, rti);
- return target;
-}
-
-/// Returns the runtime type information of [target]. The returned value is a
-/// list of type representations for the type arguments.
-///
-/// Called from generated code.
-getRuntimeTypeInfo(Object target) {
- if (target == null) return null;
- String rtiName = JS_GET_NAME(JsGetName.RTI_NAME);
- return JS('var', r'#[#]', target, rtiName);
-}
-
-/// Returns the type arguments of [object] as an instance of [substitutionName].
-getRuntimeTypeArguments(interceptor, object, substitutionName) {
- var substitution = getField(interceptor,
- '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}$substitutionName');
- return substitute(substitution, getRuntimeTypeInfo(object));
-}
-
-/// Retrieves the class name from type information stored on the constructor
-/// of [object].
-String getClassName(var object) {
- return rawRtiToJsConstructorName(getRawRuntimeType(getInterceptor(object)));
-}
-
-Type getRuntimeType(var object) {
- return newRti.getRuntimeType(object);
-}
-
-/// Applies the [substitution] on the [arguments].
-///
-/// See the comment in the beginning of this file for a description of the
-/// possible values for [substitution].
-substitute(var substitution, var arguments) {
- if (substitution == null) return arguments;
- assert(isJsFunction(substitution));
- assert(arguments == null || isJsArray(arguments));
- substitution = invoke(substitution, arguments);
- if (substitution == null) return null;
- if (isJsArray(substitution)) {
- // Substitutions are generated too late to mark Array as used, so use a
- // tautological JS 'cast' to mark Array as used. This is needed only in
- // some tiny tests where the substition is the only thing that creates an
- // Array.
- return JS('JSArray', '#', substitution);
- }
- if (isJsFunction(substitution)) {
- // TODO(johnniwinther): Check if this is still needed.
- return invoke(substitution, arguments);
- }
- return arguments;
-}
-
-bool checkArguments(
- var substitution, var arguments, var sEnv, var checks, var tEnv) {
- return areSubtypes(substitute(substitution, arguments), sEnv, checks, tEnv);
-}
-
-/// Checks whether the types of [s] are all subtypes of the types of [t].
-///
-/// [s] and [t] are either `null` or JavaScript arrays of type representations,
-/// A `null` argument is interpreted as the arguments of a raw type, that is a
-/// list of `dynamic`. If [s] and [t] are JavaScript arrays they must be of the
-/// same length.
-///
-/// See the comment in the beginning of this file for a description of type
-/// representations.
-
-bool areSubtypes(var s, var sEnv, var t, var tEnv) {
- // `null` means a raw type.
- if (t == null) return true;
- if (s == null) {
- int len = getLength(t);
- for (int i = 0; i < len; i++) {
- if (!_isSubtype(null, null, getIndex(t, i), tEnv)) {
- return false;
- }
- }
- return true;
- }
-
- assert(isJsArray(s));
- assert(isJsArray(t));
- assert(getLength(s) == getLength(t));
-
- int len = getLength(s);
- for (int i = 0; i < len; i++) {
- if (!_isSubtype(getIndex(s, i), sEnv, getIndex(t, i), tEnv)) {
- return false;
- }
- }
- return true;
-}
-
-/// Computes the signature by applying the type arguments of [context] as an
-/// instance of [contextName] to the signature function [signature].
-computeSignature(var signature, var context, var contextName) {
- var interceptor = getInterceptor(context);
- var typeArguments =
- getRuntimeTypeArguments(interceptor, context, contextName);
- return invokeOn(signature, context, typeArguments);
-}
-
-/// Returns `true` if the runtime type representation [type] is a top type.
-/// That is, either `dynamic`, `void` or `Object`.
-@pragma('dart2js:tryInline')
-bool isTopType(var type) {
- return isDartDynamicTypeRti(type) ||
- isDartVoidTypeRti(type) ||
- isDartObjectTypeRti(type) ||
- isDartJsInteropTypeArgumentRti(type);
-}
-
-/// Returns the type argument of the `FutureOr` runtime type representation
-/// [type].
-///
-/// For instance `num` of `FutureOr<num>`.
-@pragma('dart2js:tryInline')
-Object getFutureOrArgument(var type) {
- assert(isDartFutureOrType(type));
- var typeArgumentTag = JS_GET_NAME(JsGetName.FUTURE_OR_TYPE_ARGUMENT_TAG);
- return hasField(type, typeArgumentTag)
- ? getField(type, typeArgumentTag)
- : null;
-}
-
-/// Checks whether the type represented by the type representation [s] is a
-/// subtype of the type represented by the type representation [t].
-///
-/// See the comment in the beginning of this file for a description of type
-/// representations.
-///
-/// The arguments [s] and [t] must be types, usually represented by the
-/// constructor of the class, or an array (for generic class types).
-bool isSubtype(var s, var t) {
- return _isSubtype(s, null, t, null);
-}
-
-bool _isSubtype(var s, var sEnv, var t, var tEnv) {
- return false;
-}
-
-/// Top-level function subtype check when [t] is known to be a function type
-/// rti.
-bool isFunctionSubtype(var s, var t) {
- return _isFunctionSubtype(s, null, t, null);
-}
-
-bool _isFunctionSubtype(var s, var sEnv, var t, var tEnv) {
- assert(isDartFunctionType(t));
- if (!isDartFunctionType(s)) return false;
- var genericBoundsTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
- var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
- var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
-
- // Generic function types must agree on number of type parameters and bounds.
- if (hasField(s, genericBoundsTag)) {
- if (hasNoField(t, genericBoundsTag)) return false;
- var sBounds = getField(s, genericBoundsTag);
- var tBounds = getField(t, genericBoundsTag);
- int sGenericParameters = getLength(sBounds);
- int tGenericParameters = getLength(tBounds);
- if (sGenericParameters != tGenericParameters) return false;
- // TODO(sra): Compare bounds, which should be 'equal' trees due to the de
- // Bruijn numbering of type parameters.
- sEnv = sEnv == null ? sBounds : concat(sBounds, sEnv);
- tEnv = tEnv == null ? tBounds : concat(tBounds, tEnv);
- } else if (hasField(t, genericBoundsTag)) {
- return false;
- }
-
- var sReturnType = getField(s, returnTypeTag);
- var tReturnType = getField(t, returnTypeTag);
- if (!_isSubtype(sReturnType, sEnv, tReturnType, tEnv)) return false;
-
- var requiredParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
- var sParameterTypes = getField(s, requiredParametersTag);
- var tParameterTypes = getField(t, requiredParametersTag);
-
- var optionalParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
- var sOptionalParameterTypes = getField(s, optionalParametersTag);
- var tOptionalParameterTypes = getField(t, optionalParametersTag);
-
- int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0;
- int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0;
-
- int sOptionalParametersLen =
- sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0;
- int tOptionalParametersLen =
- tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0;
-
- if (sParametersLen > tParametersLen) {
- // Too many required parameters in [s].
- return false;
- }
- if (sParametersLen + sOptionalParametersLen <
- tParametersLen + tOptionalParametersLen) {
- // Too few required and optional parameters in [s].
- return false;
- }
-
- int pos = 0;
- // Check all required parameters of [s].
- for (; pos < sParametersLen; pos++) {
- if (!_isSubtype(getIndex(tParameterTypes, pos), tEnv,
- getIndex(sParameterTypes, pos), sEnv)) {
- return false;
- }
- }
- int sPos = 0;
- int tPos = pos;
- // Check the remaining parameters of [t] with the first optional parameters
- // of [s].
- for (; tPos < tParametersLen; sPos++, tPos++) {
- if (!_isSubtype(getIndex(tParameterTypes, tPos), tEnv,
- getIndex(sOptionalParameterTypes, sPos), sEnv)) {
- return false;
- }
- }
- tPos = 0;
- // Check the optional parameters of [t] with the remaining optional
- // parameters of [s]:
- for (; tPos < tOptionalParametersLen; sPos++, tPos++) {
- if (!_isSubtype(getIndex(tOptionalParameterTypes, tPos), tEnv,
- getIndex(sOptionalParameterTypes, sPos), sEnv)) {
- return false;
- }
- }
-
- var namedParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
- var sNamedParameters = getField(s, namedParametersTag);
- var tNamedParameters = getField(t, namedParametersTag);
- if (tNamedParameters == null) return true;
- if (sNamedParameters == null) return false;
- return namedParametersSubtypeCheck(
- sNamedParameters, sEnv, tNamedParameters, tEnv);
-}
-
-bool namedParametersSubtypeCheck(var s, var sEnv, var t, var tEnv) {
- assert(isJsObject(s));
- assert(isJsObject(t));
-
- // Each named parameter in [t] must exist in [s] and be a subtype of the type
- // in [s].
- List names = JS('JSFixedArray', 'Object.getOwnPropertyNames(#)', t);
- for (int i = 0; i < names.length; i++) {
- var name = names[i];
- if (JS('bool', '!Object.hasOwnProperty.call(#, #)', s, name)) {
- return false;
- }
- var tType = JS('', '#[#]', t, name);
- var sType = JS('', '#[#]', s, name);
- if (!_isSubtype(tType, tEnv, sType, sEnv)) return false;
- }
- return true;
-}
-
-/// Returns whether [type] is the representation of a generic function type
-/// parameter. Generic function type parameters are represented de Bruijn
-/// indexes.
-///
-/// This test is only valid if [type] is known _not_ to be the void rti, whose
-/// runtime representation is -1.
-bool isGenericFunctionTypeParameter(var type) {
- assert(!isDartVoidTypeRti(type));
- return type is num; // Actually int, but 'is num' is faster.
-}
-
-/// Returns [genericFunctionRti] with type parameters bound to [parameters].
-///
-/// [genericFunctionRti] must be an rti representation with a number of generic
-/// type parameters matching the number of types in [parameters].
-///
-/// Called from generated code.
-@pragma('dart2js:noInline')
-instantiatedGenericFunctionType(genericFunctionRti, parameters) {
- if (genericFunctionRti == null) return null;
-
- assert(isDartFunctionType(genericFunctionRti));
-
- var genericBoundsTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
-
- assert(hasField(genericFunctionRti, genericBoundsTag));
- var bounds = getField(genericFunctionRti, genericBoundsTag);
-
- // Generic function types must agree on number of type parameters and bounds.
- int boundLength = getLength(bounds);
- int parametersLength = getLength(parameters);
- assert(boundLength == parametersLength);
-
- var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
- return finishBindInstantiatedFunctionType(
- genericFunctionRti, result, parameters, 0);
-}
-
-bindInstantiatedFunctionType(rti, parameters, int depth) {
- var result = JS('', '{#:1}', JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG));
-
- var genericBoundsTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_GENERIC_BOUNDS_TAG);
- if (hasField(rti, genericBoundsTag)) {
- var bounds = getField(rti, genericBoundsTag);
- depth += getLength(bounds);
- setField(result, genericBoundsTag,
- bindInstantiatedTypes(bounds, parameters, depth));
- }
-
- return finishBindInstantiatedFunctionType(rti, result, parameters, depth);
-}
-
-/// Common code for function types that copies all non-bounds parts of the
-/// function [rti] into [result].
-finishBindInstantiatedFunctionType(rti, result, parameters, int depth) {
- var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
- var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
-
- if (hasField(rti, voidReturnTag)) {
- setField(result, voidReturnTag, getField(rti, voidReturnTag));
- } else if (hasField(rti, returnTypeTag)) {
- setField(result, returnTypeTag,
- bindInstantiatedType(getField(rti, returnTypeTag), parameters, depth));
- }
-
- var requiredParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG);
- if (hasField(rti, requiredParametersTag)) {
- setField(
- result,
- requiredParametersTag,
- bindInstantiatedTypes(
- getField(rti, requiredParametersTag), parameters, depth));
- }
-
- String optionalParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG);
- if (hasField(rti, optionalParametersTag)) {
- setField(
- result,
- optionalParametersTag,
- bindInstantiatedTypes(
- getField(rti, optionalParametersTag), parameters, depth));
- }
-
- String namedParametersTag =
- JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG);
- if (hasField(rti, namedParametersTag)) {
- var namedParameters = getField(rti, namedParametersTag);
- var boundNamed = JS('', '{}');
- var names = JS('JSFixedArray', 'Object.keys(#)', namedParameters);
- for (var name in names) {
- setField(
- boundNamed,
- name,
- bindInstantiatedType(
- getField(namedParameters, name), parameters, depth));
- }
- setField(result, namedParametersTag, boundNamed);
- }
-
- return result;
-}
-
-/// Copies [rti], substituting generic type parameters from [parameters].
-///
-/// Generic type parameters are de Bruijn indexes counting up through the
-/// generic function type parameters scopes to index into [parameters].
-///
-/// [depth] is the number of subsequent generic function parameters that are in
-/// scope. This is subtracted off the de Bruijn index for the type parameter to
-/// arrive at an potential index into [parameters].
-bindInstantiatedType(rti, parameters, int depth) {
- if (isDartDynamicTypeRti(rti)) return rti; // dynamic.
- if (isDartVoidTypeRti(rti)) return rti; // void.
- // Functions are constructors denoting the class of the constructor.
- if (isJsFunction(rti)) return rti;
-
- // de Bruijn type indexes.
- if (isGenericFunctionTypeParameter(rti)) {
- if (rti < depth) return rti;
- return JS('', '#[#]', parameters, rti - depth);
- }
- // Other things encoded as numbers.
- if (rti is num) return rti;
-
- if (isJsArray(rti)) {
- // An array is a parameterized class type, e.g. the list of three
- // constructor functions [Map, String, int] represents `Map<String, int>`.
- // Since the 'head' of the term and the arguments are encoded in the same
- // scheme, it is sufficient to walk all the types.
- return bindInstantiatedTypes(rti, parameters, depth);
- }
- if (isDartFunctionType(rti)) {
- return bindInstantiatedFunctionType(rti, parameters, depth);
- }
-
- // Can't include the bad [rti] since it is not a Dart value.
- throw new ArgumentError('Unknown RTI format in bindInstantiatedType.');
-}
-
-/// Returns a copy of array [rti] with each type bound.
-bindInstantiatedTypes(rti, parameters, int depth) {
- List array = JS('JSFixedArray', '#.slice()', rti);
- for (int i = 0; i < array.length; i++) {
- array[i] = bindInstantiatedType(array[i], parameters, depth);
- }
- return array;
-}
-
-/// Calls the JavaScript [function] with the [arguments] with the global scope
-/// as the `this` context.
-invoke(var function, var arguments) => invokeOn(function, null, arguments);
-
-/// Calls the JavaScript [function] with the [arguments] with [receiver] as the
-/// `this` context.
-Object invokeOn(function, receiver, arguments) {
- assert(isJsFunction(function));
- assert(arguments == null || isJsArray(arguments));
- return JS('var', r'#.apply(#, #)', function, receiver, arguments);
-}
-
-/// Calls the property [name] on the JavaScript [object].
-call(var object, String name) => JS('var', r'#[#]()', object, name);
-
-/// Returns the property [name] of the JavaScript object [object].
-getField(var object, String name) => JS('var', r'#[#]', object, name);
-
-/// Returns the property [index] of the JavaScript array [array].
-getIndex(var array, int index) {
- assert(isJsArray(array));
- return JS('var', r'#[#]', array, index);
-}
-
-setField(var object, String name, var value) {
- JS('', '#[#] = #', object, name, value);
-}
-
-setIndex(var array, int index, var value) {
- JS('', '#[#] = #', array, index, value);
-}
-
-/// Returns the length of the JavaScript array [array].
-int getLength(var array) {
- assert(isJsArray(array));
- return JS('int', r'#.length', array);
-}
-
-/// Returns whether [value] is a JavaScript array.
-bool isJsArray(var value) {
- return value is JSArray;
-}
-
-hasField(var object, var name) => JS('bool', r'# in #', name, object);
-
-hasNoField(var object, var name) => !hasField(object, name);
-
-/// Returns `true` if [o] is a JavaScript function.
-bool isJsFunction(var o) => JS('bool', r'typeof # == "function"', o);
-
-/// Returns `true` if [o] is a JavaScript object.
-bool isJsObject(var o) => JS('bool', r"typeof # == 'object'", o);
-
-/// Returns `true` if the JavaScript values [s] and [t] are identical. We use
-/// this helper instead of [identical] because `identical` needs to merge
-/// `null` and `undefined` (which we can avoid).
-bool isIdentical(var s, var t) => JS('bool', '# === #', s, t);
-
-/// Returns `true` if the JavaScript values [s] and [t] are not identical. We
-/// use this helper instead of [identical] because `identical` needs to merge
-/// `null` and `undefined` (which we can avoid).
-bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t);
-
-/// 'Top' bounds are uninteresting: null/undefined and Object.
-bool isInterestingBound(rti) =>
- rti != null &&
- isNotIdentical(
- rti,
- JS_BUILTIN(
- 'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
-
-concat(Object a1, Object a2) => JS('JSArray', '#.concat(#)', a1, a2);
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 39ec922..aceef48 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -620,6 +620,19 @@
bool _isClosure(Object? object) => _Utils.instanceOf(object,
JS_BUILTIN('depends:none;effects:none;', JsBuiltin.dartClosureConstructor));
+/// Stores an Rti on a JavaScript Array (JSArray).
+/// Rti is recovered by [_arrayInstanceType].
+/// Called from generated code.
+// Don't inline. Let the JS engine inline this. The call expression is much
+// more compact that the inlined expansion.
+@pragma('dart2js:noInline')
+Object? setRuntimeTypeInfo(Object? target, Object? rti) {
+ assert(rti != null);
+ var rtiProperty = JS_EMBEDDED_GLOBAL('', ARRAY_RTI_PROPERTY);
+ JS('var', r'#[#] = #', target, rtiProperty, rti);
+ return target;
+}
+
/// Returns the structural function [Rti] of [closure], or `null`.
/// [closure] must be a subclass of [Closure].
/// Called from generated code.
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index 31b46c5f..c50d99c 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -284,41 +284,6 @@
/// instances of parameterized classes.
RTI_NAME,
- /// Name used to tag a function type.
- FUNCTION_TYPE_TAG,
-
- /// Name used to tag bounds of a generic function type. If bounds are present,
- /// the property value is an Array of bounds (the length gives the number of
- /// type parameters). If absent, the type is not a generic function type.
- FUNCTION_TYPE_GENERIC_BOUNDS_TAG,
-
- /// Name used to tag void return in function type representations in
- /// JavaScript.
- FUNCTION_TYPE_VOID_RETURN_TAG,
-
- /// Name used to tag return types in function type representations in
- /// JavaScript.
- FUNCTION_TYPE_RETURN_TYPE_TAG,
-
- /// Name used to tag required parameters in function type representations
- /// in JavaScript.
- FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG,
-
- /// Name used to tag optional parameters in function type representations
- /// in JavaScript.
- FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG,
-
- /// Name used to tag named parameters in function type representations in
- /// JavaScript.
- FUNCTION_TYPE_NAMED_PARAMETERS_TAG,
-
- /// Name used to tag a FutureOr type.
- FUTURE_OR_TAG,
-
- /// Name used to tag type arguments types in FutureOr type representations in
- /// JavaScript.
- FUTURE_OR_TYPE_ARGUMENT_TAG,
-
/// String representation of the type of the Future class.
FUTURE_CLASS_TYPE_NAME,
@@ -374,27 +339,6 @@
/// isCheckProperty);
isCheckPropertyToJsConstructorName,
- /// Returns true if the given type is a function type. Returns false for
- /// the one `Function` type singleton. (See [isFunctionTypeSingleton]).
- ///
- /// JS_BUILTIN('bool', JsBuiltin.isFunctionType, o)
- isFunctionType,
-
- /// Returns true if the given type is a FutureOr type.
- ///
- /// JS_BUILTIN('bool', JsBuiltin.isFutureOrType, o)
- isFutureOrType,
-
- /// Returns true if the given type is the `void` type.
- ///
- /// JS_BUILTIN('bool', JsBuiltin.isVoidType, o)
- isVoidType,
-
- /// Returns true if the given type is the `dynamic` type.
- ///
- /// JS_BUILTIN('bool', JsBuiltin.isDynamicType, o)
- isDynamicType,
-
/// Returns true if the given type is a type argument of a js-interop class
/// or a supertype of a js-interop class.
///
@@ -412,25 +356,6 @@
/// JS_BUILTIN('', JsBuiltin.rawRuntimeType, o)
rawRuntimeType,
- /// Returns whether the given type is a subtype of other.
- ///
- /// The argument `other` is the name of the potential supertype. It is
- /// computed by `runtimeTypeToString`;
- ///
- /// *The `other` name must be passed in before the `type`.*
- ///
- /// JS_BUILTIN('returns:bool;effects:none;depends:none',
- /// JsBuiltin.isSubtype, other, type);
- isSubtype,
-
- /// Returns true if the given type equals the type given as second
- /// argument. Use the JS_GET_NAME helpers to get the type representation
- /// for various Dart classes.
- ///
- /// JS_BUILTIN('returns:bool;effects:none;depends:none',
- /// JsBuiltin.isFunctionTypeLiteral, type, name);
- isGivenTypeRti,
-
/// Returns the metadata of the given [index].
///
/// JS_BUILTIN('returns:var;effects:none;depends:none',
diff --git a/sdk/lib/_internal/js_runtime/pubspec.yaml b/sdk/lib/_internal/js_runtime/pubspec.yaml
index 821aaac..75ee57a 100644
--- a/sdk/lib/_internal/js_runtime/pubspec.yaml
+++ b/sdk/lib/_internal/js_runtime/pubspec.yaml
@@ -3,4 +3,4 @@
name: js_runtime
publish_to: none
environment:
- sdk: '>=2.0.0 <3.0.0'
+ sdk: '>=2.9.0-1 <3.0.0'
diff --git a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
index 08b5518..7179805 100644
--- a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
+++ b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -3,4 +3,4 @@
name: sdk_library_metadata
publish_to: none
environment:
- sdk: '>=2.0.0 <3.0.0'
+ sdk: '>=2.9.0-1 <3.0.0'
diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart
index c3201d3..8d43f33 100644
--- a/sdk/lib/_internal/vm/lib/async_patch.dart
+++ b/sdk/lib/_internal/vm/lib/async_patch.dart
@@ -307,7 +307,7 @@
}
@pragma("vm:entry-point", "call")
-void _completeOnAsyncReturn(Completer completer, Object value) {
+void _completeOnAsyncReturn(Completer completer, Object? value) {
completer.complete(value);
}
diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart
index c4b91f2..75776ec 100644
--- a/sdk/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/errors_patch.dart
@@ -36,8 +36,16 @@
_doThrowNew(assertionStart, assertionEnd, message);
}
+ @pragma("vm:entry-point", "call")
+ @pragma('vm:never-inline')
+ static _throwNewNullAssertion(String name, int line, int column) {
+ _doThrowNewSource('$name != null', line, column, null);
+ }
+
static _doThrowNew(int assertionStart, int assertionEnd, Object? message)
native "AssertionError_throwNew";
+ static _doThrowNewSource(String failedAssertion, int line, int column, Object? message)
+ native "AssertionError_throwNewSource";
@pragma("vm:entry-point", "call")
static _evaluateAssertion(condition) {
@@ -75,7 +83,7 @@
}
final String _failedAssertion;
- final String _url;
+ final String? _url;
final int _line;
final int _column;
final Object? message;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index d42689c..735c7e2 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -454,7 +454,14 @@
int get nativePort native "SendPortImpl_get_id";
}
-int _nativeApiFunctionPointer(String symbol) native "NativeApiFunctionPointer";
+int _nativeApiFunctionPointer(String symbol)
+ native "DartNativeApiFunctionPointer";
+
+int _initializeApiDLData() native "DartApiDLInitializeData";
+
+int _dartApiMajorVersion() native "DartApiDLMajorVersion";
+
+int _dartApiMinorVersion() native "DartApiDLMinorVersion";
@patch
abstract class NativeApi {
@@ -475,4 +482,14 @@
@patch
static Pointer<NativeFunction<Int8 Function(Int64)>> get closeNativePort =>
Pointer.fromAddress(_nativeApiFunctionPointer("Dart_CloseNativePort"));
+
+ @patch
+ static int get majorVersion => _dartApiMajorVersion();
+
+ @patch
+ static int get minorVersion => _dartApiMinorVersion();
+
+ @patch
+ static Pointer<Void> get initializeApiDLData =>
+ Pointer.fromAddress(_initializeApiDLData());
}
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index ae13922..aa85fcc 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -261,6 +261,7 @@
*
* Examples of accepted strings:
*
+ * * `"2012-02-27"`
* * `"2012-02-27 13:27:00"`
* * `"2012-02-27 13:27:00.123456789z"`
* * `"2012-02-27 13:27:00,123456789z"`
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index 3b6e236..68424f8 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -562,8 +562,19 @@
typedef Dart_NativeMessageHandler = Void Function(Int64, Pointer<Dart_CObject>);
-/// Exposes function pointers to functions in `dart_native_api.h`.
+/// Utilities for accessing the Dart VM API from Dart code or
+/// from C code via `dart_api_dl.h`.
abstract class NativeApi {
+ /// On breaking changes the major version is increased.
+ ///
+ /// The versioning covers the API surface in `dart_api_dl.h`.
+ external static int get majorVersion;
+
+ /// On backwards compatible changes the minor version is increased.
+ ///
+ /// The versioning covers the API surface in `dart_api_dl.h`.
+ external static int get minorVersion;
+
/// A function pointer to
/// `bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message)`
/// in `dart_native_api.h`.
@@ -590,4 +601,8 @@
/// in `dart_native_api.h`.
external static Pointer<NativeFunction<Int8 Function(Int64)>>
get closeNativePort;
+
+ /// Pass this to `Dart_InitializeApiDL` in your native code to enable using the
+ /// symbols in `dart_api_dl.h`.
+ external static Pointer<Void> get initializeApiDLData;
}
diff --git a/sdk/lib/js/_js_annotations.dart b/sdk/lib/js/_js_annotations.dart
index 8c8148d..b28e7b7 100644
--- a/sdk/lib/js/_js_annotations.dart
+++ b/sdk/lib/js/_js_annotations.dart
@@ -8,7 +8,7 @@
library _js_annotations;
class JS {
- final String name;
+ final String? name;
const JS([this.name]);
}
diff --git a/sdk/lib/vmservice/running_isolates.dart b/sdk/lib/vmservice/running_isolates.dart
index 20ab8a2..6b6667a 100644
--- a/sdk/lib/vmservice/running_isolates.dart
+++ b/sdk/lib/vmservice/running_isolates.dart
@@ -162,7 +162,7 @@
if (jsonMap.containsKey('error')) {
throw jsonMap['error'];
}
- return jsonMap['result']['result']['kernelBytes'];
+ return jsonMap['result']['kernelBytes'];
});
} else {
// fallback to compile using kernel service
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index c63f78e..ee72c4c 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -5,26 +5,17 @@
Language/Classes/Constructors/Factories/*: Skip # Not migrated to NNBD
Language/Classes/Constructors/Generative_Constructors/*: Skip # Not migrated to NNBD
Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t07: Skip # Type aliases are not fully implemented
-Language/Enums/*: Skip # Not migrated to NNBD:
-Language/Errors_and_Warnings/*: Skip # Not migrated to NNBD
-Language/Expressions/Assignable_Expressions/*: Skip # Not migrated to NNBD
-Language/Expressions/Assignment/*: Skip # Not migrated to NNBD
Language/Expressions/Assignment/Compound_Assignment/*: Skip # Not migrated to NNBD
-Language/Expressions/Bitwise_Expressions/*: Skip # Not migrated to NNBD
-Language/Expressions/Booleans/Boolean_Conversion/*: Skip # Not migrated to NNBD
+Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_static_t12: Skip # Triple shift is not implemented yet
+Language/Expressions/Assignment/Compound_Assignment/null_aware_compound_assignment_t12: Skip # Triple shift is not implemented yet
+Language/Expressions/Assignment/Compound_Assignment/variable_assignment_t12: Skip # Triple shift is not implemented yet
+Language/Expressions/Bitwise_Expressions/syntax_t01: Skip # Triple shift is not implemented yet
Language/Expressions/Constants/*: Skip # Not migrated to NNBD
-Language/Expressions/Equality/*: Skip # Not migrated to NNBD
-Language/Expressions/Function_Expressions/*: Skip # Not migrated to NNBD
+Language/Expressions/Equality/syntax_t01: Skip # Triple shift is not implemented yet
Language/Expressions/Identifier_Reference/*: Skip # Not migrated to NNBD
-Language/Expressions/If_null_Expressions/*: Skip # Not migrated to NNBD
-Language/Expressions/Instance_Creation/Const/*: Skip # Not migrated to NNBD
-Language/Expressions/Instance_Creation/New/*: Skip # Not migrated to NNBD
-Language/Expressions/Lists/*: Skip # Not migrated to NNBD
-Language/Expressions/Maps/*: Skip # Not migrated to NNBD
-Language/Expressions/Method_Invocation/Ordinary_Invocation/*: Skip # Not migrated to NNBD
-Language/Expressions/Method_Invocation/Super_Invocation/*: Skip # Not migrated to NNBD
-Language/Expressions/Unary_Expressions/*: Skip # Not migrated to NNBD
-Language/Functions/*: Skip # Not migrated to NNBD
+Language/Expressions/Instance_Creation/New/type_t09: Skip # Type aliases are not fully implemented
+Language/Expressions/Lists/syntax_t01: Skip # Triple shift is not implemented yet
+Language/Expressions/Maps/syntax_t01: Skip # Triple shift is not implemented yet
Language/Generics/*: Skip # Not migrated to NNBD
Language/Generics/Superbounded_types/*: Skip # Not migrated to NNBD
Language/Interfaces/Superinterfaces/*: Skip # Not migrated to NNBD
@@ -308,12 +299,13 @@
[ $compiler == dart2analyzer ]
Language/Classes/Instance_Methods/Operators/allowed_names_t01: Skip # Triple shift is not fully implemented
Language/Classes/Instance_Methods/Operators/arity_1_t19: Skip # Triple shift is not fully implemented (https://github.com/dart-lang/sdk/issues/42353)
+Language/Functions/syntax_t03: Skip # Triple shift is not implemented yet
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t02: Skip # Type aliases are not supported by analyzer
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t04: Skip # Type aliases are not supported by analyzer
LanguageFeatures/Subtyping/static/tests/left_bottom_A01_t06: Skip # Type aliases are not supported by analyzer
[ $compiler == fasta ]
-Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t10 : Skip # Type aliases are not fully implemented
+Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t10: Skip # Type aliases are not fully implemented
[ $compiler != fasta ]
Language/Classes/Abstract_Instance_Members/inherited_t13: Skip # github.com/dart-lang/language/issues/115
diff --git a/tests/dart2js/async_stacktrace_test.dart b/tests/dart2js/async_stacktrace_test.dart
index 708706b..fffb946 100644
--- a/tests/dart2js/async_stacktrace_test.dart
+++ b/tests/dart2js/async_stacktrace_test.dart
@@ -9,7 +9,7 @@
class Tracer {
final String expected;
- final String name;
+ final String? name;
String _trace = "";
Tracer(this.expected, [this.name]);
diff --git a/tests/dart2js/deferred/deferred_apply_lib.dart b/tests/dart2js/deferred/deferred_apply_lib.dart
new file mode 100644
index 0000000..4302fce
--- /dev/null
+++ b/tests/dart2js/deferred/deferred_apply_lib.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library deferred_apply_lib;
+
+String apply1(Function f) {
+ return Function.apply(f, [], {#req1: 10});
+}
+
+String apply2(Function f) {
+ return Function.apply(f, []);
+}
diff --git a/tests/dart2js/deferred/deferred_apply_test.dart b/tests/dart2js/deferred/deferred_apply_test.dart
new file mode 100644
index 0000000..352f3a2
--- /dev/null
+++ b/tests/dart2js/deferred/deferred_apply_test.dart
@@ -0,0 +1,69 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Requirements=nnbd-strong
+
+import 'package:expect/expect.dart';
+import 'deferred_apply_lib.dart' deferred as lib;
+
+// Test that the `_Required` sentinel in apply-metadata is initialized.
+//
+// This test is structured so that `Function.apply` is partioned out of the main
+// unit into a 'part' file. `Function.apply` contains a reference to the
+// `_Required` sentinel marker, which causes the marker to also be in that part.
+// The apply-metadata for the functions [foo1] and [foo2] contains references to
+// the sentinel that are in the main unit.
+//
+// This apparent reference to the deferred-loaded constant is not a problem
+// because the apply-metadata is contained in a JavaScript function which is not
+// called until the function is passed to `Function.apply`. The loading of the
+// part containing `Function.apply` also loads the sentinel in advance of it
+// being referenced.
+//
+// An implicit constraint here is that the apply-metadata must not be used
+// outside of code that also references the sentinel.
+//
+// If the apply-metadata is created eagerly, or we add other uses of the
+// apply-metadata, then we would need to ensure the constant is located to be
+// available at that time.
+
+main() {
+ lib.loadLibrary().then((_) {
+ Expect.equals('10', lib.apply1(foo1));
+ Expect.equals('10,$text1', lib.apply1(foo2));
+ Expect.throws(() => lib.apply2(foo2));
+ });
+}
+
+class Text {
+ final String string;
+ final String source;
+ const Text(this.string, [this.source = '']);
+ String toString() => string;
+}
+
+String foo1({required int req1}) {
+ return '$req1';
+}
+
+String foo2({required int req1, Text? text = text1}) {
+ return '$req1,$text';
+}
+
+const text1 = Text(r"""
+Those lines that I before have writ do lie,
+Even those that said I could not love you dearer:
+Yet then my judgment knew no reason why
+My most full flame should afterwards burn clearer.
+But reckoning Time, whose million'd accidents
+Creep in 'twixt vows, and change decrees of kings,
+Tan sacred beauty, blunt the sharp'st intents,
+Divert strong minds to the course of altering things;
+Alas! why, fearing of Time's tyranny,
+Might I not then say, 'Now I love you best,'
+When I was certain o'er incertainty,
+Crowning the present, doubting of the rest?
+ Love is a babe, then might I not say so,
+ To give full growth to that which still doth grow?
+""");
diff --git a/tests/dart2js/internal/mock_libraries.dart b/tests/dart2js/internal/mock_libraries.dart
index 9580cff..28f6f01 100644
--- a/tests/dart2js/internal/mock_libraries.dart
+++ b/tests/dart2js/internal/mock_libraries.dart
@@ -288,12 +288,6 @@
'throwRuntimeError': 'throwRuntimeError(message) {}',
'throwUnsupportedError': 'throwUnsupportedError(message) {}',
'throwTypeError': 'throwTypeError(message) {}',
- 'TypeVariable': '''class TypeVariable {
- final Type owner;
- final String name;
- final int bound;
- const TypeVariable(this.owner, this.name, this.bound);
- }''',
'unwrapException': 'unwrapException(e) {}',
'voidTypeCheck': 'voidTypeCheck(value) {}',
'wrapException': 'wrapException(x) { return x; }',
diff --git a/tests/dart2js/recursive_metadata_test.dart b/tests/dart2js/recursive_metadata_test.dart
index 1c46209..c857bc3 100644
--- a/tests/dart2js/recursive_metadata_test.dart
+++ b/tests/dart2js/recursive_metadata_test.dart
@@ -8,7 +8,7 @@
// to other annotated types.
class Annotation {
- final String value;
+ final String? value;
const Annotation({this.value});
}
@@ -18,9 +18,9 @@
}
class SubAnno extends Annotation {
- final Enum e;
- final Type type;
- const SubAnno({String value, this.e, this.type}) : super(value: value);
+ final Enum? e;
+ final Type? type;
+ const SubAnno({String? value, this.e, this.type}) : super(value: value);
}
@SubAnno(value: 'super')
diff --git a/tests/dart2js_2/internal/mock_libraries.dart b/tests/dart2js_2/internal/mock_libraries.dart
index 262b185..edd762b 100644
--- a/tests/dart2js_2/internal/mock_libraries.dart
+++ b/tests/dart2js_2/internal/mock_libraries.dart
@@ -246,12 +246,6 @@
'throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}',
'throwRuntimeError': 'throwRuntimeError(message) {}',
'throwUnsupportedError': 'throwUnsupportedError(message) {}',
- 'TypeVariable': '''class TypeVariable {
- final Type owner;
- final String name;
- final int bound;
- const TypeVariable(this.owner, this.name, this.bound);
- }''',
'unwrapException': 'unwrapException(e) {}',
'voidTypeCheck': 'voidTypeCheck(value) {}',
'wrapException': 'wrapException(x) { return x; }',
diff --git a/tests/dartdevc/assertion_failure_message_test.dart b/tests/dartdevc/assertion_failure_message_test.dart
new file mode 100644
index 0000000..4a7fe7b
--- /dev/null
+++ b/tests/dartdevc/assertion_failure_message_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "utils.dart";
+
+void main() {
+ try {
+ assert(false, "failure message");
+ } on AssertionError catch (error) {
+ var message = error.toString();
+ expectStringContains('Assertion failed:', message);
+ expectStringContains('assertion_failure_message_test.dart:9:12', message);
+ expectStringContains('false', message);
+ expectStringContains('failure message', message);
+ }
+
+ // 失 All offsets and source code extractions should still be correct after
+ // non-UTF8 characters. See: https://github.com/dart-lang/sdk/issues/39271
+ try {
+ assert(false, "after a non-UTF8 character");
+ } on AssertionError catch (error) {
+ var message = error.toString();
+ expectStringContains('Assertion failed:', message);
+ expectStringContains('assertion_failure_message_test.dart:21:12', message);
+ expectStringContains('false', message);
+ expectStringContains('after a non-UTF8 character', message);
+ }
+}
diff --git a/tests/compiler/dartdevc_native/nnbd_basic_assignment_test.dart b/tests/dartdevc/basic_assignment_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/nnbd_basic_assignment_test.dart
rename to tests/dartdevc/basic_assignment_test.dart
diff --git a/tests/dartdevc/const_test.dart b/tests/dartdevc/const_test.dart
new file mode 100644
index 0000000..b2dbf27
--- /dev/null
+++ b/tests/dartdevc/const_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+void main() {
+ var data = JS('', '[1, 2, 3, 4]');
+ Expect.isFalse(data is List<int>);
+
+ var list = dart.constList(data, dart.unwrapType(int));
+ Expect.isTrue(list is List<int>);
+ Expect.throws(() {
+ list[0] = 0;
+ });
+
+ var set = dart.constSet<int>(data);
+ Expect.isTrue(set is Set<int>);
+ Expect.isTrue(set.contains(3));
+ Expect.throws(() => set.clear());
+
+ var map = dart.constMap<int, int>(data);
+ Expect.isTrue(map is Map<int, int>);
+ Expect.equals(map[1], 2);
+ Expect.throws(() {
+ map[1] = 42;
+ });
+}
diff --git a/tests/compiler/dartdevc_native/debugger/debugger_test.dart b/tests/dartdevc/debugger/debugger_test.dart
similarity index 98%
copy from tests/compiler/dartdevc_native/debugger/debugger_test.dart
copy to tests/dartdevc/debugger/debugger_test.dart
index e02bd53..3765d6b 100644
--- a/tests/compiler/dartdevc_native/debugger/debugger_test.dart
+++ b/tests/dartdevc/debugger/debugger_test.dart
@@ -1,5 +1,3 @@
-// @dart = 2.6
-
/// Debugger custom formatter tests.
/// If the tests fail, paste the expected output into the [expectedGolden]
/// string literal in this file and audit the diff to ensure changes are
@@ -129,7 +127,7 @@
// Cache blocker is a workaround for:
// https://code.google.com/p/dart/issues/detail?id=11834
var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
- var goldenUrl = '/root_dart/tests/compiler/dartdevc_native/debugger/'
+ var goldenUrl = '/root_dart/tests/dartdevc_2/debugger/'
'debugger_test_golden.txt?cacheBlock=$cacheBlocker';
String golden;
@@ -326,7 +324,7 @@
if (actualStr != golden) {
var helpMessage =
'Debugger output does not match the golden data found in:\n'
- 'tests/compiler/dartdevc_native/debugger/debugger_test_golden.txt\n'
+ 'tests/dartdevc_2/debugger/debugger_test_golden.txt\n'
'The new golden data is copied to the clipboard when you click on '
'this window.\n'
'Please update the golden file with the following output and review '
diff --git a/tests/compiler/dartdevc_native/hot_restart_late_test.dart b/tests/dartdevc/hot_restart_late_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/hot_restart_late_test.dart
rename to tests/dartdevc/hot_restart_late_test.dart
diff --git a/tests/dartdevc/hot_restart_test.dart b/tests/dartdevc/hot_restart_test.dart
new file mode 100644
index 0000000..37f01ba
--- /dev/null
+++ b/tests/dartdevc/hot_restart_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+class Foo<T> {
+ Type type() => typeOf<Foo<T>>();
+}
+
+class Bar {}
+
+Type typeOf<T>() => T;
+
+Type fooOf<T>() => typeOf<Foo<T>>();
+
+typedef funcType = Function(String);
+
+void func(Object o) {}
+
+void main() {
+ var f1 = Foo<Bar>();
+ var t1 = typeOf<Foo<Bar>>();
+ Expect.equals(f1.type(), t1);
+ var s1 = fooOf<Bar>();
+ Expect.equals(t1, s1);
+
+ Expect.isTrue(func is funcType);
+
+ dart.hotRestart();
+
+ var f2 = Foo<Bar>();
+ Expect.isTrue(f2 is Foo<Bar>);
+ var t2 = typeOf<Foo<Bar>>();
+ Expect.equals(f2.type(), t2);
+ var s2 = fooOf<Bar>();
+ Expect.equals(t2, s2);
+
+ Expect.isTrue(func is funcType);
+}
diff --git a/tests/dartdevc/hot_restart_timer_test.dart b/tests/dartdevc/hot_restart_timer_test.dart
new file mode 100644
index 0000000..9685f51
--- /dev/null
+++ b/tests/dartdevc/hot_restart_timer_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'dart:async';
+import 'dart:_runtime' as dart;
+
+void main() async {
+ await timeoutTest();
+ await periodicTest();
+}
+
+void timeoutTest() async {
+ bool beforeRestart = true;
+ bool calledBeforeRestart = false;
+ bool calledAfterRestart = false;
+ void callback() {
+ if (beforeRestart) {
+ calledBeforeRestart = true;
+ } else {
+ calledAfterRestart = true;
+ }
+ }
+
+ Timer(Duration(milliseconds: 500), callback);
+ dart.hotRestart();
+ beforeRestart = false;
+ await new Future.delayed(Duration(milliseconds: 600));
+ Expect.isFalse(calledBeforeRestart);
+ Expect.isFalse(calledAfterRestart);
+}
+
+void periodicTest() async {
+ bool beforeRestart = true;
+ bool calledBeforeRestart = false;
+ bool calledAfterRestart = false;
+ void callback(_) {
+ if (beforeRestart) {
+ calledBeforeRestart = true;
+ } else {
+ calledAfterRestart = true;
+ }
+ }
+
+ Timer.periodic(Duration(milliseconds: 10), callback);
+ await new Future.delayed(Duration(milliseconds: 100));
+ dart.hotRestart();
+ beforeRestart = false;
+ await new Future.delayed(Duration(milliseconds: 100));
+ Expect.isTrue(calledBeforeRestart);
+ Expect.isFalse(calledAfterRestart);
+}
diff --git a/tests/compiler/dartdevc_native/nnbd_js_interop_test.dart b/tests/dartdevc/js_interop_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/nnbd_js_interop_test.dart
rename to tests/dartdevc/js_interop_test.dart
diff --git a/tests/dartdevc/libraries_part.dart b/tests/dartdevc/libraries_part.dart
new file mode 100644
index 0000000..d5ac766
--- /dev/null
+++ b/tests/dartdevc/libraries_part.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of 'libraries_test.dart';
diff --git a/tests/dartdevc/libraries_test.dart b/tests/dartdevc/libraries_test.dart
new file mode 100644
index 0000000..533eb5d
--- /dev/null
+++ b/tests/dartdevc/libraries_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'dart:_foreign_helper' show JS;
+import 'dart:_runtime' as dart;
+
+part 'libraries_part.dart';
+
+void main() {
+ // Test getLibraries()
+ var libraries = dart.getLibraries();
+ Expect.isTrue(libraries.contains('dart:core'));
+ Expect.isTrue(libraries.contains('package:expect/expect.dart'));
+
+ // Test getParts(...)
+ var expectParts = dart.getParts('package:expect/expect.dart');
+ Expect.isTrue(expectParts.isEmpty);
+
+ var testLibraries =
+ libraries.where((l) => l.endsWith('libraries_test.dart')).toList();
+ Expect.isTrue(testLibraries.length == 1);
+ var testParts = dart.getParts(testLibraries.first);
+ Expect.isTrue(testParts.length == 1);
+ Expect.isTrue(testParts.first.endsWith('libraries_part.dart'));
+
+ // Test getLibrary(...)
+ var core = dart.getLibrary('dart:core');
+ var stackTraceType = dart.wrapType(JS('', '#.StackTrace', core));
+ Expect.equals(StackTrace, stackTraceType);
+}
diff --git a/tests/dartdevc/no_such_method_errors_test.dart b/tests/dartdevc/no_such_method_errors_test.dart
new file mode 100644
index 0000000..1edcf7e
--- /dev/null
+++ b/tests/dartdevc/no_such_method_errors_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "utils.dart";
+
+class A {
+ int x = 42;
+ String arity1(int val) {
+ val += 10;
+ return val.toString();
+ }
+}
+
+String arity1(int val) {
+ val += 10;
+ return val.toString();
+}
+
+dynamic dynamicFunction = arity1;
+
+void main() {
+ dynamic instanceOfA = A();
+ // Call an instance of a class with no call() method.
+ try {
+ instanceOfA();
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'call'", message);
+ expectStringContains("Receiver: Instance of 'A'", message);
+ }
+
+ dynamic tearOff = instanceOfA.arity1;
+ // Dynamic call of a class method with too many arguments.
+ try {
+ tearOff(1, 2);
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'bound arity1'", message);
+ expectStringContains("too many arguments", message);
+ }
+
+ // Dynamic call of a class method with too few arguments.
+ try {
+ tearOff();
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'bound arity1'", message);
+ expectStringContains("too few arguments", message);
+ }
+
+ // Dynamic call of a top level funciton with too many arguments.
+ try {
+ dynamicFunction(1, 2);
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'arity1'", message);
+ expectStringContains("too many arguments", message);
+ }
+
+ // Dynamic call of a top level funciton with too few arguments.
+ try {
+ dynamicFunction();
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'arity1'", message);
+ expectStringContains("too few arguments", message);
+ }
+
+ // Function.apply() with too many arguments.
+ try {
+ Function.apply(dynamicFunction, [1, 2]);
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'arity1'", message);
+ expectStringContains("too many arguments", message);
+ }
+
+ // Function.apply() with too few arguments.
+ try {
+ Function.apply(dynamicFunction, []);
+ } on NoSuchMethodError catch (error) {
+ var message = error.toString();
+ expectStringContains("NoSuchMethodError: 'arity1'", message);
+ expectStringContains("too few arguments", message);
+ }
+}
diff --git a/tests/compiler/dartdevc_native/runtime_utils.dart b/tests/dartdevc/runtime_utils.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/runtime_utils.dart
rename to tests/dartdevc/runtime_utils.dart
diff --git a/tests/compiler/dartdevc_native/runtime_utils_nnbd.dart b/tests/dartdevc/runtime_utils_nnbd.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/runtime_utils_nnbd.dart
rename to tests/dartdevc/runtime_utils_nnbd.dart
diff --git a/tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart b/tests/dartdevc/subtype_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/nnbd_strong_subtype_test.dart
rename to tests/dartdevc/subtype_test.dart
diff --git a/tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart b/tests/dartdevc/subtype_weak_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/nnbd_weak_subtype_test.dart
rename to tests/dartdevc/subtype_weak_test.dart
diff --git a/tests/compiler/dartdevc_native/nnbd_type_normalization_test.dart b/tests/dartdevc/type_normalization_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/nnbd_type_normalization_test.dart
rename to tests/dartdevc/type_normalization_test.dart
diff --git a/tests/dartdevc/utils.dart b/tests/dartdevc/utils.dart
new file mode 100644
index 0000000..79440f7
--- /dev/null
+++ b/tests/dartdevc/utils.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+/// Expects that [expected] appears as a substring in [actual].
+expectStringContains(String expected, String actual) {
+ Expect.isTrue(actual.contains(expected),
+ 'Failure: "$expected" should appear in: "$actual".');
+}
diff --git a/tests/dartdevc/variance_subtype_test.dart b/tests/dartdevc/variance_subtype_test.dart
new file mode 100644
index 0000000..108ec64
--- /dev/null
+++ b/tests/dartdevc/variance_subtype_test.dart
@@ -0,0 +1,189 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=variance
+
+// Tests runtime subtyping with explicit variance modifiers.
+
+import 'dart:_runtime' show typeRep;
+import 'dart:async' show FutureOr;
+
+import 'runtime_utils.dart';
+
+class Upper {}
+
+class Middle extends Upper {}
+
+class Lower extends Middle {}
+
+class Covariant<out T> {}
+
+class Contravariant<in T> {}
+
+class Invariant<inout T> {}
+
+class LegacyCovariant<T> {}
+
+void main() {
+ // Covariant<Lower> <: Covariant<Middle>
+ checkProperSubtype(typeRep<Covariant<Lower>>(), typeRep<Covariant<Middle>>());
+
+ // Covariant<Middle> <: Covariant<Middle>
+ checkSubtype(typeRep<Covariant<Middle>>(), typeRep<Covariant<Middle>>());
+
+ // Contravariant<Upper> <: Contravariant<Middle>
+ checkProperSubtype(
+ typeRep<Contravariant<Upper>>(), typeRep<Contravariant<Middle>>());
+
+ // Contravariant<Middle> <: Contravariant<Middle>
+ checkSubtype(
+ typeRep<Contravariant<Middle>>(), typeRep<Contravariant<Middle>>());
+
+ // Invariant<Middle> <: Invariant<Middle>
+ checkSubtype(typeRep<Invariant<Middle>>(), typeRep<Invariant<Middle>>());
+
+ // Invariant<dynamic> <:> Invariant<Object>
+ checkMutualSubtype(
+ typeRep<Invariant<dynamic>>(), typeRep<Invariant<Object>>());
+
+ // Invariant<FutureOr<dynamic>> <:> Invariant<dynamic>
+ checkMutualSubtype(
+ typeRep<Invariant<FutureOr<dynamic>>>(), typeRep<Invariant<dynamic>>());
+
+ // Invariant<FutureOr<Null>> <:> Invariant<Future<Null>>
+ checkMutualSubtype(
+ typeRep<Invariant<FutureOr<Null>>>(), typeRep<Invariant<Future<Null>>>());
+
+ // LegacyCovariant<Lower> <: LegacyCovariant<Middle>
+ checkProperSubtype(
+ typeRep<LegacyCovariant<Lower>>(), typeRep<LegacyCovariant<Middle>>());
+
+ // List<Covariant<Lower>> <: Iterable<Covariant<Middle>>
+ checkProperSubtype(typeRep<List<Covariant<Lower>>>(),
+ typeRep<Iterable<Covariant<Middle>>>());
+
+ // List<Contravariant<Upper>> <: Iterable<Contravariant<Middle>>
+ checkProperSubtype(typeRep<List<Contravariant<Upper>>>(),
+ typeRep<Iterable<Contravariant<Middle>>>());
+
+ // List<Invariant<Middle>> <: Iterable<Invariant<Middle>>
+ checkProperSubtype(typeRep<List<Invariant<Middle>>>(),
+ typeRep<Iterable<Invariant<Middle>>>());
+
+ // List<LegacyCovariant<Lower>> <: Iterable<LegacyCovariant<Middle>>
+ checkProperSubtype(typeRep<List<LegacyCovariant<Lower>>>(),
+ typeRep<Iterable<LegacyCovariant<Middle>>>());
+
+ // String -> Covariant<Lower> <: String -> Covariant<Middle>
+ checkProperSubtype(typeRep<Covariant<Lower> Function(String)>(),
+ typeRep<Covariant<Middle> Function(String)>());
+
+ // Covariant<Upper> -> String <: Covariant<Middle> -> String
+ checkProperSubtype(typeRep<String Function(Covariant<Upper>)>(),
+ typeRep<String Function(Covariant<Middle>)>());
+
+ // String -> Contravariant<Upper> <: String -> Contravariant<Middle>
+ checkProperSubtype(typeRep<Contravariant<Upper> Function(String)>(),
+ typeRep<Contravariant<Middle> Function(String)>());
+
+ // Contravariant<Lower> -> String <: Contravariant<Middle> -> String
+ checkProperSubtype(typeRep<String Function(Contravariant<Lower>)>(),
+ typeRep<String Function(Contravariant<Middle>)>());
+
+ // String -> Invariant<Middle> <: String -> Invariant<Middle>
+ checkSubtype(typeRep<String Function(Invariant<Middle>)>(),
+ typeRep<String Function(Invariant<Middle>)>());
+
+ // Invariant<Middle> -> String <: Invariant<Middle> -> String
+ checkSubtype(typeRep<String Function(Invariant<Middle>)>(),
+ typeRep<String Function(Invariant<Middle>)>());
+
+ // String -> LegacyCovariant<Lower> <: String -> LegacyCovariant<Middle>
+ checkProperSubtype(typeRep<LegacyCovariant<Lower> Function(String)>(),
+ typeRep<LegacyCovariant<Middle> Function(String)>());
+
+ // LegacyCovariant<Upper> -> String <: LegacyCovariant<Middle> -> String
+ checkProperSubtype(typeRep<String Function(LegacyCovariant<Upper>)>(),
+ typeRep<String Function(LegacyCovariant<Middle>)>());
+
+ // Covariant<Upper> </: Covariant<Middle>
+ checkSubtypeFailure(
+ typeRep<Covariant<Upper>>(), typeRep<Covariant<Middle>>());
+
+ // Contravariant<Lower> </: Contravariant<Middle>
+ checkSubtypeFailure(
+ typeRep<Contravariant<Lower>>(), typeRep<Contravariant<Middle>>());
+
+ // Invariant<Upper> </: Invariant<Middle>
+ checkSubtypeFailure(
+ typeRep<Invariant<Upper>>(), typeRep<Invariant<Middle>>());
+
+ // Invariant<Lower> </: Invariant<Middle>
+ checkSubtypeFailure(
+ typeRep<Invariant<Lower>>(), typeRep<Invariant<Middle>>());
+
+ // LegacyCovariant<Upper> </: LegacyCovariant<Middle>
+ checkSubtypeFailure(
+ typeRep<LegacyCovariant<Upper>>(), typeRep<LegacyCovariant<Middle>>());
+
+ // List<Covariant<Upper>> </: Iterable<Covariant<Middle>>
+ checkSubtypeFailure(typeRep<List<Covariant<Upper>>>(),
+ typeRep<Iterable<Covariant<Middle>>>());
+
+ // List<Contravariant<Lower>> </: Iterable<Contravariant<Middle>>
+ checkSubtypeFailure(typeRep<List<Contravariant<Lower>>>(),
+ typeRep<Iterable<Contravariant<Middle>>>());
+
+ // List<Invariant<Upper>> </: Iterable<Invariant<Middle>>
+ checkSubtypeFailure(typeRep<List<Invariant<Upper>>>(),
+ typeRep<Iterable<Invariant<Middle>>>());
+
+ // List<Invariant<Lower>> </: Iterable<Invariant<Middle>>
+ checkSubtypeFailure(typeRep<List<Invariant<Lower>>>(),
+ typeRep<Iterable<Invariant<Middle>>>());
+
+ // List<LegacyCovariant<Upper>> </: Iterable<LegacyCovariant<Middle>>
+ checkSubtypeFailure(typeRep<List<LegacyCovariant<Upper>>>(),
+ typeRep<Iterable<LegacyCovariant<Middle>>>());
+
+ // String -> Covariant<Upper> </: String -> Covariant<Middle>
+ checkSubtypeFailure(typeRep<Covariant<Upper> Function(String)>(),
+ typeRep<Covariant<Middle> Function(String)>());
+
+ // Covariant<Lower> -> String </: Covariant<Middle> -> String
+ checkSubtypeFailure(typeRep<String Function(Covariant<Lower>)>(),
+ typeRep<String Function(Covariant<Middle>)>());
+
+ // String -> Contravariant<Lower> </: String -> Contravariant<Middle>
+ checkSubtypeFailure(typeRep<Contravariant<Lower> Function(String)>(),
+ typeRep<Contravariant<Middle> Function(String)>());
+
+ // Contravariant<Upper> -> String </: Contravariant<Middle> -> String
+ checkSubtypeFailure(typeRep<String Function(Contravariant<Upper>)>(),
+ typeRep<String Function(Contravariant<Middle>)>());
+
+ // String -> Invariant<Upper> </: String -> Invariant<Middle>
+ checkSubtypeFailure(typeRep<Invariant<Upper> Function(String)>(),
+ typeRep<Invariant<Middle> Function(String)>());
+
+ // Invariant<Upper> -> String </: Invariant<Middle> -> String
+ checkSubtypeFailure(typeRep<String Function(Invariant<Upper>)>(),
+ typeRep<String Function(Invariant<Middle>)>());
+
+ // String -> Invariant<Lower> </: String -> Invariant<Middle>
+ checkSubtypeFailure(typeRep<Invariant<Lower> Function(String)>(),
+ typeRep<Invariant<Middle> Function(String)>());
+
+ // Invariant<Lower> -> String <: Invariant<Middle> -> String
+ checkSubtypeFailure(typeRep<String Function(Invariant<Lower>)>(),
+ typeRep<String Function(Invariant<Middle>)>());
+
+ // String -> LegacyCovariant<Upper> </: String -> LegacyCovariant<Middle>
+ checkSubtypeFailure(typeRep<LegacyCovariant<Upper> Function(String)>(),
+ typeRep<LegacyCovariant<Middle> Function(String)>());
+
+ // LegacyCovariant<Lower> -> String </: LegacyCovariant<Middle> -> String
+ checkSubtypeFailure(typeRep<String Function(LegacyCovariant<Lower>)>(),
+ typeRep<String Function(LegacyCovariant<Middle>)>());
+}
diff --git a/tests/dartdevc/variance_test.dart b/tests/dartdevc/variance_test.dart
new file mode 100644
index 0000000..69c7679
--- /dev/null
+++ b/tests/dartdevc/variance_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// SharedOptions=--enable-experiment=variance
+
+// Tests the emission of explicit variance modifiers.
+
+import 'dart:_runtime'
+ show wrapType, unwrapType, getGenericArgVariances, Variance, typeRep;
+
+import 'package:expect/expect.dart';
+
+class A<in T> {}
+
+class B<out T> {}
+
+class C<inout T> {}
+
+class D<T> {}
+
+class E<inout X, out Y, in Z> {}
+
+mixin F<in T> {}
+
+class G<inout T> = Object with F<T>;
+
+List getVariances(Object t) {
+ // TODO(nshahan) Update to handle legacy wrapper when we unfork dart:_runtime.
+ var type = unwrapType(wrapType(t));
+ return getGenericArgVariances(type);
+}
+
+main() {
+ Expect.listEquals([Variance.contravariant], getVariances(typeRep<A>()));
+
+ Expect.listEquals([Variance.covariant], getVariances(typeRep<B>()));
+
+ Expect.listEquals([Variance.invariant], getVariances(typeRep<C>()));
+
+ // Implicit variance is not emitted into the generated code.
+ Expect.isNull(getVariances(typeRep<D>()));
+
+ Expect.listEquals(
+ [Variance.invariant, Variance.covariant, Variance.contravariant],
+ getVariances(typeRep<E>()));
+
+ Expect.listEquals([Variance.contravariant], getVariances(typeRep<F>()));
+
+ Expect.listEquals([Variance.invariant], getVariances(typeRep<G>()));
+}
diff --git a/tests/compiler/dartdevc_native/assertion_failure_message_test.dart b/tests/dartdevc_2/assertion_failure_message_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/assertion_failure_message_test.dart
rename to tests/dartdevc_2/assertion_failure_message_test.dart
diff --git a/tests/compiler/dartdevc_native/const_test.dart b/tests/dartdevc_2/const_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/const_test.dart
rename to tests/dartdevc_2/const_test.dart
diff --git a/tests/compiler/dartdevc_native/dartdevc_native_dartdevc.status b/tests/dartdevc_2/dartdevc_native_dartdevc.status
similarity index 100%
rename from tests/compiler/dartdevc_native/dartdevc_native_dartdevc.status
rename to tests/dartdevc_2/dartdevc_native_dartdevc.status
diff --git a/tests/compiler/dartdevc_native/debugger/debugger_test.dart b/tests/dartdevc_2/debugger/debugger_test.dart
similarity index 98%
rename from tests/compiler/dartdevc_native/debugger/debugger_test.dart
rename to tests/dartdevc_2/debugger/debugger_test.dart
index e02bd53..94d4a63 100644
--- a/tests/compiler/dartdevc_native/debugger/debugger_test.dart
+++ b/tests/dartdevc_2/debugger/debugger_test.dart
@@ -129,7 +129,7 @@
// Cache blocker is a workaround for:
// https://code.google.com/p/dart/issues/detail?id=11834
var cacheBlocker = new DateTime.now().millisecondsSinceEpoch;
- var goldenUrl = '/root_dart/tests/compiler/dartdevc_native/debugger/'
+ var goldenUrl = '/root_dart/tests/dartdevc_2/debugger/'
'debugger_test_golden.txt?cacheBlock=$cacheBlocker';
String golden;
@@ -326,7 +326,7 @@
if (actualStr != golden) {
var helpMessage =
'Debugger output does not match the golden data found in:\n'
- 'tests/compiler/dartdevc_native/debugger/debugger_test_golden.txt\n'
+ 'tests/dartdevc_2/debugger/debugger_test_golden.txt\n'
'The new golden data is copied to the clipboard when you click on '
'this window.\n'
'Please update the golden file with the following output and review '
diff --git a/tests/compiler/dartdevc_native/debugger/debugger_test_golden.txt b/tests/dartdevc_2/debugger/debugger_test_golden.txt
similarity index 100%
rename from tests/compiler/dartdevc_native/debugger/debugger_test_golden.txt
rename to tests/dartdevc_2/debugger/debugger_test_golden.txt
diff --git a/tests/compiler/dartdevc_native/hot_restart_lazy_test.dart b/tests/dartdevc_2/hot_restart_lazy_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/hot_restart_lazy_test.dart
rename to tests/dartdevc_2/hot_restart_lazy_test.dart
diff --git a/tests/compiler/dartdevc_native/hot_restart_test.dart b/tests/dartdevc_2/hot_restart_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/hot_restart_test.dart
rename to tests/dartdevc_2/hot_restart_test.dart
diff --git a/tests/compiler/dartdevc_native/hot_restart_timer_test.dart b/tests/dartdevc_2/hot_restart_timer_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/hot_restart_timer_test.dart
rename to tests/dartdevc_2/hot_restart_timer_test.dart
diff --git a/tests/compiler/dartdevc_native/js_interop_test.dart b/tests/dartdevc_2/js_interop_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/js_interop_test.dart
rename to tests/dartdevc_2/js_interop_test.dart
diff --git a/tests/compiler/dartdevc_native/libraries_part.dart b/tests/dartdevc_2/libraries_part.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/libraries_part.dart
rename to tests/dartdevc_2/libraries_part.dart
diff --git a/tests/compiler/dartdevc_native/libraries_test.dart b/tests/dartdevc_2/libraries_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/libraries_test.dart
rename to tests/dartdevc_2/libraries_test.dart
diff --git a/tests/compiler/dartdevc_native/no_such_method_errors_test.dart b/tests/dartdevc_2/no_such_method_errors_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/no_such_method_errors_test.dart
rename to tests/dartdevc_2/no_such_method_errors_test.dart
diff --git a/tests/compiler/dartdevc_native/runtime_utils.dart b/tests/dartdevc_2/runtime_utils.dart
similarity index 100%
copy from tests/compiler/dartdevc_native/runtime_utils.dart
copy to tests/dartdevc_2/runtime_utils.dart
diff --git a/tests/compiler/dartdevc_native/subtype_test.dart b/tests/dartdevc_2/subtype_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/subtype_test.dart
rename to tests/dartdevc_2/subtype_test.dart
diff --git a/tests/compiler/dartdevc_native/utils.dart b/tests/dartdevc_2/utils.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/utils.dart
rename to tests/dartdevc_2/utils.dart
diff --git a/tests/compiler/dartdevc_native/variance_subtype_test.dart b/tests/dartdevc_2/variance_subtype_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/variance_subtype_test.dart
rename to tests/dartdevc_2/variance_subtype_test.dart
diff --git a/tests/compiler/dartdevc_native/variance_test.dart b/tests/dartdevc_2/variance_test.dart
similarity index 100%
rename from tests/compiler/dartdevc_native/variance_test.dart
rename to tests/dartdevc_2/variance_test.dart
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 9946ac7..37ab3e9 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -2,8 +2,8 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-[ $builder_tag == asan ]
-data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose.
+[ $builder_tag == msan ]
+vmspecific_handle_test: Skip # https://dartbug.com/42314
[ $system == android ]
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
@@ -20,6 +20,9 @@
[ $arch == simarm || $arch == simarm64 ]
*: Skip # FFI not yet supported on the arm simulator.
+[ $builder_tag == asan || $builder_tag == msan || $builder_tag == tsan ]
+data_not_asan_test: SkipByDesign # This test tries to allocate too much memory on purpose.
+
# These tests trigger and catch an abort (intentionally) and terminate the VM.
# They're incompatible with ASAN because not all memory is freed when aborting and
# with AppJit because the abort the VM before it can generate a snapshot.
diff --git a/tests/ffi/vmspecific_handle_dynamically_linked_test.dart b/tests/ffi/vmspecific_handle_dynamically_linked_test.dart
new file mode 100644
index 0000000..e2237e8
--- /dev/null
+++ b/tests/ffi/vmspecific_handle_dynamically_linked_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+import 'dylib_utils.dart';
+
+void main() {
+ doDynamicLinking();
+ testHandle();
+}
+
+void doDynamicLinking() {
+ Expect.isTrue(NativeApi.majorVersion == 1);
+ Expect.isTrue(NativeApi.minorVersion >= 0);
+ final initializeApi = testLibrary.lookupFunction<
+ IntPtr Function(Pointer<Void>),
+ int Function(Pointer<Void>)>("InitDartApiDL");
+ Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
+}
+
+void testHandle() {
+ final s = SomeClass(123);
+ print("passObjectToC($s)");
+ final result = passObjectToC(s);
+ print("result = $result");
+ Expect.isTrue(identical(s, result));
+}
+
+class SomeClass {
+ // We use this getter in the native api, don't tree shake it.
+ @pragma("vm:entry-point")
+ final int a;
+ SomeClass(this.a);
+}
+
+final testLibrary = dlopenPlatformSpecific("ffi_test_functions");
+
+final passObjectToC = testLibrary.lookupFunction<Handle Function(Handle),
+ Object Function(Object)>("PassObjectToCUseDynamicLinking");
diff --git a/tests/ffi_2/ffi_2.status b/tests/ffi_2/ffi_2.status
index 0991082..37ab3e9 100644
--- a/tests/ffi_2/ffi_2.status
+++ b/tests/ffi_2/ffi_2.status
@@ -2,6 +2,9 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
+[ $builder_tag == msan ]
+vmspecific_handle_test: Skip # https://dartbug.com/42314
+
[ $system == android ]
*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
diff --git a/tests/ffi_2/vmspecific_handle_dynamically_linked_test.dart b/tests/ffi_2/vmspecific_handle_dynamically_linked_test.dart
new file mode 100644
index 0000000..e2237e8
--- /dev/null
+++ b/tests/ffi_2/vmspecific_handle_dynamically_linked_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedObjects=ffi_test_functions
+
+import 'dart:ffi';
+
+import 'package:expect/expect.dart';
+
+import 'dylib_utils.dart';
+
+void main() {
+ doDynamicLinking();
+ testHandle();
+}
+
+void doDynamicLinking() {
+ Expect.isTrue(NativeApi.majorVersion == 1);
+ Expect.isTrue(NativeApi.minorVersion >= 0);
+ final initializeApi = testLibrary.lookupFunction<
+ IntPtr Function(Pointer<Void>),
+ int Function(Pointer<Void>)>("InitDartApiDL");
+ Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
+}
+
+void testHandle() {
+ final s = SomeClass(123);
+ print("passObjectToC($s)");
+ final result = passObjectToC(s);
+ print("result = $result");
+ Expect.isTrue(identical(s, result));
+}
+
+class SomeClass {
+ // We use this getter in the native api, don't tree shake it.
+ @pragma("vm:entry-point")
+ final int a;
+ SomeClass(this.a);
+}
+
+final testLibrary = dlopenPlatformSpecific("ffi_test_functions");
+
+final passObjectToC = testLibrary.lookupFunction<Handle Function(Handle),
+ Object Function(Object)>("PassObjectToCUseDynamicLinking");
diff --git a/tests/language/nnbd/normalization/generic_function_type_object_normalization_test.dart b/tests/language/nnbd/normalization/generic_function_type_object_normalization_test.dart
index 4cb9036d..b7be0f3 100644
--- a/tests/language/nnbd/normalization/generic_function_type_object_normalization_test.dart
+++ b/tests/language/nnbd/normalization/generic_function_type_object_normalization_test.dart
@@ -144,11 +144,9 @@
FutureOr<R> h1<S extends T, R extends S>(S? x) => throw "Unused";
Future<Never> h2<S extends T, R extends S>(Null x) => throw "Unused";
- // void Function<S0 extends FutureOr<R>, S1 extends R, S2 extends R?>()
- // TODO(41952) restore the proper type above when nullable bounds work
- // correctly in the CFE.
- Function i1<R>() =>
- <T0 extends FutureOr<R>, T1 extends R, T2 extends R?>() {};
+ void Function<S0 extends FutureOr<R>, S1 extends R, S2 extends R?>()
+ i1<R>() =>
+ <T0 extends FutureOr<R>, T1 extends R, T2 extends R?>() {};
void Function<S0 extends Future<Never>, S1 extends Never, S2 extends Null>()
i2<R>() =>
@@ -169,7 +167,7 @@
checkTypeNotEquals3(o.f1, o.f2, o.f3);
checkTypeNotEquals2(o.g1, o.g2);
checkTypeNotEquals2(o.h1, o.h2);
- checkTypeNotEquals2(o.i1<Never>(), o.i2<Never>());
+ checkTypeEquals2(o.i1<Never>(), o.i2<Never>());
checkTypeNotEquals2(o.i1<Null>(), o.i2<Null>());
}
}
diff --git a/tests/language/nnbd/null_assertions/parameter_checks_opted_in.dart b/tests/language/nnbd/null_assertions/parameter_checks_opted_in.dart
new file mode 100644
index 0000000..a4f959f
--- /dev/null
+++ b/tests/language/nnbd/null_assertions/parameter_checks_opted_in.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Opted-in library for parameter_checks_test.dart.
+
+import 'dart:async' show FutureOr;
+
+foo1(int a) {}
+foo2(int a, [int b = 1, String c = '']) {}
+foo3({int a = 0, required int b}) {}
+foo4a<T>(T a) {}
+foo4b<T extends Object>(T a) {}
+foo5a<T>(FutureOr<T> a) {}
+foo5b<T extends Object>(FutureOr<T> a) {}
+foo6a<T extends FutureOr<S>, S extends U, U extends int?>(T a) {}
+foo6b<T extends FutureOr<S>, S extends U, U extends int>(T a) {}
+
+void Function(int) bar() => (int x) {};
diff --git a/tests/language/nnbd/null_assertions/parameter_checks_test.dart b/tests/language/nnbd/null_assertions/parameter_checks_test.dart
new file mode 100644
index 0000000..c6f9cc6
--- /dev/null
+++ b/tests/language/nnbd/null_assertions/parameter_checks_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for null assertions for parameters in NNBD weak mode.
+
+// Requirements=nnbd-weak
+// VMOptions=--enable-asserts --null-assertions
+
+// Opt out of Null Safety:
+// @dart = 2.6
+
+import "package:expect/expect.dart";
+
+import 'parameter_checks_opted_in.dart';
+
+main() {
+ Expect.throws(() {
+ foo1(null);
+ }, (e) => e is AssertionError && e.toString().contains("a != null"));
+ Expect.throws(() {
+ foo2(1, null);
+ }, (e) => e is AssertionError && e.toString().contains("b != null"));
+ Expect.throws(() {
+ foo3();
+ }, (e) => e is AssertionError && e.toString().contains("b != null"));
+ Expect.throws(() {
+ foo3(b: null);
+ }, (e) => e is AssertionError && e.toString().contains("b != null"));
+ foo4a<int>(null);
+ Expect.throws(() {
+ foo4b<int>(null);
+ }, (e) => e is AssertionError && e.toString().contains("a != null"));
+ foo5a<int>(null);
+ Expect.throws(() {
+ foo5b<int>(null);
+ }, (e) => e is AssertionError && e.toString().contains("a != null"));
+ foo6a<int, int, int>(null);
+ Expect.throws(() {
+ foo6b<int, int, int>(null);
+ }, (e) => e is AssertionError && e.toString().contains("a != null"));
+ Expect.throws(() {
+ bar().call(null);
+ }, (e) => e is AssertionError && e.toString().contains("x != null"));
+}
diff --git a/tests/language/spread_collections/await_test.dart b/tests/language/spread_collections/await_test.dart
new file mode 100644
index 0000000..8554bbd
--- /dev/null
+++ b/tests/language/spread_collections/await_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:async_helper/async_helper.dart";
+import 'package:expect/expect.dart';
+
+final list = [1, 2, 3, 4, 5];
+final map = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5};
+final set = {1, 2, 3, 4, 5};
+
+void main() {
+ asyncTest(() async {
+ await testList();
+ await testMap();
+ await testSet();
+ });
+}
+
+Future<void> testList() async {
+ var future12 = Future.value([1, 2]);
+ var future45 = Future.value([4, 5]);
+ var nullableFuture12 = Future<List<int>?>.value([1, 2]);
+ var futureNull = Future.value(null);
+
+ // Await in spread.
+ Expect.listEquals(list, [...await future12, 3, ...await future45]);
+
+ // Await in null-aware spread.
+ Expect.listEquals(
+ list, [...?await nullableFuture12, 3, ...?await futureNull, 4, 5]);
+}
+
+Future<void> testMap() async {
+ var future12 = Future.value({1: 1, 2: 2});
+ var future45 = Future.value({4: 4, 5: 5});
+ var nullableFuture12 = Future<Map<int, int>?>.value({1: 1, 2: 2});
+ var futureNull = Future.value(null);
+
+ // Await in spread.
+ Expect.mapEquals(map, {...await future12, 3: 3, ...await future45});
+
+ // Await in null-aware spread.
+ Expect.mapEquals(map,
+ {...?await nullableFuture12, 3: 3, ...?await futureNull, 4: 4, 5: 5});
+}
+
+Future<void> testSet() async {
+ var future12 = Future.value([1, 2]);
+ var future45 = Future.value([4, 5]);
+ var nullableFuture12 = Future<List<int>?>.value([1, 2]);
+ var futureNull = Future.value(null);
+
+ // Await in spread.
+ Expect.setEquals(set, {...await future12, 3, ...await future45});
+
+ // Await in null-aware spread.
+ Expect.setEquals(
+ set, {...?await nullableFuture12, 3, ...?await futureNull, 4, 5});
+}
diff --git a/tests/language/spread_collections/bind_test.dart b/tests/language/spread_collections/bind_test.dart
new file mode 100644
index 0000000..01ad336
--- /dev/null
+++ b/tests/language/spread_collections/bind_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Check that spread collections can be used in combination with async/await features.
+/// This is a regression test for http://dartbug.com/38896
+
+import "package:async_helper/async_helper.dart";
+import 'package:expect/expect.dart';
+
+Future<void> asyncTest1(Future<void> f()) {
+ asyncStart();
+ return f().then(asyncSuccess);
+}
+
+void main() {
+ asyncTest1(() async {
+ await awaitSpreadMemberCallBindTest(); // A
+ await yieldSpreadMemberCallBindTest(); // C
+ await spreadAwaitMemberCallBindTest(); // G
+ await spreadAwaitMemberAccessBindTest(); // I
+ });
+}
+
+class A {
+ List<int> m1() => [1, 2];
+ Future<List<int?>> run() async {
+ return [await null, ...m1()];
+ }
+}
+
+Future<void> awaitSpreadMemberCallBindTest() async {
+ // spread on member call in await
+ Expect.listEquals([null, 1, 2], await A().run());
+}
+
+class C {
+ List<int> m2() => [1, 2];
+
+ Future<List<int>> run() async {
+ return await run3().toList();
+ }
+
+ Stream<int> run3() async* {
+ for (var k in [...await m2()]) yield k;
+ }
+}
+
+Future<void> yieldSpreadMemberCallBindTest() async {
+ var expected = [1, 2];
+
+ // spread on await of member call with yield
+ Expect.listEquals(expected, await C().run());
+}
+
+class G {
+ List<int> m2() => [1, 2];
+
+ Future<List<int>> run() async {
+ return [...await m2()];
+ }
+}
+
+Future<void> spreadAwaitMemberCallBindTest() async {
+ var expected = [1, 2];
+
+ // spread on await of member call
+ Expect.listEquals(expected, await G().run());
+}
+
+class I1 {
+ List<int> foo() => [1, 2];
+}
+
+class I {
+ I1 b = I1();
+ Future<List<int>> run() async {
+ return [...await b.foo()];
+ }
+}
+
+Future<void> spreadAwaitMemberAccessBindTest() async {
+ var expected = [1, 2];
+
+ // spread on await of member access
+ Expect.listEquals(expected, await I().run());
+}
diff --git a/tests/language/spread_collections/const_error_test.dart b/tests/language/spread_collections/const_error_test.dart
new file mode 100644
index 0000000..e9fcfd2
--- /dev/null
+++ b/tests/language/spread_collections/const_error_test.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+import 'helper_classes.dart';
+
+var nonConstList = <int>[];
+var nonConstMap = <int, String>{};
+var nonConstSet = <int>{};
+const dynamic nonIterable = 3;
+const dynamic nonMap = 3;
+
+void main() {
+ testList();
+ testMap();
+ testSet();
+}
+
+void testList() {
+ // Must be constant.
+ const _ = <int>[...nonConstList]; //# 01: compile-time error
+
+ // Must be iterable.
+ const _ = <int>[...nonIterable]; //# 02: compile-time error
+
+ // Cannot be custom iterable type.
+ const _ = <int>[...ConstIterable()]; //# 03: compile-time error
+}
+
+void testMap() {
+ // Must be constant.
+ const _ = <int, String>{...nonConstMap}; //# 04: compile-time error
+
+ // Must be map.
+ const _ = <int, String>{...nonMap}; //# 05: compile-time error
+
+ // Cannot be custom map type.
+ const _ = <int, String>{...ConstMap()}; //# 06: compile-time error
+
+ // Cannot have key collision.
+ const _ = <int, String>{1: "s", ...{1: "t"}}; //# 07: compile-time error
+ const _ = <int, String>{...{1: "s"}, ...{1: "t"}}; //# 08: compile-time error
+}
+
+void testSet() {
+ // Must be constant.
+ const _ = <int>{...nonConstList}; //# 09: compile-time error
+ const _ = <int>{...nonConstSet}; //# 10: compile-time error
+
+ // Must be iterable.
+ const _ = <int>{...nonIterable}; //# 11: compile-time error
+
+ // Cannot be custom iterable type.
+ const _ = <int>{...ConstIterable()}; //# 12: compile-time error
+
+ // Cannot override operator.==().
+ const obj = 0.1;
+ const _ = {...[0.1]}; //# 13: compile-time error
+ const _ = {...[Duration(seconds: 0)]}; //# 14: compile-time error
+ const _ = {...[obj]}; //# 15: compile-time error
+
+ // Cannot have collision.
+ const _ = {1, ...[1]}; //# 16: compile-time error
+ const _ = {...[1, 1, 3, 8]}; //# 17: compile-time error
+ const _ = {...[1], ...[1]}; //# 18: compile-time error
+}
diff --git a/tests/language/spread_collections/const_test.dart b/tests/language/spread_collections/const_test.dart
new file mode 100644
index 0000000..1eb4d76
--- /dev/null
+++ b/tests/language/spread_collections/const_test.dart
@@ -0,0 +1,186 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+// Typed as dynamic to also test spreading a value of type dynamic.
+const dynamic list = [1, 2, 3, 4];
+const dynamic map = {1: 1, 2: 2, 3: 3, 4: 4};
+const dynamic set = {1, 2, 3, 4};
+
+void main() {
+ testList();
+ testMap();
+ testSet();
+ testKeyOrder();
+}
+
+void testList() {
+ // Only spread.
+ Expect.identical(list, const <int>[...list]);
+ Expect.identical(list, const <int>[...set]);
+
+ // Spread at beginning.
+ Expect.identical(list, const <int>[...<int>[1, 2], 3, 4]);
+
+ // Spread in middle.
+ Expect.identical(list, const <int>[1, ...<int>[2, 3], 4]);
+
+ // Spread at end.
+ Expect.identical(list, const <int>[1, 2, ...<int>[3, 4]]);
+
+ // Empty spreads.
+ Expect.identical(list,
+ const <int>[...<int>[], 1, 2, ...<int>[], 3, 4, ...<int>[]]);
+
+ // Multiple spreads.
+ Expect.identical(list,
+ const <int>[...<int>[1], 2, ...<int>[3, 4]]);
+
+ // Nested spreads.
+ Expect.identical(list,
+ const <int>[...<int>[...<int>[1, 2], ...<int>[3, 4]]]);
+
+ // Null-aware.
+ const List<int>? list23 = <int>[2, 3];
+ const List<int>? list4 = <int>[4];
+ Expect.identical(list,
+ const <int>[1, ...?list23, ...?(null), ...?list4]);
+
+ // Does not deep flatten.
+ Expect.identical(
+ const <Object>[1, 2, <int>[3], 4],
+ const <Object>[1, ...<Object>[2, <int>[3], 4]]);
+
+ // Establishes const context.
+ Expect.identical(const <Symbol>[Symbol("sym")],
+ const <Symbol>[...<Symbol>[Symbol("sym")]]);
+}
+
+void testMap() {
+ // Only spread.
+ Expect.identical(map, const <int, int>{...map});
+
+ // Spread at beginning.
+ Expect.identical(map,
+ const <int, int>{...<int, int>{1: 1, 2: 2}, 3: 3, 4: 4});
+
+ // Spread in middle.
+ Expect.identical(map,
+ const <int, int>{1: 1, ...<int, int>{2: 2, 3: 3}, 4: 4});
+
+ // Spread at end.
+ Expect.identical(map,
+ const <int, int>{1: 1, 2: 2, ...<int, int>{3: 3, 4: 4}});
+
+ // Empty spreads.
+ Expect.identical(map, const <int, int>{
+ ...<int, int>{},
+ 1: 1,
+ 2: 2,
+ ...<int, int>{},
+ 3: 3,
+ 4: 4,
+ ...<int, int>{}
+ });
+
+ // Multiple spreads.
+ Expect.identical(map,
+ const <int, int>{...<int, int>{1: 1}, 2: 2, ...<int, int>{3: 3, 4: 4}});
+
+ // Nested spreads.
+ Expect.identical(map, const <int, int>{
+ ...<int, int>{
+ ...<int, int>{1: 1, 2: 2},
+ ...<int, int>{3: 3, 4: 4}
+ }
+ });
+
+ // Null-aware.
+ const Map<int, int>? map23 = <int, int>{2: 2, 3: 3};
+ const Map<int, int>? map4 = <int, int>{4: 4};
+ Expect.identical(map, const <int, int>{
+ 1: 1,
+ ...?map23,
+ ...?(null),
+ ...?map4
+ });
+
+ // Does not deep flatten.
+ Expect.identical(const <int, Object>{
+ 1: 1,
+ 2: 2,
+ 3: <int, int>{3: 3},
+ 4: 4
+ }, const <int, Object>{
+ 1: 1,
+ ...<int, Object>{
+ 2: 2,
+ 3: <int, int>{3: 3},
+ 4: 4
+ }
+ });
+
+ // Establishes const context.
+ Expect.identical(const <Symbol, Symbol>{
+ Symbol("sym"): Symbol("bol")
+ }, const <Symbol, Symbol>{
+ ...<Symbol, Symbol>{Symbol("sym"): Symbol("bol")}
+ });
+}
+
+void testSet() {
+ // Only spread.
+ Expect.identical(set, const <int>{...set});
+ Expect.identical(set, const <int>{...list});
+
+ // Spread at beginning.
+ Expect.identical(set, const <int>{...<int>[1, 2], 3, 4});
+
+ // Spread in middle.
+ Expect.identical(set, const <int>{1, ...<int>[2, 3], 4});
+
+ // Spread at end.
+ Expect.identical(set, const <int>{1, 2, ...<int>[3, 4]});
+
+ // Empty spreads.
+ Expect.identical(set,
+ const <int>{...<int>[], 1, 2, ...<int>[], 3, 4, ...<int>[]});
+
+ // Multiple spreads.
+ Expect.identical(set, const <int>{...<int>[1], 2, ...<int>[3, 4]});
+
+ // Nested spreads.
+ Expect.identical(set, const <int>{...<int>{...<int>[1, 2], ...<int>[3, 4]}});
+
+ // Null-aware.
+ const List<int>? list23 = <int>[2, 3];
+ const List<int>? list4 = <int>[4];
+ Expect.identical(set,
+ const <int>{1, ...?list23, ...?(null), ...?list4});
+
+ // Does not deep flatten.
+ Expect.identical(const <Object>{1, 2, <int>{3}, 4},
+ const <Object>{1, ...<Object>{2, <int>{3}, 4}});
+
+ // Establishes const context.
+ Expect.identical(const <Symbol>{Symbol("sym")},
+ const <Symbol>{...<Symbol>{Symbol("sym")}});
+}
+
+void testKeyOrder() {
+ // Canonicalization isn't affected by which elements are spread.
+ Expect.identical(map,
+ const <int, int>{1: 1, ...<int, int>{2: 2, 3: 3}, 4: 4});
+ Expect.identical(map,
+ const <int, int>{1: 1, ...<int, int>{2: 2}, 3: 3, ...<int, int>{4: 4}});
+
+ Expect.identical(set, const <int>{1, ...<int>{2, 3}, 4});
+ Expect.identical(set, const <int>{1, ...<int>{2}, 3, ...<int>{4}});
+
+ // Ordering does affect canonicalization.
+ Expect.notIdentical(const <int, int>{1: 1, 2: 2, 3: 3},
+ const <int, int>{1: 1, ...<int, int>{3: 3, 2: 2}});
+ Expect.notIdentical(const <int>{1, 2, 3}, const <int>{1, ...<int>{3, 2}});
+}
diff --git a/tests/language/spread_collections/helper_classes.dart b/tests/language/spread_collections/helper_classes.dart
new file mode 100644
index 0000000..3e10706
--- /dev/null
+++ b/tests/language/spread_collections/helper_classes.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:collection';
+
+class ConstIterable extends IterableBase<int> {
+ const ConstIterable();
+
+ Iterator<int> get iterator => <int>[].iterator;
+}
+
+class ConstMap implements Map<int, String> {
+ const ConstMap();
+
+ Iterable<MapEntry<int, String>> get entries => const [];
+
+ bool get isEmpty => throw UnsupportedError("unsupported");
+ bool get isNotEmpty => throw UnsupportedError("unsupported");
+ Iterable<int> get keys => throw UnsupportedError("unsupported");
+ int get length => throw UnsupportedError("unsupported");
+ Iterable<String> get values => throw UnsupportedError("unsupported");
+ String? operator [](Object? key) => throw UnsupportedError("unsupported");
+ operator []=(int key, String value) => throw UnsupportedError("unsupported");
+ bool add(Object? value) => throw UnsupportedError("unsupported");
+ void addAll(Map<int, String> map) => throw UnsupportedError("unsupported");
+ void addEntries(Iterable<MapEntry<int, String>> entries) =>
+ throw UnsupportedError("unsupported");
+ Map<RK, RV> cast<RK, RV>() => throw UnsupportedError("unsupported");
+ void clear() => throw UnsupportedError("unsupported");
+ bool containsKey(Object? key) => throw UnsupportedError("unsupported");
+ bool containsValue(Object? value) => throw UnsupportedError("unsupported");
+ void forEach(void Function(int key, String value) f) =>
+ throw UnsupportedError("unsupported");
+ Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> Function(int key, String value) f) =>
+ throw UnsupportedError("unsupported");
+ String putIfAbsent(int key, String Function() ifAbsent) =>
+ throw UnsupportedError("unsupported");
+ String? remove(Object? key) => throw UnsupportedError("unsupported");
+ void removeWhere(bool Function(int key, String value) predicate) =>
+ throw UnsupportedError("unsupported");
+ String update(int key, String Function(String value) update,
+ {String Function()? ifAbsent}) =>
+ throw UnsupportedError("unsupported");
+ void updateAll(String Function(int key, String value) update) =>
+ throw UnsupportedError("unsupported");
+}
+
+class CustomMap with MapMixin<int, String> {
+ Iterable<int> get keys => [];
+ String? operator [](Object? key) => "";
+ operator []=(int key, String value) {}
+ String? remove(Object? key) => throw UnsupportedError("unsupported");
+ void clear() => throw UnsupportedError("unsupported");
+}
+
+class CustomSet extends SetBase<int> {
+ bool add(int value) => throw UnsupportedError("unsupported");
+ bool contains(Object? value) => throw UnsupportedError("unsupported");
+ Iterator<int> get iterator => <int>[].iterator;
+ int get length => 0;
+ int? lookup(Object? value) => throw UnsupportedError("unsupported");
+ bool remove(Object? value) => throw UnsupportedError("unsupported");
+ Set<int> toSet() => this;
+}
+
+class Equality {
+ final int id;
+ final String name;
+ const Equality(this.id, this.name);
+ int get hashCode => id;
+ bool operator ==(Object? other) => other is Equality && id == other.id;
+ String toString() => "$id:$name";
+}
diff --git a/tests/language/spread_collections/inference_test.dart b/tests/language/spread_collections/inference_test.dart
new file mode 100644
index 0000000..c0dff36
--- /dev/null
+++ b/tests/language/spread_collections/inference_test.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test how spread interacts with inference.
+import 'package:expect/expect.dart';
+
+void main() {
+ testBottomUpInference();
+ testTopDownInference();
+}
+
+void testBottomUpInference() {
+ // Lists.
+ Expect.type<List<dynamic>>([...[]]);
+ Expect.type<List<int>>([...<int>[]]);
+ Expect.type<List<int>>([...[1]]);
+ Expect.type<List<int>>([1, ...[2]]);
+ Expect.type<List<num>>([1, ...[0.2]]);
+ Expect.type<List<int>>([...[1, 2]]);
+ Expect.type<List<num>>([...[1, 0.2]]);
+ Expect.type<List<int>>([...[1], ...[2]]);
+ Expect.type<List<num>>([...[1], ...[0.2]]);
+
+ // Maps.
+ Expect.type<Map<dynamic, dynamic>>({...{}});
+ Expect.type<Map<int, int>>({...<int, int>{}});
+ Expect.type<Map<int, int>>({...{1: 1}});
+ Expect.type<Map<int, int>>({1: 1, ...{2: 2}});
+ Expect.type<Map<num, num>>({1: 1, ...{0.2: 0.2}});
+ Expect.type<Map<int, int>>({...{1: 1, 2: 2}});
+ Expect.type<Map<num, num>>({...{1: 1, 0.2: 0.2}});
+ Expect.type<Map<int, int>>({...{1: 1}, ...{2: 2}});
+ Expect.type<Map<num, num>>({...{1: 1}, ...{0.2: 0.2}});
+
+ // Sets.
+ Expect.type<Set<dynamic>>({...[]});
+ Expect.type<Set<int>>({...<int>[]});
+ Expect.type<Set<int>>({...[1]});
+ Expect.type<Set<int>>({1, ...[2]});
+ Expect.type<Set<num>>({1, ...[0.2]});
+ Expect.type<Set<int>>({...[1, 2]});
+ Expect.type<Set<num>>({...[1, 0.2]});
+ Expect.type<Set<int>>({...[1], ...[2]});
+ Expect.type<Set<num>>({...[1], ...[0.2]});
+ Expect.type<Set<num>>({...{1}, ...[0.2]});
+ Expect.type<Set<num>>({...{1}, ...{0.2}});
+
+ // If the iterable's type is dynamic, the element type is inferred as dynamic.
+ Expect.type<List<dynamic>>([...([] as dynamic)]);
+ Expect.type<Set<dynamic>>({1, ...([] as dynamic)});
+
+ // If the iterable's type is dynamic, the key and value types are inferred as
+ // dynamic.
+ Expect.type<Map<dynamic, dynamic>>({1: 1, ...({} as dynamic)});
+}
+
+void testTopDownInference() {
+ // Lists.
+ Iterable<T> expectIntIterable<T>() {
+ Expect.equals(int, T);
+ return [];
+ }
+
+ Iterable<T> expectDynamicIterable<T>() {
+ Expect.equals(dynamic, T);
+ return [];
+ }
+
+ // The context element type is pushed into the spread expression if it is
+ // Iterable<T>.
+ Expect.listEquals(<int>[], <int>[...expectIntIterable()]);
+
+ // Bottom up-inference from elements is not pushed back down into spread.
+ Expect.listEquals(<int>[1], [1, ...expectDynamicIterable()]);
+
+ // Maps.
+ Map<K, V> expectIntStringMap<K, V>() {
+ Expect.equals(int, K);
+ Expect.equals(String, V);
+ return {};
+ }
+
+ Map<K, V> expectDynamicDynamicMap<K, V>() {
+ Expect.equals(dynamic, K);
+ Expect.equals(dynamic, V);
+ return {};
+ }
+
+ // The context element type is pushed into the spread expression if it is
+ // Map<K, V>.
+ Expect.mapEquals(<int, String>{}, <int, String>{...expectIntStringMap()});
+
+ // Bottom up-inference from elements is not pushed back down into spread.
+ Expect.mapEquals(<int, String>{1: "s"},
+ {1: "s", ...expectDynamicDynamicMap()});
+
+ // Sets.
+ Set<T> expectIntSet<T>() {
+ Expect.equals(int, T);
+ return Set();
+ }
+
+ Set<T> expectDynamicSet<T>() {
+ Expect.equals(dynamic, T);
+ return Set();
+ }
+
+ // The context element type is pushed into the spread expression if it is
+ // Iterable<T>.
+ Expect.setEquals(<int>{}, <int>{...expectIntSet()});
+
+ // Bottom up-inference from elements is not pushed back down into spread.
+ Expect.setEquals(<int>{1}, {1, ...expectDynamicSet()});
+}
diff --git a/tests/language/spread_collections/map_set_ambiguity_error_test.dart b/tests/language/spread_collections/map_set_ambiguity_error_test.dart
new file mode 100644
index 0000000..00f40a8
--- /dev/null
+++ b/tests/language/spread_collections/map_set_ambiguity_error_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test cases where the syntax is ambiguous between maps and sets.
+import 'dart:collection';
+
+import 'helper_classes.dart';
+
+void main() {
+ Map<int, int> map = {};
+ Set<int> set = Set();
+ dynamic dyn = map;
+ Iterable<int> iterable = [];
+ CustomSet customSet = CustomSet();
+ CustomMap customMap = CustomMap();
+
+ var _ = {...dyn}; //# 00: compile-time error
+ var _ = {...map, ...set}; //# 01: compile-time error
+ var _ = {...map, ...iterable}; //# 02: compile-time error
+ var _ = {...map, ...customSet}; //# 03: compile-time error
+ var _ = {...set, ...customMap}; //# 04: compile-time error
+ var _ = {...dyn, ...dyn}; //# 05: compile-time error
+ var _ = {...iterable, ...customMap}; //# 06: compile-time error
+ var _ = {...customSet, ...customMap}; //# 07: compile-time error
+}
diff --git a/tests/language/spread_collections/map_set_ambiguity_test.dart b/tests/language/spread_collections/map_set_ambiguity_test.dart
new file mode 100644
index 0000000..11345ea
--- /dev/null
+++ b/tests/language/spread_collections/map_set_ambiguity_test.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test cases where the syntax is ambiguous between maps and sets.
+import 'dart:collection';
+
+import 'package:expect/expect.dart';
+
+import 'helper_classes.dart';
+
+void main() {
+ testBottomUpInference();
+ testTopDownInference();
+}
+
+void testBottomUpInference() {
+ Map<int, int> map = {};
+ Set<int> set = Set();
+ dynamic dynMap = map;
+ dynamic dynSet = set;
+ Iterable<int> iterable = [];
+ CustomSet customSet = CustomSet();
+ CustomMap customMap = CustomMap();
+
+ // Note: The commented out cases are the error cases. They are shown here for
+ // completeness and tested in map_set_ambiguity_error_test.dart.
+ Expect.type<Map<int, int>>({...map});
+ Expect.type<Set<int>>({...set});
+ // Expect.type<...>({...dyn});
+ Expect.type<Set<int>>({...iterable});
+ Expect.type<Set<int>>({...customSet});
+ Expect.type<Map<int, String>>({...customMap});
+
+ Expect.type<Map<int, int>>({...map, ...map});
+ // Expect.type<...>({...map, ...set});
+ Expect.type<Map<dynamic, dynamic>>({...map, ...dynMap});
+ // Expect.type<...>({...map, ...iterable});
+ // Expect.type<...>({...map, ...customSet});
+ Expect.type<Map<int, Object>>({...map, ...customMap});
+
+ Expect.type<Set<int>>({...set, ...set});
+ Expect.type<Set<dynamic>>({...set, ...dynSet});
+ Expect.type<Set<int>>({...set, ...iterable});
+ Expect.type<Set<int>>({...set, ...customSet});
+ // Expect.type<...>({...set, ...customMap});
+
+ // Expect.type<...>({...dyn, ...dyn});
+ Expect.type<Set<dynamic>>({...dynSet, ...iterable});
+ Expect.type<Set<dynamic>>({...dynSet, ...customSet});
+ Expect.type<Map<dynamic, dynamic>>({...dynMap, ...customMap});
+
+ Expect.type<Set<int>>({...iterable, ...iterable});
+ Expect.type<Set<int>>({...iterable, ...customSet});
+ // Expect.type<...>({...iterable, ...customMap});
+
+ Expect.type<Set<int>>({...customSet, ...customSet});
+ // Expect.type<...>({...customSet, ...customMap});
+
+ Expect.type<Map<int, String>>({...customMap, ...customMap});
+}
+
+void testTopDownInference() {
+ dynamic untypedMap = <int, int>{};
+ dynamic untypedIterable = <int>[];
+
+ Map<int, int> map = {...untypedMap};
+ Set<int> set = {...untypedIterable};
+ Iterable<int> iterable = {...untypedIterable};
+
+ Expect.type<Map<int, int>>(map);
+ Expect.type<Set<int>>(set);
+ Expect.type<Set<int>>(iterable);
+}
diff --git a/tests/language/spread_collections/runtime_error_test.dart b/tests/language/spread_collections/runtime_error_test.dart
new file mode 100644
index 0000000..d133b04
--- /dev/null
+++ b/tests/language/spread_collections/runtime_error_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+// Typed as dynamic to also test spreading a value of type dynamic.
+final dynamic list = [1, 2, 3, 4];
+final dynamic map = {1: 1, 2: 2, 3: 3, 4: 4};
+final dynamic set = {1, 2, 3, 4};
+
+void main() {
+ dynamic nonIterable = 3;
+ Expect.throwsTypeError(() => <int>[...nonIterable]);
+ Expect.throwsTypeError(() => <int>{...nonIterable});
+
+ dynamic nonMap = 3;
+ Expect.throwsTypeError(() => <int, int>{...nonMap});
+
+ dynamic wrongIterableType = <String>["s"];
+ Expect.throwsTypeError(() => <int>[...wrongIterableType]);
+ Expect.throwsTypeError(() => <int>{...wrongIterableType});
+
+ dynamic wrongKeyType = <String, int>{"s": 1};
+ dynamic wrongValueType = <int, String>{1: "s"};
+ Expect.throwsTypeError(() => <int, int>{...wrongKeyType});
+ Expect.throwsTypeError(() => <int, int>{...wrongValueType});
+
+ // Mismatched collection types.
+ Expect.throwsTypeError(() => <int>[...map]);
+ Expect.throwsTypeError(() => <int, int>{...list});
+ Expect.throwsTypeError(() => <int, int>{...set});
+ Expect.throwsTypeError(() => <int>{...map});
+}
diff --git a/tests/language/spread_collections/spread_test.dart b/tests/language/spread_collections/spread_test.dart
new file mode 100644
index 0000000..2a19168
--- /dev/null
+++ b/tests/language/spread_collections/spread_test.dart
@@ -0,0 +1,203 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+import 'helper_classes.dart';
+
+// Typed as dynamic to also test spreading a value of type dynamic.
+final dynamic list = [1, 2, 3, 4];
+final dynamic map = {1: 1, 2: 2, 3: 3, 4: 4};
+final dynamic set = {1, 2, 3, 4};
+
+void main() {
+ testList();
+ testMap();
+ testSet();
+ testDuplicateKeys();
+ testKeyOrder();
+}
+
+void testList() {
+ // Only spread.
+ Expect.listEquals(list, <int>[...list]);
+
+ // Spread at beginning.
+ Expect.listEquals(list, <int>[...<int>[1, 2], 3, 4]);
+
+ // Spread in middle.
+ Expect.listEquals(list, <int>[1, ...<int>[2, 3], 4]);
+
+ // Spread at end.
+ Expect.listEquals(list, <int>[1, 2, ...<int>[3, 4]]);
+
+ // Empty spreads.
+ Expect.listEquals(list,
+ <int>[...<int>[], 1, 2, ...<int>[], 3, 4, ...<int>[]]);
+
+ // Multiple spreads.
+ Expect.listEquals(list, <int>[...<int>[1], 2, ...<int>[3, 4]]);
+
+ // Nested spreads.
+ Expect.listEquals(list, <int>[...<int>[...<int>[1, 2], ...<int>[3, 4]]]);
+
+ // Null-aware.
+ List<int>? list23 = [2, 3];
+ List<int>? list4 = [4];
+ Expect.listEquals(list, <int>[1, ...?list23, ...?(null), ...?list4]);
+
+ // Does not deep flatten.
+ var innerList = <int>[3];
+ Expect.listEquals(
+ <Object>[1, 2, innerList, 4],
+ <Object>[1, ...<Object>[2, innerList, 4]]);
+
+ // Downcast element from dynamic.
+ Expect.listEquals(list, <int>[...<dynamic>[1, 2, 3, 4]]);
+}
+
+void testMap() {
+ // Only spread.
+ Expect.mapEquals(map, <int, int>{...map});
+
+ // Spread at beginning.
+ Expect.mapEquals(map, <int, int>{...<int, int>{1: 1, 2: 2}, 3: 3, 4: 4});
+
+ // Spread in middle.
+ Expect.mapEquals(map, <int, int>{1: 1, ...<int, int>{2: 2, 3: 3}, 4: 4});
+
+ // Spread at end.
+ Expect.mapEquals(map, <int, int>{1: 1, 2: 2, ...<int, int>{3: 3, 4: 4}});
+
+ // Empty spreads.
+ Expect.mapEquals(map, <int, int>{
+ ...<int, int>{},
+ 1: 1,
+ 2: 2,
+ ...<int, int>{},
+ 3: 3,
+ 4: 4,
+ ...<int, int>{}
+ });
+
+ // Multiple spreads.
+ Expect.mapEquals(map,
+ <int, int>{...<int, int>{1: 1}, 2: 2, ...<int, int>{3: 3, 4: 4}});
+
+ // Nested spreads.
+ Expect.mapEquals(map, <int, int>{
+ ...<int, int>{
+ ...<int, int>{1: 1, 2: 2},
+ ...<int, int>{3: 3, 4: 4}
+ }
+ });
+
+ // Null-aware.
+ Map<int, int>? map23 = {2: 2, 3: 3};
+ Map<int, int>? map4 = {4: 4};
+ Expect.mapEquals(map, <int, int>{
+ 1: 1,
+ ...?map23,
+ ...?(null),
+ ...?map4
+ });
+
+ // Does not deep flatten.
+ var innerMap = <int, int>{3: 3};
+ Expect.mapEquals(<int, Object>{
+ 1: 1,
+ 2: 2,
+ 3: innerMap,
+ 4: 4
+ }, <int, Object>{
+ 1: 1,
+ ...<int, Object>{
+ 2: 2,
+ 3: innerMap,
+ 4: 4
+ }
+ });
+
+ // Downcast element from dynamic.
+ Expect.mapEquals(
+ map, <int, int>{...<dynamic, dynamic>{1: 1, 2: 2, 3: 3, 4: 4}});
+}
+
+void testSet() {
+ // Only spread.
+ Expect.setEquals(set, <int>{...set});
+
+ // Spread at beginning.
+ Expect.setEquals(set, <int>{...<int>[1, 2], 3, 4});
+
+ // Spread in middle.
+ Expect.setEquals(set, <int>{1, ...<int>[2, 3], 4});
+
+ // Spread at end.
+ Expect.setEquals(set, <int>{1, 2, ...<int>[3, 4]});
+
+ // Empty spreads.
+ Expect.setEquals(set, <int>{...<int>[], 1, 2, ...<int>[], 3, 4, ...<int>[]});
+
+ // Multiple spreads.
+ Expect.setEquals(set, <int>{...<int>[1], 2, ...<int>[3, 4]});
+
+ // Nested spreads.
+ Expect.setEquals(set, <int>{...<int>{...<int>[1, 2], ...<int>[3, 4]}});
+
+ // Null-aware.
+ List<int>? list23 = [2, 3];
+ List<int>? list4 = [4];
+ Expect.setEquals(set, <int>{1, ...?list23, ...?(null), ...?list4});
+
+ // Does not deep flatten.
+ var innerSet = <int>{3};
+ Expect.setEquals(<Object>{1, 2, innerSet, 4},
+ <Object>{1, ...<Object>[2, innerSet, 4]});
+
+ // Downcast element from dynamic.
+ Expect.setEquals(set, <int>{...<dynamic>[1, 2, 3, 4]});
+}
+
+void testDuplicateKeys() {
+ Expect.mapEquals(map, <int, int>{
+ 1: 1,
+ 2: 2,
+ ...<int, int>{2: 2, 3: 3, 4: 4},
+ ...<int, int>{3: 3},
+ 4: 4
+ });
+ Expect.setEquals(set, <int>{1, 2, ...<int>[1, 2, 3, 4], ...<int>[2, 3], 4});
+}
+
+void testKeyOrder() {
+ // First equal key wins.
+ var e1a = Equality(1, "a");
+ var e1b = Equality(1, "b");
+ var e2a = Equality(2, "a");
+ var e2b = Equality(2, "b");
+
+ var map = <Equality, int>{e1a: 1, ...<Equality, int>{e1b: 2, e2a: 3, e2b: 4}};
+ Expect.equals("1:a,2:a", map.keys.join(","));
+
+ var set = <Equality>{e1a, ...<Equality>[e1b, e2a, e2b]};
+ Expect.equals("1:a,2:a", set.join(","));
+
+ // All elements are evaluated, left to right.
+ var transcript = <String>[];
+ T log<T>(T value) {
+ transcript.add(value.toString());
+ return value;
+ }
+
+ map = <Equality, int>{
+ log(e1a): log(1),
+ ...<Equality, int>{log(e1b): log(2), log(e2a): log(3), log(e2b): log(4)}
+ };
+ Expect.equals("1:a,1,1:b,2,2:a,3,2:b,4", transcript.join(","));
+
+ transcript.clear();
+ set = <Equality>{log(e1a), ...<Equality>[log(e1b), log(e2a), log(e2b)]};
+ Expect.equals("1:a,1:b,2:a,2:b", transcript.join(","));
+}
diff --git a/tests/language/spread_collections/syntax_error_test.dart b/tests/language/spread_collections/syntax_error_test.dart
new file mode 100644
index 0000000..825e5dd2
--- /dev/null
+++ b/tests/language/spread_collections/syntax_error_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void main() {
+ // Spread nothing.
+ var _ = [...]; //# 00: syntax error
+ var _ = [...?]; //# 01: syntax error
+ var _ = [...,]; //# 02: syntax error
+
+ // Use `...` in map entry.
+ var _ = {"a": ...{}}; //# 03: syntax error
+ var _ = {...{}: "b"}; //# 04: syntax error
+ var _ = {"a": ...?{}}; //# 05: syntax error
+ var _ = {...?{}: "b"}; //# 06: syntax error
+
+ // Treats `...?` as single token.
+ var _ = [... ?null]; //# 07: syntax error
+ var _ = {1: 2, ... ?null}; //# 08: syntax error
+}
diff --git a/tests/language/spread_collections/syntax_test.dart b/tests/language/spread_collections/syntax_test.dart
new file mode 100644
index 0000000..aa6a51f
--- /dev/null
+++ b/tests/language/spread_collections/syntax_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests syntax edge cases.
+import 'package:expect/expect.dart';
+
+void main() {
+ // Trailing comma.
+ Expect.listEquals([1, 2], [...[1, 2],]);
+ Expect.mapEquals({1: 1, 2: 2}, {...{1: 1, 2: 2},});
+ Expect.setEquals({1, 2}, {...{1, 2},});
+
+ // Precedence.
+ Expect.listEquals([1, 2, 3], [1, ...true ? [2] : [], 3]);
+ Expect.listEquals([1, 3], [1, ...?true ? null : [], 3]);
+
+ var a = [0];
+ Expect.listEquals([1, 2, 3], [1, ...a = [2], 3]);
+ List<int>? nullableA = [0];
+ Expect.listEquals([1, 3], [1, ...?nullableA = null, 3]);
+
+ var b = [2];
+ Expect.listEquals([1, 2, 3, 4], [1, ...b..add(3), 4]);
+ List<int>? nullableB = [2];
+ Expect.listEquals([1, 2, 3, 4], [1, ...?nullableB?..add(3), 4]);
+}
diff --git a/tests/language/spread_collections/type_error_test.dart b/tests/language/spread_collections/type_error_test.dart
new file mode 100644
index 0000000..ccfc61a
--- /dev/null
+++ b/tests/language/spread_collections/type_error_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void main() {
+ // Spread non-iterable or non-map.
+ var _ = [...(3)]; //# 00: compile-time error
+ var _ = <int, int>{...(3)}; //# 01: compile-time error
+ var _ = <int>{...(3)}; //# 02: compile-time error
+
+ // Object.
+ var _ = [...([] as Object)]; //# 03: compile-time error
+ var _ = <int, int>{...({} as Object)}; //# 04: compile-time error
+ var _ = <int>{...([] as Object)}; //# 05: compile-time error
+
+ // Wrong element type.
+ var _ = <int>[...<String>[]]; //# 06: compile-time error
+ var _ = <int, int>{...<String, int>{}}; //# 07: compile-time error
+ var _ = <int, int>{...<int, String>{}}; //# 08: compile-time error
+ var _ = <int>{...<String>[]}; //# 09: compile-time error
+
+ // Downcast element.
+ var _ = <int>[...<num>[1, 2]]); //# 10: compile-time error
+ var _ = <int, int>{...<num, num>{1: 1, 2: 2}}); //# 11: compile-time error
+ var _ = <int>{...<num>[1, 2]}); //# 12: compile-time error
+}
diff --git a/tests/language/spread_collections/unevaluated_test.dart b/tests/language/spread_collections/unevaluated_test.dart
new file mode 100644
index 0000000..62af46f
--- /dev/null
+++ b/tests/language/spread_collections/unevaluated_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the body of an if element with unevaluated condition can
+// contain a spread.
+// Regression test for https://github.com/dart-lang/sdk/issues/36812
+
+const b = bool.fromEnvironment("foo");
+
+main() {
+ const l1 = [1, 2, 3];
+ const l2 = [if (b) ...l1];
+ print(l2);
+}
diff --git a/tests/language/stack_trace/demangle_ctors_test.dart b/tests/language/stack_trace/demangle_ctors_test.dart
new file mode 100644
index 0000000..697ed12
--- /dev/null
+++ b/tests/language/stack_trace/demangle_ctors_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that stack traces are properly demangled in constructors (#28740).
+
+import "package:expect/expect.dart";
+
+class SomeClass {
+ SomeClass.namedConstructor() {
+ throw new Exception();
+ }
+
+ SomeClass() {
+ throw new Exception();
+ }
+
+ factory SomeClass.useFactory() {
+ throw new Exception();
+ }
+}
+
+class OnlyHasFactory {
+ factory OnlyHasFactory() {
+ throw new Exception();
+ }
+}
+
+void main() {
+ try {
+ new SomeClass();
+ } on Exception catch (e, st) {
+ final stString = st.toString();
+ Expect.isTrue(stString.contains("new SomeClass"));
+ Expect.isFalse(stString.contains("SomeClass."));
+ }
+
+ try {
+ new SomeClass.namedConstructor();
+ } on Exception catch (e, st) {
+ final stString = st.toString();
+ Expect.isTrue(stString.contains("new SomeClass.namedConstructor"));
+ }
+
+ try {
+ new OnlyHasFactory();
+ } on Exception catch (e, st) {
+ final stString = st.toString();
+ Expect.isTrue(stString.contains("new OnlyHasFactory"));
+ Expect.isFalse(stString.contains("OnlyHasFactory."));
+ }
+
+ try {
+ new SomeClass.useFactory();
+ } on Exception catch (e, st) {
+ final stString = st.toString();
+ Expect.isTrue(stString.contains("new SomeClass.useFactory"));
+ }
+}
diff --git a/tests/language/stack_trace/full1_test.dart b/tests/language/stack_trace/full1_test.dart
new file mode 100644
index 0000000..42963f2
--- /dev/null
+++ b/tests/language/stack_trace/full1_test.dart
@@ -0,0 +1,54 @@
+// (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+@pragma("vm:entry-point") // Prevents obfuscation
+void func1() {
+ throw new Exception("Test full stacktrace");
+}
+
+@pragma("vm:entry-point") // Prevents obfuscation
+void func2() {
+ func1();
+}
+
+@pragma("vm:entry-point") // Prevents obfuscation
+void func3() {
+ try {
+ func2();
+ } on Object catch (e, s) {
+ var fullTrace = s.toString();
+ Expect.isTrue(fullTrace.contains("func1"));
+ Expect.isTrue(fullTrace.contains("func2"));
+ Expect.isTrue(fullTrace.contains("func3"));
+ Expect.isTrue(fullTrace.contains("func4"));
+ Expect.isTrue(fullTrace.contains("func5"));
+ Expect.isTrue(fullTrace.contains("func6"));
+ Expect.isTrue(fullTrace.contains("main"));
+ }
+}
+
+@pragma("vm:entry-point") // Prevents obfuscation
+int func4() {
+ func3();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevents obfuscation
+int func5() {
+ func4();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevents obfuscation
+int func6() {
+ func5();
+ return 1;
+}
+
+main() {
+ var i = func6();
+ Expect.equals(1, i);
+}
diff --git a/tests/language/stack_trace/full2_test.dart b/tests/language/stack_trace/full2_test.dart
new file mode 100644
index 0000000..fc15d54
--- /dev/null
+++ b/tests/language/stack_trace/full2_test.dart
@@ -0,0 +1,75 @@
+// (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+void func1() {
+ throw new Exception("Test full stacktrace");
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+void func2() {
+ func1();
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+void func3() {
+ try {
+ func2();
+ } on Object catch (e, s) {
+ var fullTrace = s.toString();
+ Expect.isTrue(fullTrace.contains("func1"));
+ Expect.isTrue(fullTrace.contains("func2"));
+ Expect.isTrue(fullTrace.contains("func3"));
+ Expect.isTrue(fullTrace.contains("func4"));
+ Expect.isTrue(fullTrace.contains("func5"));
+ Expect.isTrue(fullTrace.contains("func6"));
+ Expect.isTrue(fullTrace.contains("func7"));
+ Expect.isTrue(fullTrace.contains("main"));
+
+ rethrow; // This is a rethrow.
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+int func4() {
+ func3();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+int func5() {
+ try {
+ func4();
+ } on Object catch (e, s) {
+ var fullTrace = s.toString();
+ Expect.isTrue(fullTrace.contains("func1"));
+ Expect.isTrue(fullTrace.contains("func2"));
+ Expect.isTrue(fullTrace.contains("func3"));
+ Expect.isTrue(fullTrace.contains("func4"));
+ Expect.isTrue(fullTrace.contains("func5"));
+ Expect.isTrue(fullTrace.contains("func6"));
+ Expect.isTrue(fullTrace.contains("func7"));
+ Expect.isTrue(fullTrace.contains("main"));
+ }
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+int func6() {
+ func5();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation.
+int func7() {
+ func6();
+ return 1;
+}
+
+main() {
+ var i = func7();
+ Expect.equals(1, i);
+}
diff --git a/tests/language/stack_trace/full3_test.dart b/tests/language/stack_trace/full3_test.dart
new file mode 100644
index 0000000..f6b28a3
--- /dev/null
+++ b/tests/language/stack_trace/full3_test.dart
@@ -0,0 +1,74 @@
+// (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+@pragma("vm:entry-point") // Prevent obfuscation
+void func1() {
+ throw new Exception("Test full stacktrace");
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+void func2() {
+ func1();
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+void func3() {
+ try {
+ func2();
+ } on Object catch (e, s) {
+ var fullTrace = s.toString();
+ Expect.isTrue(fullTrace.contains("func1"));
+ Expect.isTrue(fullTrace.contains("func2"));
+ Expect.isTrue(fullTrace.contains("func3"));
+ Expect.isTrue(fullTrace.contains("func4"));
+ Expect.isTrue(fullTrace.contains("func5"));
+ Expect.isTrue(fullTrace.contains("func6"));
+ Expect.isTrue(fullTrace.contains("func7"));
+ Expect.isTrue(fullTrace.contains("main"));
+ throw new Exception("This is not a rethrow");
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+int func4() {
+ func3();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+int func5() {
+ try {
+ func4();
+ } on Object catch (e, s) {
+ var fullTrace = s.toString();
+ Expect.isFalse(fullTrace.contains("func1"));
+ Expect.isFalse(fullTrace.contains("func2"));
+ Expect.isTrue(fullTrace.contains("func3"));
+ Expect.isTrue(fullTrace.contains("func4"));
+ Expect.isTrue(fullTrace.contains("func5"));
+ Expect.isTrue(fullTrace.contains("func6"));
+ Expect.isTrue(fullTrace.contains("func7"));
+ Expect.isTrue(fullTrace.contains("main"));
+ }
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+int func6() {
+ func5();
+ return 1;
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+int func7() {
+ func6();
+ return 1;
+}
+
+main() {
+ var i = func7();
+ Expect.equals(1, i);
+}
diff --git a/tests/language/stack_trace/rethrow_error_test.dart b/tests/language/stack_trace/rethrow_error_test.dart
new file mode 100644
index 0000000..ae1f042
--- /dev/null
+++ b/tests/language/stack_trace/rethrow_error_test.dart
@@ -0,0 +1,182 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class SubclassOfError extends Error {}
+
+fail() => throw "Fail";
+
+// == Rethrow, skipping through typed handlers. ==
+
+@pragma("vm:entry-point") // Prevent obfuscation
+aa1() {
+ try {
+ bb1();
+ fail();
+ } catch (error
+ , stacktrace // //# withtraceparameter: ok
+ ) {
+ expectTrace(
+ ['gg1', 'ff1', 'ee1', 'dd1', 'cc1', 'bb1', 'aa1'],
+ (error as dynamic).stackTrace);
+ expectTrace(['gg1', 'ff1', 'ee1', 'dd1', 'cc1', 'bb1', 'aa1'], stacktrace); // //# withtraceparameter: continued
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+bb1() => cc1();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+cc1() {
+ try {
+ dd1();
+ } on String catch (e) {
+ fail();
+ } on int catch (e) {
+ fail();
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+dd1() => ee1();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ee1() {
+ try {
+ ff1();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ff1() => gg1();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+gg1() => throw new SubclassOfError();
+
+// == Rethrow, rethrow again in typed handler. ==
+
+@pragma("vm:entry-point") // Prevent obfuscation
+aa2() {
+ try {
+ bb2();
+ fail();
+ } catch (error
+ , stacktrace // //# withtraceparameter: continued
+ ) {
+ expectTrace(
+ ['gg2', 'ff2', 'ee2', 'dd2', 'cc2', 'bb2', 'aa2'],
+ (error as dynamic).stackTrace);
+ expectTrace(['gg2', 'ff2', 'ee2', 'dd2', 'cc2', 'bb2', 'aa2'], stacktrace); // //# withtraceparameter: continued
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+bb2() => cc2();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+cc2() {
+ try {
+ dd2();
+ } on SubclassOfError catch (e) {
+ rethrow;
+ } on int catch (e) {
+ fail();
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+dd2() => ee2();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ee2() {
+ try {
+ ff2();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ff2() => gg2();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+gg2() => throw new SubclassOfError();
+
+// == Rethrow, with intervening catch without a trace parameter.
+
+@pragma("vm:entry-point") // Prevent obfuscation
+aa3() {
+ try {
+ bb3();
+ fail();
+ } catch (error
+ , stacktrace // //# withtraceparameter: continued
+ ) {
+ expectTrace(
+ ['gg3', 'ff3', 'ee3', 'dd3', 'cc3', 'bb3', 'aa3'],
+ (error as dynamic).stackTrace);
+ expectTrace(['cc3', 'bb3', 'aa3'], stacktrace); // //# withtraceparameter: continued
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+bb3() => cc3();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+cc3() {
+ try {
+ dd3();
+ } catch (e) {
+ throw e;
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+dd3() => ee3();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ee3() {
+ try {
+ ff3();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point") // Prevent obfuscation
+ff3() => gg3();
+
+@pragma("vm:entry-point") // Prevent obfuscation
+gg3() => throw new SubclassOfError();
+
+expectTrace(functionNames, stacktrace) {
+ // Note we don't expect functionNames to cover the whole trace, only the
+ // top portion, because the frames below main are an implementation detail.
+ var traceLines = stacktrace.toString().split('\n');
+ var expectedIndex = 0;
+ var actualIndex = 0;
+ print(stacktrace);
+ print(functionNames);
+ while (expectedIndex < functionNames.length) {
+ var expected = functionNames[expectedIndex];
+ var actual = traceLines[actualIndex];
+ if (actual.indexOf(expected) == -1) {
+ if (expectedIndex == 0) {
+ actualIndex++; // Skip over some helper frames at the top
+ } else {
+ throw "Expected: $expected actual: $actual";
+ }
+ } else {
+ actualIndex++;
+ expectedIndex++;
+ }
+ }
+}
+
+main() {
+ aa1();
+ aa2();
+ aa3();
+}
diff --git a/tests/language/stack_trace/rethrow_nonerror_test.dart b/tests/language/stack_trace/rethrow_nonerror_test.dart
new file mode 100644
index 0000000..304d591
--- /dev/null
+++ b/tests/language/stack_trace/rethrow_nonerror_test.dart
@@ -0,0 +1,167 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class NotASubclassOfError {}
+
+fail() => throw "Fail";
+
+// == Rethrow, skipping through typed handlers. ==
+
+@pragma("vm:entry-point")
+aa1() {
+ try {
+ bb1();
+ fail();
+ } catch (exception, stacktrace) {
+ expectTrace(['gg1', 'ff1', 'ee1', 'dd1', 'cc1', 'bb1', 'aa1'], stacktrace);
+ }
+}
+
+@pragma("vm:entry-point")
+bb1() => cc1();
+
+@pragma("vm:entry-point")
+cc1() {
+ try {
+ dd1();
+ } on String catch (e) {
+ fail();
+ } on int catch (e) {
+ fail();
+ }
+}
+
+@pragma("vm:entry-point")
+dd1() => ee1();
+
+@pragma("vm:entry-point")
+ee1() {
+ try {
+ ff1();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point")
+ff1() => gg1();
+
+@pragma("vm:entry-point")
+gg1() => throw new NotASubclassOfError();
+
+// == Rethrow, rethrow again in typed handler. ==
+
+@pragma("vm:entry-point")
+aa2() {
+ try {
+ bb2();
+ fail();
+ } catch (exception, stacktrace) {
+ expectTrace(['gg2', 'ff2', 'ee2', 'dd2', 'cc2', 'bb2', 'aa2'], stacktrace);
+ }
+}
+
+@pragma("vm:entry-point")
+bb2() => cc2();
+
+@pragma("vm:entry-point")
+cc2() {
+ try {
+ dd2();
+ } on NotASubclassOfError catch (e) {
+ rethrow;
+ } on int catch (e) {
+ fail();
+ }
+}
+
+@pragma("vm:entry-point")
+dd2() => ee2();
+
+@pragma("vm:entry-point")
+ee2() {
+ try {
+ ff2();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point")
+ff2() => gg2();
+
+@pragma("vm:entry-point")
+gg2() => throw new NotASubclassOfError();
+
+// == Rethrow, with intervening catch without a trace parameter.
+
+@pragma("vm:entry-point")
+aa3() {
+ try {
+ bb3();
+ fail();
+ } catch (exception, stacktrace) {
+ expectTrace(['cc3', 'bb3', 'aa3'], stacktrace);
+ }
+}
+
+@pragma("vm:entry-point")
+bb3() => cc3();
+
+@pragma("vm:entry-point")
+cc3() {
+ try {
+ dd3();
+ } catch (e) {
+ throw e;
+ }
+}
+
+@pragma("vm:entry-point")
+dd3() => ee3();
+
+@pragma("vm:entry-point")
+ee3() {
+ try {
+ ff3();
+ } catch (e) {
+ rethrow;
+ }
+}
+
+@pragma("vm:entry-point")
+ff3() => gg3();
+
+@pragma("vm:entry-point")
+gg3() => throw new NotASubclassOfError();
+
+expectTrace(functionNames, stacktrace) {
+ // Note we don't expect functionNames to cover the whole trace, only the
+ // top portion, because the frames below main are an implementation detail.
+ var traceLines = stacktrace.toString().split('\n');
+ var expectedIndex = 0;
+ var actualIndex = 0;
+ print(stacktrace);
+ print(functionNames);
+ while (expectedIndex < functionNames.length) {
+ var expected = functionNames[expectedIndex];
+ var actual = traceLines[actualIndex];
+ if (actual.indexOf(expected) == -1) {
+ if (expectedIndex == 0) {
+ actualIndex++; // Skip over some helper frames at the top
+ } else {
+ throw "Expected: $expected actual: $actual";
+ }
+ } else {
+ actualIndex++;
+ expectedIndex++;
+ }
+ }
+}
+
+main() {
+ aa1();
+ aa2();
+ aa3();
+}
diff --git a/tests/language/stack_trace/stack_trace_test.dart b/tests/language/stack_trace/stack_trace_test.dart
new file mode 100644
index 0000000..5e4d7c6
--- /dev/null
+++ b/tests/language/stack_trace/stack_trace_test.dart
@@ -0,0 +1,138 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program for testing throw statement
+
+import "package:expect/expect.dart";
+
+class MyException {
+ const MyException(String message) : message_ = message;
+ final String message_;
+}
+
+class Helper {
+ static int f1(int i) {
+ try {
+ i = func();
+ i = 10;
+ } on MyException catch (exception, stacktrace) {
+ i = 50;
+ print(exception.message_);
+ Expect.isNotNull(stacktrace);
+ print(stacktrace);
+ }
+ try {
+ int j;
+ i = func1();
+ i = 200;
+ } on MyException catch (exception, stacktrace) {
+ i = 50;
+ print(exception.message_);
+ Expect.isNotNull(stacktrace);
+ print(stacktrace);
+ }
+ try {
+ int j;
+ i = func2();
+ i = 200;
+ } on MyException catch (exception, stacktrace) {
+ i = 50;
+ print(exception.message_);
+ Expect.isNotNull(stacktrace);
+ print(stacktrace);
+ } finally {
+ i = i + 800;
+ }
+ return i;
+ }
+
+ static int func() {
+ int i = 0;
+ while (i < 10) {
+ i++;
+ }
+ if (i > 0) {
+ throw new MyException("Exception Test for stack trace being printed");
+ }
+ return 10;
+ }
+
+ static int func1() {
+ try {
+ func();
+ } on MyException catch (exception) {
+ throw new MyException("Exception Test for stack trace being printed");
+ ;
+ }
+ return 10;
+ }
+
+ static int func2() {
+ try {
+ func();
+ } on MyException catch (exception) {
+ rethrow;
+ }
+ return 10;
+ }
+}
+
+class StackTraceTest {
+ static testMain() {
+ Expect.equals(850, Helper.f1(1));
+ }
+}
+
+// Test that the full stack trace is generated for rethrow.
+class RethrowStacktraceTest {
+ var config = 0;
+
+ @pragma("vm:entry-point") // Prevent obfuscation
+ issue12940() {
+ throw "Progy";
+ }
+
+ b() {
+ issue12940();
+ }
+
+ c() {
+ if (config == 0) {
+ try {
+ b();
+ } catch (e) {
+ rethrow;
+ }
+ } else {
+ try {
+ b();
+ } catch (e, s) {
+ rethrow;
+ }
+ }
+ }
+
+ d() {
+ c();
+ }
+
+ testBoth() {
+ for (config = 0; config < 2; config++) {
+ try {
+ d();
+ } catch (e, s) {
+ Expect.isTrue(s.toString().contains("issue12940"));
+ }
+ }
+ }
+
+ static testMain() {
+ var test = new RethrowStacktraceTest();
+ test.testBoth();
+ }
+}
+
+main() {
+ StackTraceTest.testMain();
+ RethrowStacktraceTest.testMain();
+}
diff --git a/tests/language/string/adjacent_const_string_literals_test.dart b/tests/language/string/adjacent_const_string_literals_test.dart
new file mode 100644
index 0000000..0af09ba
--- /dev/null
+++ b/tests/language/string/adjacent_const_string_literals_test.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class Conster {
+ const Conster(this.value);
+
+ final value;
+
+ toString() {
+ return value.toString();
+ }
+}
+
+main() {
+ testEmpty();
+ testInterpolation();
+ testMultiline();
+}
+
+testEmpty() {
+ Expect.equals("", (const Conster("" "" "")).toString());
+ Expect.equals("", (const Conster("" '' "")).toString());
+ Expect.equals("", (const Conster("" "" r"")).toString());
+
+ Expect.equals("a", (const Conster("a" "")).toString());
+ Expect.equals("a", (const Conster("a" '')).toString());
+ Expect.equals("a", (const Conster("a" r'')).toString());
+
+ Expect.equals("b", (const Conster('b' "")).toString());
+ Expect.equals("b", (const Conster('b' '')).toString());
+ Expect.equals("b", (const Conster('b' r'')).toString());
+
+ Expect.equals("c", (const Conster(r'c' "")).toString());
+ Expect.equals("c", (const Conster(r'c' '')).toString());
+ Expect.equals("c", (const Conster(r'c' r'')).toString());
+
+ Expect.equals("a", (const Conster("" "a")).toString());
+ Expect.equals("a", (const Conster("" 'a')).toString());
+ Expect.equals("a", (const Conster("" r'a')).toString());
+
+ Expect.equals("b", (const Conster('' "b")).toString());
+ Expect.equals("b", (const Conster('' 'b')).toString());
+ Expect.equals("b", (const Conster('' r'b')).toString());
+
+ Expect.equals("c", (const Conster(r'' "c")).toString());
+ Expect.equals("c", (const Conster(r'' 'c')).toString());
+ Expect.equals("c", (const Conster(r'' r'c')).toString());
+}
+
+const s = "a";
+
+testInterpolation() {
+ Expect.equals(r"ab", (const Conster("$s" "b")).toString());
+ Expect.equals(r"ab", (const Conster('$s' "b")).toString());
+ Expect.equals(r"$sb", (const Conster(r'$s' "b")).toString());
+
+ Expect.equals(r"-a-b", (const Conster("-$s-" "b")).toString());
+ Expect.equals(r"-a-b", (const Conster('-$s-' "b")).toString());
+ Expect.equals(r"-$s-b", (const Conster(r'-$s-' "b")).toString());
+
+ Expect.equals(r"ba", (const Conster('b' "$s")).toString());
+ Expect.equals(r"ba", (const Conster('b' '$s')).toString());
+ Expect.equals(r"b$s", (const Conster('b' r'$s')).toString());
+
+ Expect.equals(r"b-a-", (const Conster('b' "-$s-")).toString());
+ Expect.equals(r"b-a-", (const Conster('b' '-$s-')).toString());
+ Expect.equals(r"b-$s-", (const Conster('b' r'-$s-')).toString());
+}
+
+testMultiline() {
+ Expect.equals(
+ "abe",
+ (const Conster("a"
+ "b"
+ "e"))
+ .toString());
+ Expect.equals(
+ "a b e",
+ (const Conster("a "
+ "b "
+ "e"))
+ .toString());
+ Expect.equals(
+ "a b e",
+ (const Conster("a"
+ " b"
+ " e"))
+ .toString());
+
+ Expect.equals(
+ "abe",
+ (const Conster("""
+a"""
+ "b"
+ "e"))
+ .toString());
+ Expect.equals(
+ "a b e",
+ (const Conster("""
+a"""
+ " b"
+ " e"))
+ .toString());
+
+ Expect.equals(
+ "abe",
+ (const Conster("""
+a"""
+ """
+b"""
+ """
+e"""))
+ .toString());
+}
diff --git a/tests/language/string/adjacent_string_literals_test.dart b/tests/language/string/adjacent_string_literals_test.dart
new file mode 100644
index 0000000..48f8ba2
--- /dev/null
+++ b/tests/language/string/adjacent_string_literals_test.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+ testEmpty();
+ testInterpolation();
+ testMultiline();
+}
+
+testEmpty() {
+ Expect.equals("", "" "" "");
+ Expect.equals("", "" '' "");
+ Expect.equals("", "" "" r"");
+
+ Expect.equals("a", "a" "");
+ Expect.equals("a", "a" '');
+ Expect.equals("a", "a" r'');
+
+ Expect.equals("b", 'b' "");
+ Expect.equals("b", 'b' '');
+ Expect.equals("b", 'b' r'');
+
+ Expect.equals("c", r'c' "");
+ Expect.equals("c", r'c' '');
+ Expect.equals("c", r'c' r'');
+
+ Expect.equals("a", "" "a");
+ Expect.equals("a", "" 'a');
+ Expect.equals("a", "" r'a');
+
+ Expect.equals("b", '' "b");
+ Expect.equals("b", '' 'b');
+ Expect.equals("b", '' r'b');
+
+ Expect.equals("c", r'' "c");
+ Expect.equals("c", r'' 'c');
+ Expect.equals("c", r'' r'c');
+}
+
+testInterpolation() {
+ var s = "a";
+ Expect.equals(r"ab", "$s" "b");
+ Expect.equals(r"ab", '$s' "b");
+ Expect.equals(r"$sb", r'$s' "b");
+
+ Expect.equals(r"-a-b", "-$s-" "b");
+ Expect.equals(r"-a-b", '-$s-' "b");
+ Expect.equals(r"-$s-b", r'-$s-' "b");
+
+ Expect.equals(r"ba", 'b' "$s");
+ Expect.equals(r"ba", 'b' '$s');
+ Expect.equals(r"b$s", 'b' r'$s');
+
+ Expect.equals(r"b-a-", 'b' "-$s-");
+ Expect.equals(r"b-a-", 'b' '-$s-');
+ Expect.equals(r"b-$s-", 'b' r'-$s-');
+}
+
+testMultiline() {
+ Expect.equals(
+ "abe",
+ "a"
+ "b"
+ "e");
+ Expect.equals(
+ "a b e",
+ "a "
+ "b "
+ "e");
+ Expect.equals(
+ "a b e",
+ "a"
+ " b"
+ " e");
+
+ Expect.equals(
+ "abe",
+ """
+a"""
+ "b"
+ "e");
+ Expect.equals(
+ "a b e",
+ """
+a"""
+ " b"
+ " e");
+
+ Expect.equals(
+ "abe",
+ """
+a"""
+ """
+b"""
+ """
+e""");
+}
diff --git a/tests/language/string/bad_raw_string_runtime_test.dart b/tests/language/string/bad_raw_string_runtime_test.dart
new file mode 100644
index 0000000..4046aa5
--- /dev/null
+++ b/tests/language/string/bad_raw_string_runtime_test.dart
@@ -0,0 +1,26 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ // Raw String may not contain newline (may not be multi-line).
+ String x = ''
+
+
+
+
+ // Test that a raw string containing just one character, a \n char, fails.
+ // Enclose the test string in a bigger multiline string, except in case 03:
+
+ """
+
+ r'
+'
+
+ """
+
+ ;
+}
diff --git a/tests/language/string/bad_raw_string_test.dart b/tests/language/string/bad_raw_string_test.dart
new file mode 100644
index 0000000..7091ebae
--- /dev/null
+++ b/tests/language/string/bad_raw_string_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ // Raw String may not contain newline (may not be multi-line).
+ String x = ''
+ r'
+// ^
+// [cfe] String starting with r' must end with '.
+// ^
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+'
+// [error line 13, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+// [cfe] String starting with ' must end with '.
+ r"
+// ^
+// [cfe] String starting with r" must end with ".
+// ^
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+"
+// [error line 22, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+// [cfe] String starting with " must end with ".
+
+ // Test that a raw string containing just one character, a \n char, fails.
+ // Enclose the test string in a bigger multiline string, except in case 03:
+ '''
+ """
+ '''
+ r'
+// ^
+// [cfe] String starting with r' must end with '.
+// ^
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+'
+// [error line 37, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+// [cfe] String starting with ' must end with '.
+ '''
+ """
+ '''
+ ;
+}
diff --git a/tests/language/string/char_escape_test.dart b/tests/language/string/char_escape_test.dart
new file mode 100644
index 0000000..7b87fbe
--- /dev/null
+++ b/tests/language/string/char_escape_test.dart
@@ -0,0 +1,533 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for reading escape sequences in string literals
+
+import "package:expect/expect.dart";
+
+class CharEscapeTest {
+ static testMain() {
+ var x00 = "\x00";
+ var u0000 = "\u0000";
+ var v0 = "\u{0}";
+ var v00 = "\u{00}";
+ var v000 = "\u{000}";
+ var v0000 = "\u{0000}";
+ var v00000 = "\u{00000}";
+ var v000000 = "\u{000000}";
+ Expect.equals(1, x00.length);
+ Expect.equals(1, u0000.length);
+ Expect.equals(1, v0.length);
+ Expect.equals(1, v00.length);
+ Expect.equals(1, v000.length);
+ Expect.equals(1, v0000.length);
+ Expect.equals(1, v00000.length);
+ Expect.equals(1, v000000.length);
+ Expect.equals(0, x00.codeUnitAt(0));
+ Expect.equals(0, u0000.codeUnitAt(0));
+ Expect.equals(0, v0.codeUnitAt(0));
+ Expect.equals(0, v00.codeUnitAt(0));
+ Expect.equals(0, v000.codeUnitAt(0));
+ Expect.equals(0, v0000.codeUnitAt(0));
+ Expect.equals(0, v00000.codeUnitAt(0));
+ Expect.equals(0, v000000.codeUnitAt(0));
+ Expect.equals("\x00", new String.fromCharCodes([0]));
+ Expect.equals("\u0000", new String.fromCharCodes([0]));
+ Expect.equals("\u{0}", new String.fromCharCodes([0]));
+ Expect.equals("\u{00}", new String.fromCharCodes([0]));
+ Expect.equals("\u{000}", new String.fromCharCodes([0]));
+ Expect.equals("\u{0000}", new String.fromCharCodes([0]));
+ Expect.equals("\u{00000}", new String.fromCharCodes([0]));
+ Expect.equals("\u{000000}", new String.fromCharCodes([0]));
+
+ var x01 = "\x01";
+ var u0001 = "\u0001";
+ var v1 = "\u{1}";
+ var v01 = "\u{01}";
+ var v001 = "\u{001}";
+ var v0001 = "\u{0001}";
+ var v00001 = "\u{00001}";
+ var v000001 = "\u{000001}";
+ Expect.equals(1, x01.length);
+ Expect.equals(1, u0001.length);
+ Expect.equals(1, v1.length);
+ Expect.equals(1, v01.length);
+ Expect.equals(1, v001.length);
+ Expect.equals(1, v0001.length);
+ Expect.equals(1, v00001.length);
+ Expect.equals(1, v000001.length);
+ Expect.equals(1, x01.codeUnitAt(0));
+ Expect.equals(1, u0001.codeUnitAt(0));
+ Expect.equals(1, v1.codeUnitAt(0));
+ Expect.equals(1, v01.codeUnitAt(0));
+ Expect.equals(1, v001.codeUnitAt(0));
+ Expect.equals(1, v0001.codeUnitAt(0));
+ Expect.equals(1, v00001.codeUnitAt(0));
+ Expect.equals(1, v000001.codeUnitAt(0));
+ Expect.equals("\x01", new String.fromCharCodes([1]));
+ Expect.equals("\u0001", new String.fromCharCodes([1]));
+ Expect.equals("\u{1}", new String.fromCharCodes([1]));
+ Expect.equals("\u{01}", new String.fromCharCodes([1]));
+ Expect.equals("\u{001}", new String.fromCharCodes([1]));
+ Expect.equals("\u{0001}", new String.fromCharCodes([1]));
+ Expect.equals("\u{00001}", new String.fromCharCodes([1]));
+ Expect.equals("\u{000001}", new String.fromCharCodes([1]));
+
+ var x55 = "\x55";
+ var u0055 = "\u0055";
+ var v55 = "\u{55}";
+ var v055 = "\u{055}";
+ var v0055 = "\u{0055}";
+ var v00055 = "\u{00055}";
+ var v000055 = "\u{000055}";
+ Expect.equals(1, x55.length);
+ Expect.equals(1, u0055.length);
+ Expect.equals(1, v55.length);
+ Expect.equals(1, v055.length);
+ Expect.equals(1, v0055.length);
+ Expect.equals(1, v00055.length);
+ Expect.equals(1, v000055.length);
+ Expect.equals(0x55, x55.codeUnitAt(0));
+ Expect.equals(0x55, u0055.codeUnitAt(0));
+ Expect.equals(0x55, v55.codeUnitAt(0));
+ Expect.equals(0x55, v055.codeUnitAt(0));
+ Expect.equals(0x55, v0055.codeUnitAt(0));
+ Expect.equals(0x55, v00055.codeUnitAt(0));
+ Expect.equals(0x55, v000055.codeUnitAt(0));
+ Expect.equals("\x55", new String.fromCharCodes([0x55]));
+ Expect.equals("\u0055", new String.fromCharCodes([0x55]));
+ Expect.equals("\u{55}", new String.fromCharCodes([0x55]));
+ Expect.equals("\u{055}", new String.fromCharCodes([0x55]));
+ Expect.equals("\u{0055}", new String.fromCharCodes([0x55]));
+ Expect.equals("\u{00055}", new String.fromCharCodes([0x55]));
+ Expect.equals("\u{000055}", new String.fromCharCodes([0x55]));
+
+ var x7F = "\x7F";
+ var u007F = "\u007F";
+ var v7F = "\u{7F}";
+ var v07F = "\u{07F}";
+ var v007F = "\u{007F}";
+ var v0007F = "\u{0007F}";
+ var v00007F = "\u{00007F}";
+ Expect.equals(1, x7F.length);
+ Expect.equals(1, u007F.length);
+ Expect.equals(1, v7F.length);
+ Expect.equals(1, v07F.length);
+ Expect.equals(1, v007F.length);
+ Expect.equals(1, v0007F.length);
+ Expect.equals(1, v00007F.length);
+ Expect.equals(0x7F, x7F.codeUnitAt(0));
+ Expect.equals(0x7F, u007F.codeUnitAt(0));
+ Expect.equals(0x7F, v7F.codeUnitAt(0));
+ Expect.equals(0x7F, v07F.codeUnitAt(0));
+ Expect.equals(0x7F, v007F.codeUnitAt(0));
+ Expect.equals(0x7F, v0007F.codeUnitAt(0));
+ Expect.equals(0x7F, v00007F.codeUnitAt(0));
+ Expect.equals("\x7F", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u007F", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u{7F}", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u{07F}", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u{007F}", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u{0007F}", new String.fromCharCodes([0x7F]));
+ Expect.equals("\u{00007F}", new String.fromCharCodes([0x7F]));
+
+ var x80 = "\x80";
+ var u0080 = "\u0080";
+ var v80 = "\u{80}";
+ var v080 = "\u{080}";
+ var v0080 = "\u{0080}";
+ var v00080 = "\u{00080}";
+ var v000080 = "\u{000080}";
+ Expect.equals(1, x80.length);
+ Expect.equals(1, u0080.length);
+ Expect.equals(1, v80.length);
+ Expect.equals(1, v080.length);
+ Expect.equals(1, v0080.length);
+ Expect.equals(1, v00080.length);
+ Expect.equals(1, v000080.length);
+ Expect.equals(0x80, x80.codeUnitAt(0));
+ Expect.equals(0x80, u0080.codeUnitAt(0));
+ Expect.equals(0x80, v80.codeUnitAt(0));
+ Expect.equals(0x80, v080.codeUnitAt(0));
+ Expect.equals(0x80, v0080.codeUnitAt(0));
+ Expect.equals(0x80, v00080.codeUnitAt(0));
+ Expect.equals(0x80, v000080.codeUnitAt(0));
+ Expect.equals("\x80", new String.fromCharCodes([0x80]));
+ Expect.equals("\u0080", new String.fromCharCodes([0x80]));
+ Expect.equals("\u{80}", new String.fromCharCodes([0x80]));
+ Expect.equals("\u{080}", new String.fromCharCodes([0x80]));
+ Expect.equals("\u{0080}", new String.fromCharCodes([0x80]));
+ Expect.equals("\u{00080}", new String.fromCharCodes([0x80]));
+ Expect.equals("\u{000080}", new String.fromCharCodes([0x80]));
+
+ var xAA = "\xAA";
+ var u00AA = "\u00AA";
+ var vAA = "\u{AA}";
+ var v0AA = "\u{0AA}";
+ var v00AA = "\u{00AA}";
+ var v000AA = "\u{000AA}";
+ var v0000AA = "\u{0000AA}";
+ Expect.equals(1, xAA.length);
+ Expect.equals(1, u00AA.length);
+ Expect.equals(1, vAA.length);
+ Expect.equals(1, v0AA.length);
+ Expect.equals(1, v00AA.length);
+ Expect.equals(1, v000AA.length);
+ Expect.equals(1, v0000AA.length);
+ Expect.equals(0xAA, xAA.codeUnitAt(0));
+ Expect.equals(0xAA, u00AA.codeUnitAt(0));
+ Expect.equals(0xAA, vAA.codeUnitAt(0));
+ Expect.equals(0xAA, v0AA.codeUnitAt(0));
+ Expect.equals(0xAA, v00AA.codeUnitAt(0));
+ Expect.equals(0xAA, v000AA.codeUnitAt(0));
+ Expect.equals(0xAA, v0000AA.codeUnitAt(0));
+ Expect.equals("\xAA", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u00AA", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u{AA}", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u{0AA}", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u{00AA}", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u{000AA}", new String.fromCharCodes([0xAA]));
+ Expect.equals("\u{0000AA}", new String.fromCharCodes([0xAA]));
+
+ var xFE = "\xFE";
+ var u00FE = "\u00FE";
+ var vFE = "\u{FE}";
+ var v0FE = "\u{0FE}";
+ var v00FE = "\u{00FE}";
+ var v000FE = "\u{000FE}";
+ var v0000FE = "\u{0000FE}";
+ Expect.equals(1, xFE.length);
+ Expect.equals(1, u00FE.length);
+ Expect.equals(1, vFE.length);
+ Expect.equals(1, v0FE.length);
+ Expect.equals(1, v00FE.length);
+ Expect.equals(1, v000FE.length);
+ Expect.equals(1, v0000FE.length);
+ Expect.equals(0xFE, xFE.codeUnitAt(0));
+ Expect.equals(0xFE, u00FE.codeUnitAt(0));
+ Expect.equals(0xFE, vFE.codeUnitAt(0));
+ Expect.equals(0xFE, v0FE.codeUnitAt(0));
+ Expect.equals(0xFE, v00FE.codeUnitAt(0));
+ Expect.equals(0xFE, v000FE.codeUnitAt(0));
+ Expect.equals(0xFE, v0000FE.codeUnitAt(0));
+ Expect.equals("\xFE", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u00FE", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u{FE}", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u{0FE}", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u{00FE}", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u{000FE}", new String.fromCharCodes([0xFE]));
+ Expect.equals("\u{0000FE}", new String.fromCharCodes([0xFE]));
+
+ var xFF = "\xFF";
+ var u00FF = "\u00FF";
+ var vFF = "\u{FF}";
+ var v0FF = "\u{0FF}";
+ var v00FF = "\u{00FF}";
+ var v000FF = "\u{000FF}";
+ var v0000FF = "\u{0000FF}";
+ Expect.equals(1, xFF.length);
+ Expect.equals(1, u00FF.length);
+ Expect.equals(1, vFF.length);
+ Expect.equals(1, v0FF.length);
+ Expect.equals(1, v00FF.length);
+ Expect.equals(1, v000FF.length);
+ Expect.equals(1, v0000FF.length);
+ Expect.equals(0xFF, xFF.codeUnitAt(0));
+ Expect.equals(0xFF, u00FF.codeUnitAt(0));
+ Expect.equals(0xFF, vFF.codeUnitAt(0));
+ Expect.equals(0xFF, v0FF.codeUnitAt(0));
+ Expect.equals(0xFF, v00FF.codeUnitAt(0));
+ Expect.equals(0xFF, v000FF.codeUnitAt(0));
+ Expect.equals(0xFF, v0000FF.codeUnitAt(0));
+ Expect.equals("\xFF", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u00FF", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u{FF}", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u{0FF}", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u{00FF}", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u{000FF}", new String.fromCharCodes([0xFF]));
+ Expect.equals("\u{0000FF}", new String.fromCharCodes([0xFF]));
+
+ var u1000 = "\u1000";
+ var v1000 = "\u{1000}";
+ var v01000 = "\u{01000}";
+ var v001000 = "\u{001000}";
+ Expect.equals(1, u1000.length);
+ Expect.equals(1, v1000.length);
+ Expect.equals(1, v01000.length);
+ Expect.equals(1, v001000.length);
+ Expect.equals(0x1000, u1000.codeUnitAt(0));
+ Expect.equals(0x1000, v1000.codeUnitAt(0));
+ Expect.equals(0x1000, v01000.codeUnitAt(0));
+ Expect.equals(0x1000, v001000.codeUnitAt(0));
+ Expect.equals("\u1000", new String.fromCharCodes([0x1000]));
+ Expect.equals("\u{1000}", new String.fromCharCodes([0x1000]));
+ Expect.equals("\u{01000}", new String.fromCharCodes([0x1000]));
+ Expect.equals("\u{001000}", new String.fromCharCodes([0x1000]));
+
+ var u5555 = "\u5555";
+ var v5555 = "\u{5555}";
+ var v05555 = "\u{05555}";
+ var v005555 = "\u{005555}";
+ Expect.equals(1, u5555.length);
+ Expect.equals(1, v5555.length);
+ Expect.equals(1, v05555.length);
+ Expect.equals(1, v005555.length);
+ Expect.equals(0x5555, u5555.codeUnitAt(0));
+ Expect.equals(0x5555, v5555.codeUnitAt(0));
+ Expect.equals(0x5555, v05555.codeUnitAt(0));
+ Expect.equals(0x5555, v005555.codeUnitAt(0));
+ Expect.equals("\u5555", new String.fromCharCodes([0x5555]));
+ Expect.equals("\u{5555}", new String.fromCharCodes([0x5555]));
+ Expect.equals("\u{05555}", new String.fromCharCodes([0x5555]));
+ Expect.equals("\u{005555}", new String.fromCharCodes([0x5555]));
+
+ var u7FFF = "\u7FFF";
+ var v7FFF = "\u{7FFF}";
+ var v07FFF = "\u{07FFF}";
+ var v007FFF = "\u{007FFF}";
+ Expect.equals(1, u7FFF.length);
+ Expect.equals(1, v7FFF.length);
+ Expect.equals(1, v07FFF.length);
+ Expect.equals(1, v007FFF.length);
+ Expect.equals(0x7FFF, u7FFF.codeUnitAt(0));
+ Expect.equals(0x7FFF, v7FFF.codeUnitAt(0));
+ Expect.equals(0x7FFF, v07FFF.codeUnitAt(0));
+ Expect.equals(0x7FFF, v007FFF.codeUnitAt(0));
+ Expect.equals("\u7FFF", new String.fromCharCodes([0x7FFF]));
+ Expect.equals("\u{7FFF}", new String.fromCharCodes([0x7FFF]));
+ Expect.equals("\u{07FFF}", new String.fromCharCodes([0x7FFF]));
+ Expect.equals("\u{007FFF}", new String.fromCharCodes([0x7FFF]));
+
+ var u8000 = "\u8000";
+ var v8000 = "\u{8000}";
+ var v08000 = "\u{08000}";
+ var v008000 = "\u{008000}";
+ Expect.equals(1, u8000.length);
+ Expect.equals(1, v8000.length);
+ Expect.equals(1, v08000.length);
+ Expect.equals(1, v008000.length);
+ Expect.equals(0x8000, u8000.codeUnitAt(0));
+ Expect.equals(0x8000, v8000.codeUnitAt(0));
+ Expect.equals(0x8000, v08000.codeUnitAt(0));
+ Expect.equals(0x8000, v008000.codeUnitAt(0));
+ Expect.equals("\u8000", new String.fromCharCodes([0x8000]));
+ Expect.equals("\u{8000}", new String.fromCharCodes([0x8000]));
+ Expect.equals("\u{08000}", new String.fromCharCodes([0x8000]));
+ Expect.equals("\u{008000}", new String.fromCharCodes([0x8000]));
+
+ var uAAAA = "\uAAAA";
+ var vAAAA = "\u{AAAA}";
+ var v0AAAA = "\u{0AAAA}";
+ var v00AAAA = "\u{00AAAA}";
+ Expect.equals(1, uAAAA.length);
+ Expect.equals(1, vAAAA.length);
+ Expect.equals(1, v0AAAA.length);
+ Expect.equals(1, v00AAAA.length);
+ Expect.equals(0xAAAA, uAAAA.codeUnitAt(0));
+ Expect.equals(0xAAAA, vAAAA.codeUnitAt(0));
+ Expect.equals(0xAAAA, v0AAAA.codeUnitAt(0));
+ Expect.equals(0xAAAA, v00AAAA.codeUnitAt(0));
+ Expect.equals("\uAAAA", new String.fromCharCodes([0xAAAA]));
+ Expect.equals("\u{AAAA}", new String.fromCharCodes([0xAAAA]));
+ Expect.equals("\u{0AAAA}", new String.fromCharCodes([0xAAAA]));
+ Expect.equals("\u{00AAAA}", new String.fromCharCodes([0xAAAA]));
+
+ var uFFFE = "\uFFFE";
+ var vFFFE = "\u{FFFE}";
+ var v0FFFE = "\u{0FFFE}";
+ var v00FFFE = "\u{00FFFE}";
+ Expect.equals(1, uFFFE.length);
+ Expect.equals(1, vFFFE.length);
+ Expect.equals(1, v0FFFE.length);
+ Expect.equals(1, v00FFFE.length);
+ Expect.equals(0xFFFE, uFFFE.codeUnitAt(0));
+ Expect.equals(0xFFFE, vFFFE.codeUnitAt(0));
+ Expect.equals(0xFFFE, v0FFFE.codeUnitAt(0));
+ Expect.equals(0xFFFE, v00FFFE.codeUnitAt(0));
+ Expect.equals("\uFFFE", new String.fromCharCodes([0xFFFE]));
+ Expect.equals("\u{FFFE}", new String.fromCharCodes([0xFFFE]));
+ Expect.equals("\u{0FFFE}", new String.fromCharCodes([0xFFFE]));
+ Expect.equals("\u{00FFFE}", new String.fromCharCodes([0xFFFE]));
+
+ var uFFFF = "\uFFFF";
+ var vFFFF = "\u{FFFF}";
+ var v0FFFF = "\u{0FFFF}";
+ var v00FFFF = "\u{00FFFF}";
+ Expect.equals(1, uFFFF.length);
+ Expect.equals(1, vFFFF.length);
+ Expect.equals(1, v0FFFF.length);
+ Expect.equals(1, v00FFFF.length);
+ Expect.equals(0xFFFF, uFFFF.codeUnitAt(0));
+ Expect.equals(0xFFFF, vFFFF.codeUnitAt(0));
+ Expect.equals(0xFFFF, v0FFFF.codeUnitAt(0));
+ Expect.equals(0xFFFF, v00FFFF.codeUnitAt(0));
+ Expect.equals("\uFFFF", new String.fromCharCodes([0xFFFF]));
+ Expect.equals("\u{FFFF}", new String.fromCharCodes([0xFFFF]));
+ Expect.equals("\u{0FFFF}", new String.fromCharCodes([0xFFFF]));
+ Expect.equals("\u{00FFFF}", new String.fromCharCodes([0xFFFF]));
+
+ var v10000 = "\u{10000}";
+ var v010000 = "\u{010000}";
+ Expect.equals(2, v10000.length);
+ Expect.equals(2, v010000.length);
+ Expect.equals("\u{10000}", new String.fromCharCodes([0x10000]));
+ Expect.equals("\u{010000}", new String.fromCharCodes([0x10000]));
+
+ var v1FFFF = "\u{1FFFF}";
+ var v01FFFF = "\u{01FFFF}";
+ Expect.equals(2, v1FFFF.length);
+ Expect.equals(2, v01FFFF.length);
+ Expect.equals("\u{1FFFF}", new String.fromCharCodes([0x1FFFF]));
+ Expect.equals("\u{01FFFF}", new String.fromCharCodes([0x1FFFF]));
+
+ var v105555 = "\u{105555}";
+ Expect.equals(2, v105555.length);
+ Expect.equals("\u{105555}", new String.fromCharCodes([0x105555]));
+
+ var v10FFFF = "\u{10FFFF}";
+ Expect.equals(2, v10FFFF.length);
+ Expect.equals("\u{10FFFF}", new String.fromCharCodes([0x10FFFF]));
+
+ var bs = "\b";
+ Expect.isTrue(bs != "b");
+ Expect.equals(1, bs.length);
+ Expect.equals(0x08, bs.codeUnitAt(0));
+ Expect.equals(bs, new String.fromCharCodes([0x08]));
+ Expect.equals("\x08", bs);
+ Expect.equals("\u0008", bs);
+ Expect.equals("\u{8}", bs);
+ Expect.equals("\u{08}", bs);
+ Expect.equals("\u{008}", bs);
+ Expect.equals("\u{0008}", bs);
+ Expect.equals("\u{00008}", bs);
+ Expect.equals("\u{000008}", bs);
+
+ var ht = "\t";
+ Expect.isTrue(ht != "t");
+ Expect.equals(1, ht.length);
+ Expect.equals(0x09, ht.codeUnitAt(0));
+ Expect.equals(ht, new String.fromCharCodes([0x09]));
+ Expect.equals("\x09", ht);
+ Expect.equals("\u0009", ht);
+ Expect.equals("\u{9}", ht);
+ Expect.equals("\u{09}", ht);
+ Expect.equals("\u{009}", ht);
+ Expect.equals("\u{0009}", ht);
+ Expect.equals("\u{00009}", ht);
+ Expect.equals("\u{000009}", ht);
+
+ var lf = "\n";
+ Expect.isTrue(lf != "n");
+ Expect.equals(1, lf.length);
+ Expect.equals(0x0A, lf.codeUnitAt(0));
+ Expect.equals(lf, new String.fromCharCodes([0x0A]));
+ Expect.equals("\x0A", lf);
+ Expect.equals("\u000A", lf);
+ Expect.equals("\u{A}", lf);
+ Expect.equals("\u{0A}", lf);
+ Expect.equals("\u{00A}", lf);
+ Expect.equals("\u{000A}", lf);
+ Expect.equals("\u{0000A}", lf);
+ Expect.equals("\u{00000A}", lf);
+
+ var vt = "\v";
+ Expect.isTrue(vt != "v");
+ Expect.equals(1, vt.length);
+ Expect.equals(0x0B, vt.codeUnitAt(0));
+ Expect.equals(vt, new String.fromCharCodes([0x0B]));
+ Expect.equals("\x0B", vt);
+ Expect.equals("\u000B", vt);
+ Expect.equals("\u{B}", vt);
+ Expect.equals("\u{0B}", vt);
+ Expect.equals("\u{00B}", vt);
+ Expect.equals("\u{000B}", vt);
+ Expect.equals("\u{0000B}", vt);
+ Expect.equals("\u{00000B}", vt);
+
+ var ff = "\f";
+ Expect.isTrue(ff != "f");
+ Expect.equals(1, ff.length);
+ Expect.equals(0x0C, ff.codeUnitAt(0));
+ Expect.equals(ff, new String.fromCharCodes([0x0C]));
+ Expect.equals("\x0C", ff);
+ Expect.equals("\u000C", ff);
+ Expect.equals("\u{C}", ff);
+ Expect.equals("\u{0C}", ff);
+ Expect.equals("\u{00C}", ff);
+ Expect.equals("\u{000C}", ff);
+ Expect.equals("\u{0000C}", ff);
+ Expect.equals("\u{00000C}", ff);
+
+ var cr = "\r";
+ Expect.isTrue(cr != "r");
+ Expect.equals(1, cr.length);
+ Expect.equals(0x0D, cr.codeUnitAt(0));
+ Expect.equals(cr, new String.fromCharCodes([0x0D]));
+ Expect.equals("\x0D", cr);
+ Expect.equals("\u000D", cr);
+ Expect.equals("\u{D}", cr);
+ Expect.equals("\u{0D}", cr);
+ Expect.equals("\u{00D}", cr);
+ Expect.equals("\u{000D}", cr);
+ Expect.equals("\u{0000D}", cr);
+ Expect.equals("\u{00000D}", cr);
+
+ Expect.equals("\a", "a");
+ // \b U+0006 BS
+ Expect.equals("\c", "c");
+ Expect.equals("\d", "d");
+ Expect.equals("\e", "e");
+ // \f U+000C FF
+ Expect.equals("\g", "g");
+ Expect.equals("\h", "h");
+ Expect.equals("\i", "i");
+ Expect.equals("\j", "j");
+ Expect.equals("\k", "k");
+ Expect.equals("\l", "l");
+ Expect.equals("\m", "m");
+ // \n U+000A LF
+ Expect.equals("\o", "o");
+ Expect.equals("\p", "p");
+ Expect.equals("\q", "q");
+ // \r U+000D CR
+ Expect.equals("\s", "s");
+ // \t U+0009 HT
+ // \u code point escape
+ // \v U+000B VT
+ Expect.equals("\w", "w");
+ // \x code point escape
+ Expect.equals("\y", "y");
+ Expect.equals("\z", "z");
+
+ Expect.equals("\A", "A");
+ Expect.equals("\B", "B");
+ Expect.equals("\C", "C");
+ Expect.equals("\D", "D");
+ Expect.equals("\E", "E");
+ Expect.equals("\F", "F");
+ Expect.equals("\G", "G");
+ Expect.equals("\H", "H");
+ Expect.equals("\I", "I");
+ Expect.equals("\J", "J");
+ Expect.equals("\K", "K");
+ Expect.equals("\L", "L");
+ Expect.equals("\M", "M");
+ Expect.equals("\N", "N");
+ Expect.equals("\O", "O");
+ Expect.equals("\P", "P");
+ Expect.equals("\Q", "Q");
+ Expect.equals("\R", "R");
+ Expect.equals("\S", "S");
+ Expect.equals("\T", "T");
+ Expect.equals("\U", "U");
+ Expect.equals("\V", "V");
+ Expect.equals("\W", "W");
+ Expect.equals("\X", "X");
+ Expect.equals("\Y", "Y");
+ Expect.equals("\Z", "Z");
+ }
+}
+
+main() {
+ CharEscapeTest.testMain();
+}
diff --git a/tests/language/string/charcode_test.dart b/tests/language/string/charcode_test.dart
new file mode 100644
index 0000000..89061a4
--- /dev/null
+++ b/tests/language/string/charcode_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr
+
+import "package:expect/expect.dart";
+
+main() {
+ for (int i = 0; i < 20; i++) {
+ Expect.isTrue(moo("x"));
+ Expect.isFalse(moo("X"));
+ Expect.isFalse(moo("xx"));
+ Expect.isTrue(mooRev("x"));
+ Expect.isFalse(mooRev("X"));
+ Expect.isFalse(mooRev("xx"));
+ Expect.isTrue(goo("Hello", "e"));
+ Expect.isFalse(goo("Hello", "E"));
+ Expect.isFalse(goo("Hello", "ee"));
+ Expect.isTrue(gooRev("Hello", "e"));
+ Expect.isFalse(gooRev("Hello", "E"));
+ Expect.isFalse(gooRev("Hello", "ee"));
+ Expect.isTrue(hoo("HH"));
+ Expect.isFalse(hoo("Ha"));
+ Expect.isTrue(hooRev("HH"));
+ Expect.isFalse(hooRev("Ha"));
+ }
+ Expect.isFalse(moo(12));
+ Expect.isFalse(mooRev(12));
+ Expect.isTrue(goo([1, 2], 2));
+ Expect.isTrue(gooRev([1, 2], 2));
+ Expect.throwsRangeError(() => hoo("H"));
+ Expect.throwsRangeError(() => hooRev("H"));
+}
+
+moo(j) {
+ return "x" == j;
+}
+
+goo(a, j) {
+ return a[1] == j;
+}
+
+// Check constant folding.
+hoo(a) {
+ return a[1] == ("Hello")[0];
+}
+
+mooRev(j) {
+ return j == "x";
+}
+
+gooRev(a, j) {
+ return j == a[1];
+}
+
+// Check constant folding.
+hooRev(a) {
+ return ("Hello")[0] == a[1];
+}
diff --git a/tests/language/string/const_interpolation2_test.dart b/tests/language/string/const_interpolation2_test.dart
new file mode 100644
index 0000000..78912b7
--- /dev/null
+++ b/tests/language/string/const_interpolation2_test.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Regression test for issue #24839 - http://dartbug.com/24839
+
+const u1 = null;
+const int? u2 = null;
+const List? u3 = null;
+const u4 = const bool.hasEnvironment("XXXXX")
+ ? const String.fromEnvironment("XXXXX")
+ : null;
+const u5 = const bool.hasEnvironment("XXXXX")
+ ? const int.fromEnvironment("XXXXX")
+ : null;
+const u6 = bool.hasEnvironment("XXXXX")
+ ? const bool.fromEnvironment("XXXXX")
+ : null;
+const n1 = 42;
+const n2 = 3.1415;
+const int n3 = 37;
+const double n4 = 4.6692;
+const num n5 = b3 ? 1 : 2.71828;
+const n6 = const int.fromEnvironment("XXXXX", defaultValue: 87);
+const s1 = "s1";
+const String s2 = "s2";
+const String s3 = "$s1$s2";
+const s4 = const String.fromEnvironment("XXXXX", defaultValue: "s4");
+const b1 = true;
+const b2 = false;
+const b3 = b1 && (b2 || !b1);
+const b4 = const bool.fromEnvironment("XXXXX", defaultValue: true);
+
+// Individually
+const su1 = "$u1";
+const su2 = "$u2";
+const su3 = "$u3";
+const su4 = "$u4";
+const su5 = "$u5";
+const su6 = "$u6";
+const sn1 = "$n1";
+const sn2 = "$n2";
+const sn3 = "$n3";
+const sn4 = "$n4";
+const sn5 = "$n5";
+const sn6 = "$n6";
+const ss1 = "$s1";
+const ss2 = "$s2";
+const ss3 = "$s3";
+const ss4 = "$s4";
+const sb1 = "$b1";
+const sb2 = "$b2";
+const sb3 = "$b3";
+const sb4 = "$b4";
+
+// Constant variables in interpolation.
+const interpolation1 =
+ "$u1 $u2 $u3 $u4 $u5 $u6 $n1 $n2 $n3 $n4 $n5 $n6 $s1 $s2 $s3 $s4 $b1 $b2 $b3 $b4";
+// Constant expressions in interpolation.
+// (Single string, the linebreak to fit this into 80 chars is inside an
+// interpolation, which is allowed, even for single-line strings).
+const interpolation2 =
+ "${u1} ${u2} ${u3} ${u4} ${u5} ${u6} ${n1} ${n2} ${n3} ${n4} ${n5} ${n6} ${
+ s1} ${s2} ${s3} ${s4} ${b1} ${b2} ${b3} ${b4}";
+// Adjacent string literals are combined.
+const interpolation3 = "$u1 $u2 $u3 $u4 $u5 "
+ '$u6 $n1 $n2 $n3 $n4 '
+ """$n5 $n6 $s1 $s2 $s3 """
+ '''$s4 $b1 $b2 $b3 $b4''';
+// Nested interpolations.
+const interpolation4 = "${"$u1 $u2 $u3 $u4 $u5 " '$u6 $n1 $n2 $n3 $n4'} ${
+ """$n5 $n6 $s1 $s2 $s3 """ '''$s4 $b1 $b2 $b3 $b4'''}";
+
+main() {
+ Expect.equals(u1.toString(), su1);
+ Expect.equals(u2.toString(), su2);
+ Expect.equals(u3.toString(), su3);
+ Expect.equals(u4.toString(), su4);
+ Expect.equals(u5.toString(), su5);
+ Expect.equals(u6.toString(), su6);
+ Expect.equals(n1.toString(), sn1);
+ Expect.equals(n2.toString(), sn2);
+ Expect.equals(n3.toString(), sn3);
+ Expect.equals(n4.toString(), sn4);
+ Expect.equals(n5.toString(), sn5);
+ Expect.equals(n6.toString(), sn6);
+ Expect.equals(s1.toString(), ss1);
+ Expect.equals(s2.toString(), ss2);
+ Expect.equals(s3.toString(), ss3);
+ Expect.equals(s4.toString(), ss4);
+ Expect.equals(b1.toString(), sb1);
+ Expect.equals(b2.toString(), sb2);
+ Expect.equals(b3.toString(), sb3);
+ Expect.equals(b4.toString(), sb4);
+ var expect = "null null null null null null 42 3.1415 37 4.6692 2.71828 87 "
+ "s1 s2 s1s2 s4 true false false true";
+ Expect.equals(expect, interpolation1);
+ Expect.equals(expect, interpolation2);
+ Expect.equals(expect, interpolation3);
+ Expect.equals(expect, interpolation4);
+}
diff --git a/tests/language/string/const_interpolation_constant_string_interpolation_test.dart b/tests/language/string/const_interpolation_constant_string_interpolation_test.dart
new file mode 100644
index 0000000..16121c9
--- /dev/null
+++ b/tests/language/string/const_interpolation_constant_string_interpolation_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr --no-background-compilation
+
+import "package:expect/expect.dart";
+
+main() {
+ final a = new A();
+ for (int i = 0; i < 20; i++) {
+ final r = interpolIt(a);
+ Expect.stringEquals("hello home", r);
+ }
+ final b = new B();
+ // Deoptimize "interpolIt".
+ final r = interpolIt(b);
+ Expect.stringEquals("hello world", r);
+}
+
+String interpolIt(v) {
+ // String interpolation will be constant folded.
+ return "hello ${v.foo()}";
+}
+
+class A {
+ foo() => "home";
+}
+
+class B {
+ foo() => "world";
+}
diff --git a/tests/language/string/escape4_test.dart b/tests/language/string/escape4_test.dart
new file mode 100644
index 0000000..6f4efba
--- /dev/null
+++ b/tests/language/string/escape4_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that newlines cannot be escaped in strings.
+
+main() {
+ // Note: The newline inside a string literal doesn't play nice with the
+ // static error updater tool, so if you need to tweak the static error
+ // expectations in this test, you may need to do so manually.
+ print('Hello, World!\
+');
+// [error line 11, column 8, length 1]
+// [cfe] Can't find ')' to match '('.
+// [error line 11, column 9, length 1]
+// [cfe] String starting with ' must end with '.
+// [error line 11, column 23, length 1]
+// [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+// [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+// [error line 11, column 23, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+// [error line 12, column 1, length 3]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+// [cfe] Expected ';' after this.
+// [error line 12, column 1]
+// [cfe] String starting with ' must end with '.
+// [error line 12, column 3, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+}
+// [error line 29, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
diff --git a/tests/language/string/escapes_test.dart b/tests/language/string/escapes_test.dart
new file mode 100644
index 0000000..78808a7
--- /dev/null
+++ b/tests/language/string/escapes_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class StringEscapesTest {
+ static testMain() {
+ testDelimited();
+ testFixed2();
+ testFixed4();
+ testEscapes();
+ testLiteral();
+ }
+
+ static testDelimited() {
+ String str = "Foo\u{1}Bar\u{000001}Baz\u{D7FF}Boo";
+ Expect.equals(15, str.length);
+ Expect.equals(1, str.codeUnitAt(3));
+ Expect.equals(1, str.codeUnitAt(7));
+ Expect.equals(0xD7FF, str.codeUnitAt(11));
+ Expect.equals('B'.codeUnitAt(0), str.codeUnitAt(12));
+ }
+
+ static testEscapes() {
+ String str = "Foo\fBar\vBaz\bBoo";
+ Expect.equals(15, str.length);
+ Expect.equals(12, str.codeUnitAt(3));
+ Expect.equals('B'.codeUnitAt(0), str.codeUnitAt(4));
+ Expect.equals(11, str.codeUnitAt(7));
+ Expect.equals('z'.codeUnitAt(0), str.codeUnitAt(10));
+ Expect.equals(8, str.codeUnitAt(11));
+ Expect.equals('o'.codeUnitAt(0), str.codeUnitAt(14));
+ str = "Abc\rDef\nGhi\tJkl";
+ Expect.equals(15, str.length);
+ Expect.equals(13, str.codeUnitAt(3));
+ Expect.equals('D'.codeUnitAt(0), str.codeUnitAt(4));
+ Expect.equals(10, str.codeUnitAt(7));
+ Expect.equals('G'.codeUnitAt(0), str.codeUnitAt(8));
+ Expect.equals(9, str.codeUnitAt(11));
+ Expect.equals('J'.codeUnitAt(0), str.codeUnitAt(12));
+ }
+
+ static testFixed2() {
+ String str = "Foo\xFFBar";
+ Expect.equals(7, str.length);
+ Expect.equals(255, str.codeUnitAt(3));
+ Expect.equals('B'.codeUnitAt(0), str.codeUnitAt(4));
+ }
+
+ static testFixed4() {
+ String str = "Foo\u0001Bar";
+ Expect.equals(7, str.length);
+ Expect.equals(1, str.codeUnitAt(3));
+ Expect.equals('B'.codeUnitAt(0), str.codeUnitAt(4));
+ }
+
+ static testLiteral() {
+ String str = "\a\c\d\e\g\h\i\j\k\l\$\{\}\"";
+ Expect.equals(r'acdeghijkl${}"', str);
+ }
+}
+
+main() {
+ StringEscapesTest.testMain();
+}
diff --git a/tests/language/string/interpolate1_test.dart b/tests/language/string/interpolate1_test.dart
new file mode 100644
index 0000000..1bc80c0
--- /dev/null
+++ b/tests/language/string/interpolate1_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The interpolated identifier can't start with '$'.
+
+main() {
+ var $x = 1;
+ var s = "eins und $$x macht zwei.";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ // ^
+ // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
+ // [cfe] Getter not found: 'x'.
+}
diff --git a/tests/language/string/interpolate2_test.dart b/tests/language/string/interpolate2_test.dart
new file mode 100644
index 0000000..bb49ba5
--- /dev/null
+++ b/tests/language/string/interpolate2_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing string interpolation of expressions.
+
+import "package:expect/expect.dart";
+
+class StringInterpolate2Test {
+ static var F1;
+
+ static void testMain() {
+ F1 = "1 + 5 = ${1+5}";
+
+ Expect.equals("1 + 5 = 6", F1);
+
+ var fib = [1, 1, 2, 3, 5, 8, 13, 21];
+
+ var i = 5;
+ var s = "${i}";
+ Expect.equals("5", s);
+
+ s = "fib(${i}) = ${fib[i]}";
+ Expect.equals("fib(5) = 8", s);
+
+ i = 5;
+ s = "$i squared is ${((x) => x*x)(i)}";
+ Expect.equals("5 squared is 25", s);
+
+ Expect.equals("8", "${fib.length}");
+ // test single quote
+ Expect.equals("8", '${fib.length}');
+ // test multi-line
+ Expect.equals(
+ "8",
+ '${fib.
+ length}');
+
+ var map = {"red": 1, "green": 2, "blue": 3};
+ s = "green has value ${map["green"]}";
+ Expect.equals("green has value 2", s);
+
+ i = 0;
+ b() => "${++i}";
+ s = "aaa ${"bbb ${b()} bbb"} aaa ${b()}";
+ Expect.equals("aaa bbb 1 bbb aaa 2", s);
+
+ // test multiple levels of nesting, including changing quotes and
+ // multiline string types
+ s = "a ${(){ return 'b ${(){ return """
+c""";}()}'; }()} d";
+ Expect.equals("a b c d", s);
+ }
+}
+
+main() {
+ StringInterpolate2Test.testMain();
+}
diff --git a/tests/language/string/interpolate3_test.dart b/tests/language/string/interpolate3_test.dart
new file mode 100644
index 0000000..ada7879
--- /dev/null
+++ b/tests/language/string/interpolate3_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The interpolated identifier must start with an identifier start character.
+
+main() {
+ var x = 1;
+ var s = "eins und $-x macht zwei.";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+}
diff --git a/tests/language/string/interpolate_null_test.dart b/tests/language/string/interpolate_null_test.dart
new file mode 100644
index 0000000..e10b808
--- /dev/null
+++ b/tests/language/string/interpolate_null_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing NPE within string interpolation.
+
+import "package:expect/expect.dart";
+
+class A {
+ A(String this.name) {}
+ String name;
+}
+
+main() {
+ dynamic a = new A("Kermit");
+ var s = "Hello Mr. ${a.name}";
+ Expect.stringEquals("Hello Mr. Kermit", s);
+ a = null;
+ try {
+ s = "Hello Mr. ${a.name}";
+ } on NoSuchMethodError catch (e) {
+ return;
+ }
+ Expect.fail("NoSuchMethodError not thrown");
+}
diff --git a/tests/language/string/interpolate_test.dart b/tests/language/string/interpolate_test.dart
new file mode 100644
index 0000000..5c25f42
--- /dev/null
+++ b/tests/language/string/interpolate_test.dart
@@ -0,0 +1,266 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing string interpolation.
+
+import "package:expect/expect.dart";
+
+class WhatchamaCallIt {
+ WhatchamaCallIt() {}
+
+ String foo() {
+ // Test $this and Field name is defined in subclass.
+ dynamic self = this;
+ dynamic name = self.name;
+ return "$this and $name";
+ }
+}
+
+class ThingamaBob extends WhatchamaCallIt {
+ ThingamaBob(String s)
+ : name = s,
+ super();
+ String name;
+ toString() => "Hansel";
+}
+
+const String A = "svin";
+const String B = "hest";
+const int N = 1 + 1;
+late String Printers;
+late String AAR_Printers;
+
+main() {
+ Printers = "Printers: $A and $B";
+ AAR_Printers = "AAR has $N $Printers.";
+
+ var x = 1;
+ var s = "eins und \$x macht zwei.";
+ print(s);
+ Expect.equals(r"eins und $x macht zwei.", s);
+
+ s = "eins und $x macht zwei.";
+ print(s);
+ Expect.equals(r"eins und 1 macht zwei.", s);
+
+ print(AAR_Printers);
+ Expect.equals(r"AAR has 2 Printers: svin and hest.", AAR_Printers);
+
+ var s$eins = "eins";
+ var $1 = 1;
+ var zw = "zw";
+ var ei = "ei";
+ var zw$ei = "\"Martini, dry? Nai zwai.\"";
+ s = "${s$eins} und ${$1} macht $zw$ei.";
+ print(s);
+ Expect.equals(r"eins und 1 macht zwei.", s);
+
+ dynamic t = new ThingamaBob("Gretel");
+ print(t.foo());
+ Expect.equals(t.foo(), "Hansel and Gretel");
+
+ testStringVariants();
+}
+
+class Stringable {
+ final String value;
+ Stringable(this.value);
+ String toString() => value;
+ operator *(int count) => new Stringable(value * count);
+}
+
+void testStringVariants() {
+ String latin = "ab\x00\xff";
+ String nonLatin = "\u2000\u{10000}\ufeff";
+ dynamic oLatin = new Stringable(latin);
+ dynamic oNonLatin = new Stringable(nonLatin);
+
+ // ASCII.
+ Expect.equals(latin * 3, "$latin$latin$latin");
+ Expect.equals(
+ latin * 64,
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin");
+ Expect.equals(
+ latin * 64,
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}");
+ // Non-ASCII.
+ Expect.equals(nonLatin * 3, "$nonLatin$nonLatin$nonLatin");
+ Expect.equals(
+ nonLatin * 64,
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin");
+ Expect.equals(
+ nonLatin * 64,
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}"
+ "${nonLatin * 4}${nonLatin * 4}");
+ // Mixed.
+ Expect.equals(latin * 3 + nonLatin, "$latin$latin$latin$nonLatin");
+ Expect.equals(nonLatin + latin * 3, "$nonLatin$latin$latin$latin");
+ Expect.equals(
+ latin * 60 + nonLatin * 4,
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin"
+ "$nonLatin$nonLatin$nonLatin$nonLatin");
+ Expect.equals(
+ nonLatin * 4 + latin * 60,
+ "$nonLatin$nonLatin$nonLatin$nonLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin$latin$latin$latin$latin"
+ "$latin$latin$latin$latin");
+ Expect.equals(
+ latin * 60 + nonLatin * 4,
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${nonLatin * 4}");
+ Expect.equals(
+ nonLatin * 4 + latin * 60,
+ "${nonLatin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${latin * 4}");
+ // With objects.
+ Expect.equals(latin * 3, "$latin$oLatin$latin");
+ Expect.equals(
+ latin * 64,
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin"
+ "$latin$latin$latin$latin$latin$latin$latin$oLatin");
+ Expect.equals(
+ latin * 64,
+ "${latin * 4}${latin * 4}${latin * 4}${oLatin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${oLatin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${oLatin * 4}"
+ "${latin * 4}${latin * 4}${latin * 4}${oLatin * 4}");
+ // Non-ASCII.
+ Expect.equals(nonLatin * 3, "$nonLatin$oNonLatin$nonLatin");
+ Expect.equals(
+ nonLatin * 64,
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin"
+ "$nonLatin$nonLatin$nonLatin$oNonLatin");
+ Expect.equals(
+ nonLatin * 64,
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}"
+ "${nonLatin * 4}${oNonLatin * 4}");
+ // Mixed.
+ Expect.equals(latin * 2 + nonLatin * 2, "$latin$oLatin$nonLatin$oNonLatin");
+ Expect.equals(nonLatin * 2 + latin * 2, "$nonLatin$oNonLatin$latin$oLatin");
+ Expect.equals(
+ (latin * 2 + nonLatin * 2) * 8,
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin"
+ "$latin$oLatin$nonLatin$oNonLatin");
+ Expect.equals(
+ (nonLatin * 2 + latin * 2) * 8,
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin"
+ "$nonLatin$oNonLatin$latin$oLatin");
+
+ // All combinations
+ var o1 = new Stringable("x");
+ var o2 = new Stringable("\ufeff");
+
+ Expect.equals("a\u2000x\ufeff", "${"a"}${"\u2000"}${o1}${o2}");
+ Expect.equals("a\u2000\ufeffx", "${"a"}${"\u2000"}${o2}${o1}");
+ Expect.equals("ax\u2000\ufeff", "${"a"}${o1}${"\u2000"}${o2}");
+ Expect.equals("ax\ufeff\u2000", "${"a"}${o1}${o2}${"\u2000"}");
+ Expect.equals("a\ufeffx\u2000", "${"a"}${o2}${o1}${"\u2000"}");
+ Expect.equals("a\ufeff\u2000x", "${"a"}${o2}${"\u2000"}${o1}");
+
+ Expect.equals("\u2000ax\ufeff", "${"\u2000"}${"a"}${o1}${o2}");
+ Expect.equals("\u2000a\ufeffx", "${"\u2000"}${"a"}${o2}${o1}");
+ Expect.equals("xa\u2000\ufeff", "${o1}${"a"}${"\u2000"}${o2}");
+ Expect.equals("xa\ufeff\u2000", "${o1}${"a"}${o2}${"\u2000"}");
+ Expect.equals("\ufeffax\u2000", "${o2}${"a"}${o1}${"\u2000"}");
+ Expect.equals("\ufeffa\u2000x", "${o2}${"a"}${"\u2000"}${o1}");
+
+ Expect.equals("\u2000xa\ufeff", "${"\u2000"}${o1}${"a"}${o2}");
+ Expect.equals("\u2000\ufeffax", "${"\u2000"}${o2}${"a"}${o1}");
+ Expect.equals("x\u2000a\ufeff", "${o1}${"\u2000"}${"a"}${o2}");
+ Expect.equals("x\ufeffa\u2000", "${o1}${o2}${"a"}${"\u2000"}");
+ Expect.equals("\ufeffxa\u2000", "${o2}${o1}${"a"}${"\u2000"}");
+ Expect.equals("\ufeff\u2000ax", "${o2}${"\u2000"}${"a"}${o1}");
+
+ Expect.equals("\u2000x\ufeffa", "${"\u2000"}${o1}${o2}${"a"}");
+ Expect.equals("\u2000\ufeffxa", "${"\u2000"}${o2}${o1}${"a"}");
+ Expect.equals("x\u2000\ufeffa", "${o1}${"\u2000"}${o2}${"a"}");
+ Expect.equals("x\ufeff\u2000a", "${o1}${o2}${"\u2000"}${"a"}");
+ Expect.equals("\ufeffx\u2000a", "${o2}${o1}${"\u2000"}${"a"}");
+ Expect.equals("\ufeff\u2000xa", "${o2}${"\u2000"}${o1}${"a"}");
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation1_runtime_test.dart
similarity index 68%
copy from tests/language_2/string/interpolation6_runtime_test.dart
copy to tests/language/string/interpolation1_runtime_test.dart
index 4d4d546..3ede1d8 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation1_runtime_test.dart
@@ -7,15 +7,19 @@
// A dollar must be followed by a "{" or an identifier.
-class StringInterpolation6NegativeTest {
- static testMain() {
- // Dollar not followed by "{" or identifier.
- String regexp;
+class A {
+ final String str;
+ const A(this.str);
+}
- print(regexp);
+class StringInterpolation1NegativeTest {
+ // Dollar not followed by "{" or identifier.
+
+ static testMain() {
+
}
}
main() {
- StringInterpolation6NegativeTest.testMain();
+ StringInterpolation1NegativeTest.testMain();
}
diff --git a/tests/language/string/interpolation1_test.dart b/tests/language/string/interpolation1_test.dart
new file mode 100644
index 0000000..7f43236
--- /dev/null
+++ b/tests/language/string/interpolation1_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A dollar must be followed by a "{" or an identifier.
+
+class A {
+ final String str;
+ const A(this.str);
+}
+
+class StringInterpolation1NegativeTest {
+ // Dollar not followed by "{" or identifier.
+ static const DOLLAR = const A("$");
+ // [error line 14, column 35, length 0]
+ // [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ // [error line 14, column 35, length 0]
+ // [analyzer] COMPILE_TIME_ERROR.INVALID_CONSTANT
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ static testMain() {
+ print(DOLLAR);
+ }
+}
+
+main() {
+ StringInterpolation1NegativeTest.testMain();
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation2_runtime_test.dart
similarity index 70%
copy from tests/language_2/string/interpolation6_runtime_test.dart
copy to tests/language/string/interpolation2_runtime_test.dart
index 4d4d546..0b0a89f 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation2_runtime_test.dart
@@ -7,15 +7,13 @@
// A dollar must be followed by a "{" or an identifier.
-class StringInterpolation6NegativeTest {
+class StringInterpolation2NegativeTest {
static testMain() {
- // Dollar not followed by "{" or identifier.
- String regexp;
+ // Dollar followed by "/".
- print(regexp);
}
}
main() {
- StringInterpolation6NegativeTest.testMain();
+ StringInterpolation2NegativeTest.testMain();
}
diff --git a/tests/language/string/interpolation2_test.dart b/tests/language/string/interpolation2_test.dart
new file mode 100644
index 0000000..076fcc1
--- /dev/null
+++ b/tests/language/string/interpolation2_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A dollar must be followed by a "{" or an identifier.
+
+class StringInterpolation2NegativeTest {
+ static testMain() {
+ // Dollar followed by "/".
+ print('C;Y1;X4;K"$/Month"');
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ }
+}
+
+main() {
+ StringInterpolation2NegativeTest.testMain();
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation3_runtime_test.dart
similarity index 70%
copy from tests/language_2/string/interpolation6_runtime_test.dart
copy to tests/language/string/interpolation3_runtime_test.dart
index 4d4d546..96b92fb 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation3_runtime_test.dart
@@ -7,15 +7,13 @@
// A dollar must be followed by a "{" or an identifier.
-class StringInterpolation6NegativeTest {
+class StringInterpolation3NegativeTest {
static testMain() {
- // Dollar not followed by "{" or identifier.
- String regexp;
+ // Dollar followed by a number.
- print(regexp);
}
}
main() {
- StringInterpolation6NegativeTest.testMain();
+ StringInterpolation3NegativeTest.testMain();
}
diff --git a/tests/language/string/interpolation3_test.dart b/tests/language/string/interpolation3_test.dart
new file mode 100644
index 0000000..0760fd9
--- /dev/null
+++ b/tests/language/string/interpolation3_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A dollar must be followed by a "{" or an identifier.
+
+class StringInterpolation3NegativeTest {
+ static testMain() {
+ // Dollar followed by a number.
+ print('F;P4;F$2R');
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ }
+}
+
+main() {
+ StringInterpolation3NegativeTest.testMain();
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation4_runtime_test.dart
similarity index 78%
rename from tests/language_2/string/interpolation6_runtime_test.dart
rename to tests/language/string/interpolation4_runtime_test.dart
index 4d4d546..e89625c 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation4_runtime_test.dart
@@ -7,15 +7,13 @@
// A dollar must be followed by a "{" or an identifier.
-class StringInterpolation6NegativeTest {
+class StringInterpolation4NegativeTest {
static testMain() {
// Dollar not followed by "{" or identifier.
- String regexp;
- print(regexp);
}
}
main() {
- StringInterpolation6NegativeTest.testMain();
+ StringInterpolation4NegativeTest.testMain();
}
diff --git a/tests/language/string/interpolation4_test.dart b/tests/language/string/interpolation4_test.dart
new file mode 100644
index 0000000..740dc9a
--- /dev/null
+++ b/tests/language/string/interpolation4_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A dollar must be followed by a "{" or an identifier.
+
+class StringInterpolation4NegativeTest {
+ static testMain() {
+ // Dollar not followed by "{" or identifier.
+ print("-" + "$" + "foo");
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ }
+}
+
+main() {
+ StringInterpolation4NegativeTest.testMain();
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation5_runtime_test.dart
similarity index 70%
copy from tests/language_2/string/interpolation6_runtime_test.dart
copy to tests/language/string/interpolation5_runtime_test.dart
index 4d4d546..acbec21 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation5_runtime_test.dart
@@ -7,15 +7,13 @@
// A dollar must be followed by a "{" or an identifier.
-class StringInterpolation6NegativeTest {
+class StringInterpolation5NegativeTest {
static testMain() {
- // Dollar not followed by "{" or identifier.
- String regexp;
+ // Dollar followed by a number.
- print(regexp);
}
}
main() {
- StringInterpolation6NegativeTest.testMain();
+ StringInterpolation5NegativeTest.testMain();
}
diff --git a/tests/language/string/interpolation5_test.dart b/tests/language/string/interpolation5_test.dart
new file mode 100644
index 0000000..cd04ed3
--- /dev/null
+++ b/tests/language/string/interpolation5_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A dollar must be followed by a "{" or an identifier.
+
+class StringInterpolation5NegativeTest {
+ static testMain() {
+ // Dollar followed by a number.
+ print("$1,000");
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ }
+}
+
+main() {
+ StringInterpolation5NegativeTest.testMain();
+}
diff --git a/tests/language_2/string/interpolation6_runtime_test.dart b/tests/language/string/interpolation6_test.dart
similarity index 64%
copy from tests/language_2/string/interpolation6_runtime_test.dart
copy to tests/language/string/interpolation6_test.dart
index 4d4d546..74cfbbe 100644
--- a/tests/language_2/string/interpolation6_runtime_test.dart
+++ b/tests/language/string/interpolation6_test.dart
@@ -1,6 +1,3 @@
-// TODO(multitest): This was automatically migrated from a multitest and may
-// contain strange or dead code.
-
// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -11,7 +8,10 @@
static testMain() {
// Dollar not followed by "{" or identifier.
String regexp;
-
+ regexp = "^(\\d\\d?)[-/](\\d\\d?)$";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
print(regexp);
}
}
diff --git a/tests/language/string/interpolation7_test.dart b/tests/language/string/interpolation7_test.dart
new file mode 100644
index 0000000..77a07aa
--- /dev/null
+++ b/tests/language/string/interpolation7_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Dart test program testing string interpolation with toString on custom
+// classes and on null.
+
+class A {
+ const A();
+ String toString() {
+ return "A";
+ }
+}
+
+class StringInterpolation7Test {
+ static testMain() {
+ A? a = new A();
+ Expect.equals("A + A", "$a + $a");
+ a = null;
+ Expect.equals("null", "$a");
+ }
+}
+
+main() {
+ StringInterpolation7Test.testMain();
+}
diff --git a/tests/language/string/interpolation8_test.dart b/tests/language/string/interpolation8_test.dart
new file mode 100644
index 0000000..a3c09bc
--- /dev/null
+++ b/tests/language/string/interpolation8_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Allow assignment of string interpolation to a static const field
+
+import "package:expect/expect.dart";
+
+class A {
+ static const x = 1;
+ static const y = "Two is greater than ${x}";
+}
+
+main() {
+ Expect.identical("Two is greater than 1", A.y);
+}
diff --git a/tests/language/string/interpolation9_runtime_test.dart b/tests/language/string/interpolation9_runtime_test.dart
new file mode 100644
index 0000000..3cf2bd1
--- /dev/null
+++ b/tests/language/string/interpolation9_runtime_test.dart
@@ -0,0 +1,38 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Almost valid string interpolation syntax.
+
+main() {
+ var x;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ return x;
+}
diff --git a/tests/language/string/interpolation9_test.dart b/tests/language/string/interpolation9_test.dart
new file mode 100644
index 0000000..b3166b7
--- /dev/null
+++ b/tests/language/string/interpolation9_test.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Almost valid string interpolation syntax.
+
+main() {
+ var x;
+
+ x = "$";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = "x$";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = "$x$";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = "$$x";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = "$ ";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+
+ x = '$';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = 'x$';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '$x$';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '$$x';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '$ ';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+
+ x = """$""";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = """x$""";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = """$x$""";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = """$$x""";
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = """$ """;
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+
+ x = '''$''';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '''x$''';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '''$x$''';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '''$$x''';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+ x = '''$ ''';
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+
+ return x;
+}
diff --git a/tests/language/string/interpolation_and_buffer_legacy_lib.dart b/tests/language/string/interpolation_and_buffer_legacy_lib.dart
new file mode 100644
index 0000000..c74b541
--- /dev/null
+++ b/tests/language/string/interpolation_and_buffer_legacy_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.6
+
+class ToStringNull {
+ String toString() => null;
+}
diff --git a/tests/language/string/interpolation_and_buffer_legacy_test.dart b/tests/language/string/interpolation_and_buffer_legacy_test.dart
new file mode 100644
index 0000000..eb34ef2
--- /dev/null
+++ b/tests/language/string/interpolation_and_buffer_legacy_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// A null safe library cannot implement `toString()` and return `null`, but a
+// legacy library, which may be called from null safe code, can. Test that that
+// doesn't fail.
+
+// Requirements=nnbd-weak
+import "package:expect/expect.dart";
+
+import "interpolation_and_buffer_legacy_lib.dart";
+
+void main() {
+ var n = ToStringNull();
+
+ // Throws immediately when evaluating the first interpolated expression.
+ Expect.throws<Error>(() => "$n${throw "unreachable"}");
+
+ // Throws immediately when adding object that doesn't return a String.
+ Expect.throws<Error>(
+ () => StringBuffer()..write(n)..write(throw "unreachable"));
+
+ // Same behavior for constructor argument as if adding it to buffer later.
+ Expect.throws<Error>(() => StringBuffer(n)..write(throw "unreachable"));
+}
diff --git a/tests/language/string/interpolation_and_buffer_test.dart b/tests/language/string/interpolation_and_buffer_test.dart
new file mode 100644
index 0000000..7086276
--- /dev/null
+++ b/tests/language/string/interpolation_and_buffer_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Interpolation calls `toString`.
+// The evaluation of the interpolation fails if `toString` throws or returns
+// null. In Dart 2, any method overriding `Object.toString` must return a
+// `String` or `null`. In particular, if `object.toString()` returns null, then
+// `"$object"` must not evaluate to the string `"null"`.
+//
+// The specification states that the expression of an interpolation is
+// evaluated as follows:
+//
+// 1. Evaluate $e_i$ to an object $o_i$.
+// 2. Invoke the `toString` method on *o<sub>i</sub>* with no arguments,
+// and let *r<sub>i</sub>*$ be the returned value.
+// 3. If *r<sub>i</sub>* is not an instance of the built-in type `String`,
+// throw an `Error`.
+//
+// (Then the resulting strings are concatenated with the literal string parts).
+//
+//
+// Adding an object to a `StringBuffer` behaves the same as evaluating
+// an expression in an interpolation. It must immediately fail if the
+// object's toString throws or returns `null`.
+//
+// This ensures that implementing interpolation via a `StringBuffer`is
+// a valid implementation choice.
+
+import "package:expect/expect.dart";
+
+class ToStringString {
+ String toString() => "String";
+}
+
+class ToStringThrows {
+ String toString() => throw "Throw";
+}
+
+void main() {
+ var s = ToStringString();
+ var t = ToStringThrows();
+
+ Expect.equals("$s$s", "StringString");
+ // Throws immediately when evaluating the first interpolated expression.
+ Expect.throws<String>(() => "$t${throw "unreachable"}", (e) => e == "Throw");
+
+ // Throws immediately when adding object that doesn't return a String.
+ Expect.equals(
+ (StringBuffer()..write(s)..write(s)).toString(), "StringString");
+ Expect.throws<String>(
+ () => StringBuffer()..write(t)..write(throw "unreachable"),
+ (e) => e == "Throw");
+
+ // Same behavior for constructor argument as if adding it to buffer later.
+ Expect.equals((StringBuffer(s)..write(s)).toString(), "StringString");
+ Expect.throws<String>(
+ () => StringBuffer(t)..write(throw "unreachable"), (e) => e == "Throw");
+}
diff --git a/tests/language/string/interpolation_newline_test.dart b/tests/language/string/interpolation_newline_test.dart
new file mode 100644
index 0000000..91ad04f
--- /dev/null
+++ b/tests/language/string/interpolation_newline_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Test of newlines in interpolated strings.
+
+main() {
+ String expected = '[[{{}: {}}]]';
+ String a = "${ [ "${ [ '${ { '${ { } }' : { } } }' ] }" ] }";
+ String b = "${ [ "${ [ '${ { '${
+ { } }' : { } } }' ] }" ] }";
+ String c = "${ [ "${ [ '${ { '${
+ {
+ } }' : {
+ } } }' ] }" ] }";
+ if (expected != a) throw 'expecteda: $expected != $a';
+ if (a != b) throw 'ab: $a != $b';
+ if (b != c) throw 'bc: $b != $c';
+ print('$a$b$c');
+}
diff --git a/tests/language/string/interpolation_runtime_test.dart b/tests/language/string/interpolation_runtime_test.dart
new file mode 100644
index 0000000..90623b8e
--- /dev/null
+++ b/tests/language/string/interpolation_runtime_test.dart
@@ -0,0 +1,85 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Tests for string interpolation
+class StringInterpolationTest {
+ StringInterpolationTest() {}
+
+ static void m() {}
+
+ static const int i = 1;
+ static const String a = "<hi>";
+
+ int j = -1;
+ int k = -1;
+
+ static testMain(bool alwaysFalse) {
+ var test = new StringInterpolationTest();
+ test.j = 3;
+ test.k = 5;
+
+ // simple string
+ Expect.equals(" hi ", " hi ");
+
+ var c1 = '1';
+ var c2 = '2';
+ var c3 = '3';
+ var c4 = '4';
+ // no chars before/after/between embedded expressions
+ Expect.equals(" 1", " ${c1}");
+ Expect.equals("1 ", "${c1} ");
+ Expect.equals("1", "${c1}");
+ Expect.equals("12", "${c1}${c2}");
+ Expect.equals("12 34", "${c1}${c2} ${c3}${c4}");
+
+ // embedding static fields
+ Expect.equals(" hi 1 ", " hi ${i} ");
+ Expect.equals(" hi <hi> ", " hi ${a} ");
+
+ // embedding method parameters
+ Expect.equals("param = 9", test.embedParams(9));
+
+ // embedding a class field
+ Expect.equals("j = 3", test.embedSingleField());
+
+ // embedding more than one (non-constant) expression
+ Expect.equals(" hi 1 <hi>", " hi ${i} ${a}");
+ Expect.equals("j = 3; k = 5", test.embedMultipleFields());
+
+ // escaping $ - doesn't start the embedded expression
+ Expect.equals("\$", "escaped \${3+2}"[12]);
+ Expect.equals("{", "escaped \${3+2}"[13]);
+ Expect.equals("3", "escaped \${3+2}"[14]);
+ Expect.equals("+", "escaped \${3+2}"[15]);
+ Expect.equals("2", "escaped \${3+2}"[16]);
+ Expect.equals("}", "escaped \${3+2}"[17]);
+
+ if (alwaysFalse) {
+
+ }
+
+ Expect.equals("${m}", "$m");
+ }
+
+ String embedParams(int z) {
+ return "param = ${z}";
+ }
+
+ String embedSingleField() {
+ return "j = ${j}";
+ }
+
+ String embedMultipleFields() {
+ return "j = ${j}; k = ${k}";
+ }
+}
+
+main() {
+ StringInterpolationTest.testMain(false);
+}
diff --git a/tests/language/string/interpolation_test.dart b/tests/language/string/interpolation_test.dart
new file mode 100644
index 0000000..50968b0
--- /dev/null
+++ b/tests/language/string/interpolation_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Tests for string interpolation
+class StringInterpolationTest {
+ StringInterpolationTest() {}
+
+ static void m() {}
+
+ static const int i = 1;
+ static const String a = "<hi>";
+
+ int j = -1;
+ int k = -1;
+
+ static testMain(bool alwaysFalse) {
+ var test = new StringInterpolationTest();
+ test.j = 3;
+ test.k = 5;
+
+ // simple string
+ Expect.equals(" hi ", " hi ");
+
+ var c1 = '1';
+ var c2 = '2';
+ var c3 = '3';
+ var c4 = '4';
+ // no chars before/after/between embedded expressions
+ Expect.equals(" 1", " ${c1}");
+ Expect.equals("1 ", "${c1} ");
+ Expect.equals("1", "${c1}");
+ Expect.equals("12", "${c1}${c2}");
+ Expect.equals("12 34", "${c1}${c2} ${c3}${c4}");
+
+ // embedding static fields
+ Expect.equals(" hi 1 ", " hi ${i} ");
+ Expect.equals(" hi <hi> ", " hi ${a} ");
+
+ // embedding method parameters
+ Expect.equals("param = 9", test.embedParams(9));
+
+ // embedding a class field
+ Expect.equals("j = 3", test.embedSingleField());
+
+ // embedding more than one (non-constant) expression
+ Expect.equals(" hi 1 <hi>", " hi ${i} ${a}");
+ Expect.equals("j = 3; k = 5", test.embedMultipleFields());
+
+ // escaping $ - doesn't start the embedded expression
+ Expect.equals("\$", "escaped \${3+2}"[12]);
+ Expect.equals("{", "escaped \${3+2}"[13]);
+ Expect.equals("3", "escaped \${3+2}"[14]);
+ Expect.equals("+", "escaped \${3+2}"[15]);
+ Expect.equals("2", "escaped \${3+2}"[16]);
+ Expect.equals("}", "escaped \${3+2}"[17]);
+
+ if (alwaysFalse) {
+ "${i.toHorse()}";
+ // ^^^^^^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
+ // [cfe] The method 'toHorse' isn't defined for the class 'int'.
+ }
+
+ Expect.equals("${m}", "$m");
+ }
+
+ String embedParams(int z) {
+ return "param = ${z}";
+ }
+
+ String embedSingleField() {
+ return "j = ${j}";
+ }
+
+ String embedMultipleFields() {
+ return "j = ${j}; k = ${k}";
+ }
+}
+
+main() {
+ StringInterpolationTest.testMain(false);
+}
diff --git a/tests/language/string/intrinsics_test.dart b/tests/language/string/intrinsics_test.dart
new file mode 100644
index 0000000..ed1521c
--- /dev/null
+++ b/tests/language/string/intrinsics_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Replace with shared test once interface issues clarified.
+// Test various String intrinsics
+// VMOptions=--optimization-counter-threshold=10
+
+import "package:expect/expect.dart";
+
+main() {
+ var oneByte = "Hello world";
+ var empty = "";
+ for (int i = 0; i < 20; i++) {
+ Expect.equals(11, testLength(oneByte));
+ Expect.equals(0, testLength(empty));
+ Expect.isFalse(testIsEmpty(oneByte));
+ Expect.isTrue(testIsEmpty(empty));
+ }
+}
+
+testLength(s) {
+ return s.length;
+}
+
+testIsEmpty(s) {
+ return s.isEmpty;
+}
diff --git a/tests/language/string/join_test.dart b/tests/language/string/join_test.dart
new file mode 100644
index 0000000..0cc06f8
--- /dev/null
+++ b/tests/language/string/join_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Regression test ensuring that only ObjectArrays are handed to the VM code.
+
+import "package:expect/expect.dart";
+
+class StringJoinTest {
+ static testMain() {
+ List<String> ga = ["a", "b"];
+ Expect.equals("ab", ga.join());
+ Expect.equals("ab", ga.join(""));
+ }
+}
+
+main() {
+ StringJoinTest.testMain();
+}
diff --git a/tests/language/string/literals_test.dart b/tests/language/string/literals_test.dart
new file mode 100644
index 0000000..6b4f4f5
--- /dev/null
+++ b/tests/language/string/literals_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+ var expect = new String.fromCharCodes(
+ [0, 0x0a, 0x0d, 0x7f, 0xff, 0xffff, 0xd800, 0xdc00, 0xdbff, 0xdfff]);
+ test(string) {
+ Expect.equals(expect, string);
+ }
+
+ // Plain escapes of code points.
+ test("\x00\x0a\x0d\x7f\xff\uffff\u{10000}\u{10ffff}");
+ test("""\x00\x0a\x0d\x7f\xff\uffff\u{10000}\u{10ffff}""");
+ test('\x00\x0a\x0d\x7f\xff\uffff\u{10000}\u{10ffff}');
+ test('''\x00\x0a\x0d\x7f\xff\uffff\u{10000}\u{10ffff}''');
+ // Plain escapes of individual code units.
+ test("\x00\x0a\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff");
+ test("""\x00\x0a\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff""");
+ test('\x00\x0a\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff');
+ test('''\x00\x0a\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff''');
+ // Insert newline into multiline string.
+ test("""\x00
+\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff""");
+ test('''\x00
+\x0d\x7f\xff\uffff\ud800\udc00\udbff\udfff''');
+ // Extract code points from multi-character escape string.
+ test("\x00\x0a\x0d\x7f\xff\uffff"
+ "${"\u{10000}"[0]}${"\u{10000}"[1]}"
+ "${"\u{10FFFF}"[0]}${"\u{10FFFF}"[1]}");
+ test("\x00\x0a\x0d\x7f\xff\uffff" + "\ud800" + "\udc00\udbff" + "\udfff");
+ // Single line string over multiple lines with newlines inside interpolation.
+ test("\x00\x0a\x0d\x7f\xff${
+ ""
+ }\uffff\ud800\udc00\udbff\udfff");
+}
diff --git a/tests/language/string/multiline_newline_cr.dart b/tests/language/string/multiline_newline_cr.dart
new file mode 100644
index 0000000..1b0627a
--- /dev/null
+++ b/tests/language/string/multiline_newline_cr.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library multiline_newline_cr;
+
+const constantMultilineString = """
+a
+b
+""";
+
+var nonConstantMultilineString = """
+a
+b
+""";
+
+const constantRawMultilineString = r"""
+\a
+\b
+""";
+
+var nonConstantRawMultilineString = r"""
+\a
+\b
+""";
diff --git a/tests/language/string/multiline_newline_crlf.dart b/tests/language/string/multiline_newline_crlf.dart
new file mode 100644
index 0000000..958a82c
--- /dev/null
+++ b/tests/language/string/multiline_newline_crlf.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Note: This test relies on LF line endings in the source file.
+// It requires an entry in the .gitattributes file.
+
+library multiline_newline_crlf;
+
+const constantMultilineString = """
+a
+b
+""";
+
+var nonConstantMultilineString = """
+a
+b
+""";
+
+const constantRawMultilineString = r"""
+\a
+\b
+""";
+
+var nonConstantRawMultilineString = r"""
+\a
+\b
+""";
\ No newline at end of file
diff --git a/tests/language/string/multiline_newline_lf.dart b/tests/language/string/multiline_newline_lf.dart
new file mode 100644
index 0000000..b13fbab
--- /dev/null
+++ b/tests/language/string/multiline_newline_lf.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Note: This test relies on LF line endings in the source file.
+// It requires an entry in the .gitattributes file.
+
+library multiline_newline_lf;
+
+const constantMultilineString = """
+a
+b
+""";
+
+var nonConstantMultilineString = """
+a
+b
+""";
+
+const constantRawMultilineString = r"""
+\a
+\b
+""";
+
+var nonConstantRawMultilineString = r"""
+\a
+\b
+""";
diff --git a/tests/language/string/multiline_newline_runtime_1_test.dart b/tests/language/string/multiline_newline_runtime_1_test.dart
new file mode 100644
index 0000000..0b4647a
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_1_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+ const c4 = c1 == true ? 1 : 2;
+ Expect.equals(1, c4);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_2_test.dart b/tests/language/string/multiline_newline_runtime_2_test.dart
new file mode 100644
index 0000000..984ee09
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_2_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+ const c5 = c2 == true ? 2 : 3;
+ Expect.equals(2, c5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_3_test.dart b/tests/language/string/multiline_newline_runtime_3_test.dart
new file mode 100644
index 0000000..8208eeae7
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_3_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+
+
+
+ const c6 = c3 == true ? 3 : 4;
+ Expect.equals(3, c6);
+
+
+
+
+
+
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_4_test.dart b/tests/language/string/multiline_newline_runtime_4_test.dart
new file mode 100644
index 0000000..caef817
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_4_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+
+
+
+
+
+
+ const c4r = c1r == true ? 1 : 2;
+ Expect.equals(1, c4r);
+
+
+
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_5_test.dart b/tests/language/string/multiline_newline_runtime_5_test.dart
new file mode 100644
index 0000000..6510e9c
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_5_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ const c5r = c2r == true ? 2 : 3;
+ Expect.equals(2, c5r);
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_6_test.dart b/tests/language/string/multiline_newline_runtime_6_test.dart
new file mode 100644
index 0000000..353fb28
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_6_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ const c6r = c3r == true ? 3 : 4;
+ Expect.equals(3, c6r);
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_runtime_test.dart b/tests/language/string/multiline_newline_runtime_test.dart
new file mode 100644
index 0000000..7fa95ca
--- /dev/null
+++ b/tests/language/string/multiline_newline_runtime_test.dart
@@ -0,0 +1,128 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/multiline_newline_test.dart b/tests/language/string/multiline_newline_test.dart
new file mode 100644
index 0000000..37ef0c7
--- /dev/null
+++ b/tests/language/string/multiline_newline_test.dart
@@ -0,0 +1,173 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'multiline_newline_cr.dart' as cr;
+import 'multiline_newline_crlf.dart' as crlf;
+import 'multiline_newline_lf.dart' as lf;
+
+main() {
+ Expect.equals(4, cr.constantMultilineString.length);
+ Expect.equals(4, crlf.constantMultilineString.length);
+ Expect.equals(4, lf.constantMultilineString.length);
+
+ Expect.equals(6, cr.constantRawMultilineString.length);
+ Expect.equals(6, crlf.constantRawMultilineString.length);
+ Expect.equals(6, lf.constantRawMultilineString.length);
+
+ Expect.equals(cr.constantMultilineString, crlf.constantMultilineString);
+ Expect.equals(crlf.constantMultilineString, lf.constantMultilineString);
+ Expect.equals(lf.constantMultilineString, cr.constantMultilineString);
+
+ Expect.equals(cr.constantRawMultilineString, crlf.constantRawMultilineString);
+ Expect.equals(crlf.constantRawMultilineString, lf.constantRawMultilineString);
+ Expect.equals(lf.constantRawMultilineString, cr.constantRawMultilineString);
+
+ Expect.equals(4, cr.nonConstantMultilineString.length);
+ Expect.equals(4, crlf.nonConstantMultilineString.length);
+ Expect.equals(4, lf.nonConstantMultilineString.length);
+
+ Expect.equals(6, cr.nonConstantRawMultilineString.length);
+ Expect.equals(6, crlf.nonConstantRawMultilineString.length);
+ Expect.equals(6, lf.nonConstantRawMultilineString.length);
+
+ Expect.equals(cr.nonConstantMultilineString, crlf.nonConstantMultilineString);
+ Expect.equals(crlf.nonConstantMultilineString, lf.nonConstantMultilineString);
+ Expect.equals(lf.nonConstantMultilineString, cr.nonConstantMultilineString);
+
+ Expect.equals(
+ cr.nonConstantRawMultilineString, crlf.nonConstantRawMultilineString);
+ Expect.equals(
+ crlf.nonConstantRawMultilineString, lf.nonConstantRawMultilineString);
+ Expect.equals(
+ lf.nonConstantRawMultilineString, cr.nonConstantRawMultilineString);
+
+ const c1 =
+ cr.constantMultilineString == crlf.constantMultilineString ? true : null;
+ const c2 =
+ crlf.constantMultilineString == lf.constantMultilineString ? true : null;
+ const c3 =
+ lf.constantMultilineString == cr.constantMultilineString ? true : null;
+ Expect.isTrue(c1);
+ Expect.isTrue(c2);
+ Expect.isTrue(c3);
+
+ const c1r = cr.constantRawMultilineString == crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c2r = crlf.constantRawMultilineString == lf.constantRawMultilineString
+ ? true
+ : null;
+ const c3r = lf.constantRawMultilineString == cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isTrue(c1r);
+ Expect.isTrue(c2r);
+ Expect.isTrue(c3r);
+
+ const c4 = c1 ? 1 : 2;
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(1, c4);
+
+ const c5 = c2 ? 2 : 3;
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(2, c5);
+
+ const c6 = c3 ? 3 : 4;
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(3, c6);
+
+ const c4r = c1r ? 1 : 2;
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(1, c4r);
+
+ const c5r = c2r ? 2 : 3;
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(2, c5r);
+
+ const c6r = c3r ? 3 : 4;
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ Expect.equals(3, c6r);
+
+ const c7 =
+ cr.constantMultilineString != crlf.constantMultilineString ? true : null;
+ const c8 =
+ crlf.constantMultilineString != lf.constantMultilineString ? true : null;
+ const c9 =
+ lf.constantMultilineString != cr.constantMultilineString ? true : null;
+ Expect.isNull(c7);
+ Expect.isNull(c8);
+ Expect.isNull(c9);
+
+ const c7r = cr.constantRawMultilineString != crlf.constantRawMultilineString
+ ? true
+ : null;
+ const c8r = crlf.constantRawMultilineString != lf.constantRawMultilineString
+ ? true
+ : null;
+ const c9r = lf.constantRawMultilineString != cr.constantRawMultilineString
+ ? true
+ : null;
+ Expect.isNull(c7r);
+ Expect.isNull(c8r);
+ Expect.isNull(c9r);
+
+ // What's the deal with the compile-time errors below? This is to validate
+ // that constants are evaluated correctly at compile-time (or analysis
+ // time). For example, only if [c7] is evaluated correctly does it become
+ // null which leads to a compile-time error (as it isn't a boolean). For
+ // tools like dart2js, this ensures that the compile-time evaluation of
+ // constants is similar to the runtime evaluation tested above. For tools
+ // like the analyzer, this ensures that evaluation is tested (there's no
+ // runtime evaluation).
+ const c10 = c7 ? 1 : 2;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ const c11 = c8 ? 2 : 3;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ const c12 = c9 ? 3 : 4;
+ // ^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+
+ const c10r = c7r ? 1 : 2;
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ const c11r = c8r ? 2 : 3;
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+ const c12r = c9r ? 3 : 4;
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_EVAL_TYPE_BOOL
+ // [cfe] A value of type 'bool?' can't be assigned to a variable of type 'bool'.
+ // ^^^
+ // [analyzer] STATIC_WARNING.UNCHECKED_USE_OF_NULLABLE_VALUE
+}
diff --git a/tests/language/string/multiline_strings_test.dart b/tests/language/string/multiline_strings_test.dart
new file mode 100644
index 0000000..fa96fb1
--- /dev/null
+++ b/tests/language/string/multiline_strings_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Note: This test relies on LF line endings in the source file.
+
+import "package:expect/expect.dart";
+
+main() {
+ Expect.equals(
+ 'foo',
+ '''
+foo''');
+
+ Expect.equals(
+ '\\\nfoo',
+ '''\\
+foo''');
+
+ Expect.equals(
+ '\t\nfoo',
+ '''\t
+foo''');
+
+ Expect.equals(
+ 'foo',
+ '''\
+foo''');
+
+ Expect.equals(
+ 'foo',
+ '''\ \
+foo''');
+
+ Expect.equals(
+ ' \nfoo',
+ '''\x20
+foo''');
+
+ String x = ' ';
+ Expect.equals(
+ ' \nfoo',
+ '''$x
+foo''');
+
+ Expect.equals(
+ 'foo',
+ r'''
+foo''');
+
+ Expect.equals(
+ '\\\\\nfoo',
+ r'''\\
+foo''');
+
+ Expect.equals(
+ '\\t\nfoo',
+ r'''\t
+foo''');
+
+ Expect.equals(
+ 'foo',
+ r'''\
+foo''');
+
+ Expect.equals(
+ 'foo',
+ r'''\ \
+foo''');
+}
diff --git a/tests/language/string/no_operator_runtime_test.dart b/tests/language/string/no_operator_runtime_test.dart
new file mode 100644
index 0000000..ebf1dc7
--- /dev/null
+++ b/tests/language/string/no_operator_runtime_test.dart
@@ -0,0 +1,29 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+main() {
+ var x = "x";
+ var y = "y";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/tests/language/string/no_operator_test.dart b/tests/language/string/no_operator_test.dart
new file mode 100644
index 0000000..e6da249
--- /dev/null
+++ b/tests/language/string/no_operator_test.dart
@@ -0,0 +1,74 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+main() {
+ var x = "x";
+ var y = "y";
+ Expect.throws(() => x < y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '<' isn't defined for the class 'String'.
+ Expect.throws(() => x <= y);
+ // ^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '<=' isn't defined for the class 'String'.
+ Expect.throws(() => x > y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '>' isn't defined for the class 'String'.
+ Expect.throws(() => x >= y);
+ // ^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '>=' isn't defined for the class 'String'.
+ Expect.throws(() => x - y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '-' isn't defined for the class 'String'.
+ Expect.throws(() => x * y);
+ // ^
+ // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [cfe] A value of type 'String' can't be assigned to a variable of type 'int'.
+ Expect.throws(() => x / y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '/' isn't defined for the class 'String'.
+ Expect.throws(() => x ~/ y);
+ // ^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '~/' isn't defined for the class 'String'.
+ Expect.throws(() => x % y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '%' isn't defined for the class 'String'.
+ Expect.throws(() => x >> y);
+ // ^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '>>' isn't defined for the class 'String'.
+ Expect.throws(() => x << y);
+ // ^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '<<' isn't defined for the class 'String'.
+ Expect.throws(() => x & y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '&' isn't defined for the class 'String'.
+ Expect.throws(() => x | y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '|' isn't defined for the class 'String'.
+ Expect.throws(() => x ^ y);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '^' isn't defined for the class 'String'.
+ Expect.throws(() => -x);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator 'unary-' isn't defined for the class 'String'.
+ Expect.throws(() => ~x);
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+ // [cfe] The operator '~' isn't defined for the class 'String'.
+}
diff --git a/tests/language/string/optimizations_test.dart b/tests/language/string/optimizations_test.dart
new file mode 100644
index 0000000..a40bc0b
--- /dev/null
+++ b/tests/language/string/optimizations_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js's type inferrer, that used to not
+// correctly infer optional named parameters.
+
+import "package:expect/expect.dart";
+import "../compiler_annotations.dart";
+
+@DontInline()
+foo({path}) {
+ () => 42;
+ return path.toString();
+}
+
+@DontInline()
+bar({path}) {
+ () => 42;
+ return path;
+}
+
+main() {
+ var a = <Object>[foo(path: '42'), foo(), 42, bar(path: '54')];
+ Expect.isTrue(a[1] is String);
+ Expect.throwsNoSuchMethodError(() => bar().concat('54'));
+}
diff --git a/tests/language/string/overflow.dart b/tests/language/string/overflow.dart
new file mode 100644
index 0000000..8b01e19
--- /dev/null
+++ b/tests/language/string/overflow.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test to ensure that the VM does not have an integer overflow issue
+// when concatenating strings.
+
+import "package:expect/expect.dart";
+
+main() {
+ String a = "a";
+ for (; a.length < 256 * 1024 * 1024;) a = a + a;
+
+ var exception_thrown = false;
+ try {
+ var concat = "$a$a$a$a$a$a$a$a";
+ } on OutOfMemoryError catch (exc) {
+ exception_thrown = true;
+ }
+ Expect.isTrue(exception_thrown);
+}
diff --git a/tests/language/string/raw_string_test.dart b/tests/language/string/raw_string_test.dart
new file mode 100644
index 0000000..358f882
--- /dev/null
+++ b/tests/language/string/raw_string_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Note: This test relies on LF line endings in the source file.
+
+import "package:expect/expect.dart";
+
+class RawStringTest {
+ static testMain() {
+ Expect.equals("abcd", r"abcd");
+ Expect.equals("", r"");
+ Expect.equals("", r'');
+ Expect.equals("", r"""""");
+ Expect.equals("", r'''''');
+ Expect.equals("''''", r"''''");
+ Expect.equals('""""', r'""""');
+ Expect.equals(
+ "1\n2\n3",
+ r"""1
+2
+3""");
+ Expect.equals(
+ "1\n2\n3",
+ r'''1
+2
+3''');
+ Expect.equals(
+ "1",
+ r"""
+1""");
+ Expect.equals(
+ "1",
+ r'''
+1''');
+ Expect.equals("'", r"'");
+ Expect.equals('"', r'"');
+ Expect.equals("1", r"1");
+ Expect.equals("1", r"1");
+ Expect.equals("\$", r"$");
+ Expect.equals("\\", r"\");
+ Expect.equals("\\", r'\');
+ Expect.equals("\${12}", r"${12}");
+ Expect.equals("\\a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\l\\m",
+ r"\a\b\c\d\e\f\g\h\i\j\k\l\m");
+ Expect.equals("\\n\\o\\p\\q\\r\\s\\t\\u\\v\\w\\x\\y\\z",
+ r"\n\o\p\q\r\s\t\u\v\w\x\y\z");
+ }
+}
+
+main() {
+ RawStringTest.testMain();
+}
diff --git a/tests/language/string/runtime_test.dart b/tests/language/string/runtime_test.dart
new file mode 100644
index 0000000..41a0d8e
--- /dev/null
+++ b/tests/language/string/runtime_test.dart
@@ -0,0 +1,47 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Replace with shared test once interface issues clarified.
+
+import "package:expect/expect.dart";
+
+class StringTest {
+ static testMain() {
+ testCodePoints();
+ testNoSuchMethod();
+ testStringsJoin();
+ testCharCodes();
+ }
+
+ static testCodePoints() {
+ String str = "string";
+ for (int i = 0; i < str.length; i++) {
+ Expect.equals(true, str[i] is String);
+ Expect.equals(true, str.codeUnitAt(i) is int);
+ }
+ }
+
+ static testStringsJoin() {
+ List<String> a = ["Hello", "World"];
+ String s = a.join("*^*");
+ Expect.equals("Hello*^*World", s);
+ }
+
+ static testNoSuchMethod() {
+ String a = "Hello";
+
+ }
+
+ static testCharCodes() {
+ String s = new String.fromCharCodes(const [0x41, 0xC1, 0x424]);
+ Expect.equals("A", s[0]);
+ Expect.equals(0x424, s.codeUnitAt(2));
+ }
+}
+
+main() {
+ StringTest.testMain();
+}
diff --git a/tests/language/string/split_test.dart b/tests/language/string/split_test.dart
new file mode 100644
index 0000000..2517237
--- /dev/null
+++ b/tests/language/string/split_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Issue 24043.
+
+import "package:expect/expect.dart";
+
+class EvilMatch implements Match {
+ int get start => 100000000;
+ int get end => 3;
+ bool noSuchMethod(Invocation im) => false; // To appease dartanalyzer.
+}
+
+class EvilIterator implements Iterator<Match> {
+ bool moveNext() => true;
+ EvilMatch get current => new EvilMatch();
+}
+
+class EvilIterable extends Iterable<Match> {
+ get iterator => new EvilIterator();
+}
+
+class EvilPattern implements Pattern {
+ allMatches(String s, [int start = 0]) => new EvilIterable();
+ bool noSuchMethod(Invocation im) => false; // To appease dartanalyzer.
+}
+
+void main() {
+ Expect.throwsRangeError(() => "foo".split(new EvilPattern())[0].length);
+}
diff --git a/tests/language/string/string_test.dart b/tests/language/string/string_test.dart
new file mode 100644
index 0000000..1ab3f92
--- /dev/null
+++ b/tests/language/string/string_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Replace with shared test once interface issues clarified.
+
+import "package:expect/expect.dart";
+
+class StringTest {
+ static testMain() {
+ testCodePoints();
+ testNoSuchMethod();
+ testStringsJoin();
+ testCharCodes();
+ }
+
+ static testCodePoints() {
+ String str = "string";
+ for (int i = 0; i < str.length; i++) {
+ Expect.equals(true, str[i] is String);
+ Expect.equals(true, str.codeUnitAt(i) is int);
+ }
+ }
+
+ static testStringsJoin() {
+ List<String> a = ["Hello", "World"];
+ String s = a.join("*^*");
+ Expect.equals("Hello*^*World", s);
+ }
+
+ static testNoSuchMethod() {
+ String a = "Hello";
+ a[1] = 12;
+// ^^^
+// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_OPERATOR
+// [cfe] The operator '[]=' isn't defined for the class 'String'.
+ }
+
+ static testCharCodes() {
+ String s = new String.fromCharCodes(const [0x41, 0xC1, 0x424]);
+ Expect.equals("A", s[0]);
+ Expect.equals(0x424, s.codeUnitAt(2));
+ }
+}
+
+main() {
+ StringTest.testMain();
+}
diff --git a/tests/language/string/substring_runtime_test.dart b/tests/language/string/substring_runtime_test.dart
new file mode 100644
index 0000000..38007ad
--- /dev/null
+++ b/tests/language/string/substring_runtime_test.dart
@@ -0,0 +1,20 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart version of two-argument Ackermann-Peter function.
+
+import "package:expect/expect.dart";
+
+main() {
+ try {
+
+
+ } on TypeError catch (e) {
+ // OK.
+ } on ArgumentError catch (e) {
+ // OK.
+ }
+}
diff --git a/tests/language/string/substring_test.dart b/tests/language/string/substring_test.dart
new file mode 100644
index 0000000..bf2ce99
--- /dev/null
+++ b/tests/language/string/substring_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart version of two-argument Ackermann-Peter function.
+
+import "package:expect/expect.dart";
+
+main() {
+ try {
+ print("abcdef".substring(1.5, 3.5));
+ // ^^^
+ // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [cfe] The argument type 'double' can't be assigned to the parameter type 'int'.
+ // ^^^
+ // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [cfe] The argument type 'double' can't be assigned to the parameter type 'int'.
+ Expect.fail("Should have thrown an exception");
+ } on TypeError catch (e) {
+ // OK.
+ } on ArgumentError catch (e) {
+ // OK.
+ }
+}
diff --git a/tests/language/string/supertype_checked_test.dart b/tests/language/string/supertype_checked_test.dart
new file mode 100644
index 0000000..016c757
--- /dev/null
+++ b/tests/language/string/supertype_checked_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// This tests a bug in dart2js which caused the compiler to emit bad
+// type assertions for supertypes of String.
+
+class A implements Comparable<A> {
+ int value;
+
+ A(this.value);
+
+ int compareTo(Object other) {
+ A o = promote(other);
+ return value.compareTo(o.value);
+ }
+
+ A promote(var other) {
+ return other;
+ }
+}
+
+main() {
+ var a = new A(1);
+ var b = new A(2);
+ Expect.equals(-1, a.compareTo(b));
+}
diff --git a/tests/language/string/unicode1_test.dart b/tests/language/string/unicode1_test.dart
new file mode 100644
index 0000000..04a9f5f
--- /dev/null
+++ b/tests/language/string/unicode1_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// (backslash) uXXXX must have exactly 4 hex digits.
+
+main() {
+ var str = "Foo\u00";
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+ // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+ str = "Foo\uDEEMBar";
+ // ^^^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+ // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+}
diff --git a/tests/language/string/unicode2_test.dart b/tests/language/string/unicode2_test.dart
new file mode 100644
index 0000000..4624fbd
--- /dev/null
+++ b/tests/language/string/unicode2_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// \u{X*} should have 1-6 hex digits.
+
+main() {
+ var str = "Foo\u{}Bar";
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+ // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+ str = "Foo\u{000000000}Bar";
+ str = "Foo\u{DEAF!}Bar";
+ // ^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+ // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+}
diff --git a/tests/language/string/unicode3_test.dart b/tests/language/string/unicode3_test.dart
new file mode 100644
index 0000000..3c04303
--- /dev/null
+++ b/tests/language/string/unicode3_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Backslash xXX must have exactly 2 hex digits.
+
+main() {
+ var str = "Foo\x0";
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_HEX_ESCAPE
+ // [cfe] An escape sequence starting with '\x' must be followed by 2 hexadecimal digits.
+ str = "Foo\xF Bar";
+ // ^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_HEX_ESCAPE
+ // [cfe] An escape sequence starting with '\x' must be followed by 2 hexadecimal digits.
+}
diff --git a/tests/language/string/unicode4_test.dart b/tests/language/string/unicode4_test.dart
new file mode 100644
index 0000000..89095fa
--- /dev/null
+++ b/tests/language/string/unicode4_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Unicode escapes must refer to valid Unicode points and not surrogate
+/// characters.
+
+main() {
+ var str = "Foo\u{FFFFFF}";
+ // ^^^^^^^^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_CODE_POINT
+ // [cfe] The escape sequence starting with '\u' isn't a valid code point.
+ str = "Foo\uD800";
+ str = "Foo\uDC00";
+}
diff --git a/tests/language/string/unicode_bom_middle_test.dart b/tests/language/string/unicode_bom_middle_test.dart
new file mode 100644
index 0000000..e620b2b
--- /dev/null
+++ b/tests/language/string/unicode_bom_middle_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+int inscrutable(int x) => x == 0 ? 0 : x | inscrutable(x & (x - 1));
+
+foo(x) {
+ if (inscrutable(1999) == 1999) return x;
+ return 499;
+}
+
+main() {
+ Expect.equals(3, "xx".length); // BOM character between the xs.
+ Expect.equals(3, foo("xx").length); // BOM character between the xs.
+}
diff --git a/tests/language/string/unicode_bom_test.dart b/tests/language/string/unicode_bom_test.dart
new file mode 100644
index 0000000..2e23445
--- /dev/null
+++ b/tests/language/string/unicode_bom_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// This file is saved with a BOM character (as first character). This character
+// should be ignored.
+// Tests that files with a BOM character are correctly handled.
+
+main() {
+ /* do nothing. */
+}
diff --git a/tests/language/string/unicode_hash_test.dart b/tests/language/string/unicode_hash_test.dart
new file mode 100644
index 0000000..430c51e
--- /dev/null
+++ b/tests/language/string/unicode_hash_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+main() {
+ Expect.equals("\u{10412}", "𐐒"); // Second string is literal U+10412.
+ Expect.equals("\u{10412}".hashCode, "𐐒".hashCode);
+}
diff --git a/tests/language/super/abstract_method_test.dart b/tests/language/super/abstract_method_test.dart
new file mode 100644
index 0000000..19c877a
--- /dev/null
+++ b/tests/language/super/abstract_method_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that a method overridden by an abstract method is called at
+// runtime.
+
+import "package:expect/expect.dart";
+
+class Base {
+ foo() => 42;
+}
+
+abstract class A extends Base {
+ foo();
+}
+
+class B extends A {
+ testSuperCall() => super.foo();
+ foo() =>
+ 42; // required since if is removed, then a warning is introduced on 'B' above
+}
+
+main() {
+ Expect.equals(42, new B().foo());
+ Expect.equals(42, new B().testSuperCall());
+}
diff --git a/tests/language/super/additional_interface_adds_optional_args_supercall_test.dart b/tests/language/super/additional_interface_adds_optional_args_supercall_test.dart
new file mode 100644
index 0000000..534a590
--- /dev/null
+++ b/tests/language/super/additional_interface_adds_optional_args_supercall_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ void foo() {}
+}
+
+abstract class I {
+ void foo([x]);
+}
+
+abstract class B extends A implements I {
+ // If this class were concrete, there would be a problem, since `new
+ // B().foo(42)` would be statically allowed, but would lead to invalid
+ // arguments being passed to A.foo. But since the class is abstract, there is
+ // no problem.
+}
+
+class C extends B {
+ void foo([x]) {
+ // But it is a problem to try to pass `x` along to super, since the super
+ // method is A.foo.
+ super.foo(/*@compile-error=unspecified*/ x);
+ }
+}
+
+void f(B b) {
+ b.foo(42);
+}
+
+main() {
+ f(new C());
+}
diff --git a/tests/language/super/all_named_constructor_test.dart b/tests/language/super/all_named_constructor_test.dart
new file mode 100644
index 0000000..72c8637
--- /dev/null
+++ b/tests/language/super/all_named_constructor_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing implicit invocation of super constructor with all
+// named parameters.
+
+import "package:expect/expect.dart";
+
+var res = 0;
+
+class A {
+ A([int v = 1]) {
+ res += v;
+ }
+}
+
+class B extends A {
+ B([int v = 2]) {
+ res += v;
+ }
+}
+
+main() {
+ new B();
+ Expect.equals(3, res);
+}
diff --git a/tests/language/super/assign_runtime_test.dart b/tests/language/super/assign_runtime_test.dart
new file mode 100644
index 0000000..77f3ddb
--- /dev/null
+++ b/tests/language/super/assign_runtime_test.dart
@@ -0,0 +1,22 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ int x = -1;
+}
+
+class C extends A {
+ void setX(int value) {
+ super.x = value;
+ }
+}
+
+main() {
+ A a = new C();
+ a.x = 37;
+
+}
diff --git a/tests/language/super/assign_test.dart b/tests/language/super/assign_test.dart
new file mode 100644
index 0000000..bfb2c38
--- /dev/null
+++ b/tests/language/super/assign_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ int x = -1;
+}
+
+class C extends A {
+ void setX(int value) {
+ super.x = value;
+ }
+}
+
+main() {
+ A a = new C();
+ a.x = 37;
+ a.setX(42);
+ //^^^^
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
+ // [cfe] The method 'setX' isn't defined for the class 'A'.
+}
diff --git a/tests/language/super/bound_closure_test.dart b/tests/language/super/bound_closure_test.dart
new file mode 100644
index 0000000..554b0e2
--- /dev/null
+++ b/tests/language/super/bound_closure_test.dart
@@ -0,0 +1,149 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ bar([var optional = 1]) => 498 + optional;
+ bar2({namedOptional: 2}) => 40 + namedOptional;
+ bar3(x, [var optional = 3]) => x + 498 + optional;
+ bar4(x, {namedOptional: 4}) => 422 + x + namedOptional;
+
+ // Gee is the same as bar, but we make sure that gee is used. Potentially
+ // this yields different code if the redirecting stub exists.
+ gee([var optional = 1]) => 498 + optional;
+ gee2({namedOptional: 2}) => 40 + namedOptional;
+ gee3(x, [var optional = 3]) => x + 498 + optional;
+ gee4(x, {namedOptional: 4}) => 422 + x + namedOptional;
+
+ // Use identifiers that could be intercepted.
+ add([var optional = 33]) => 1234 + optional;
+ trim({namedOptional: 22}) => 1313 + namedOptional;
+ sublist(x, [optional = 44]) => 4321 + optional + x;
+ splitMapJoin(x, {onMatch: 55, onNonMatch: 66}) =>
+ 111 + x + onMatch + onNonMatch;
+
+ // Other interceptable identifiers, but all of them are used.
+ shuffle([var optional = 121]) => 12342 + optional;
+ toList({growable: 2233}) => 13131 + growable;
+ lastIndexOf(x, [optional = 424]) => 14321 + optional + x;
+ lastWhere(x, {orElse: 555}) => x + 1213 + 555;
+}
+
+class B extends A {
+ // The closure `super.bar` is invoked without the optional argument.
+ // Dart2js must not generate a `bar$0 => bar$1(null)` closure, since that
+ // would redirect to B's `bar$1`. Instead it must enforce that `bar$0` in
+ // `A` redirects to A's bar$1.
+ foo() => confuse(super.bar)();
+ foo2() => confuse(super.bar)(2);
+ foo3() => confuse(super.bar2)();
+ foo4() => confuse(super.bar2)(namedOptional: 77);
+ foo5() => confuse(super.bar3)(-3);
+ foo6() => confuse(super.bar3)(-11, -19);
+ foo7() => confuse(super.bar4)(0);
+ foo8() => confuse(super.bar4)(3, namedOptional: 77);
+
+ fooGee() => confuse(super.gee)();
+ fooGee2() => confuse(super.gee)(2);
+ fooGee3() => confuse(super.gee2)();
+ fooGee4() => confuse(super.gee2)(namedOptional: 77);
+ fooGee5() => confuse(super.gee3)(-3);
+ fooGee6() => confuse(super.gee3)(-11, -19);
+ fooGee7() => confuse(super.gee4)(0);
+ fooGee8() => confuse(super.gee4)(3, namedOptional: 77);
+
+ fooIntercept() => confuse(super.add)();
+ fooIntercept2() => confuse(super.add)(2);
+ fooIntercept3() => confuse(super.trim)();
+ fooIntercept4() => confuse(super.trim)(namedOptional: 77);
+ fooIntercept5() => confuse(super.sublist)(-3);
+ fooIntercept6() => confuse(super.sublist)(-11, -19);
+ fooIntercept7() => confuse(super.splitMapJoin)(0);
+ fooIntercept8() => confuse(super.splitMapJoin)(3, onMatch: 77, onNonMatch: 8);
+
+ fooIntercept21() => confuse(super.shuffle)();
+ fooIntercept22() => confuse(super.shuffle)(2);
+ fooIntercept23() => confuse(super.toList)();
+ fooIntercept24() => confuse(super.toList)(growable: 77);
+ fooIntercept25() => confuse(super.lastIndexOf)(-3);
+ fooIntercept26() => confuse(super.lastIndexOf)(-11, -19);
+ fooIntercept27() => confuse(super.lastWhere)(0);
+ fooIntercept28() => confuse(super.lastWhere)(3, orElse: 77);
+
+ // Warning: overrides should not change default parameter values.
+ bar([var optional]) => -1; // //# 01: static type warning
+ bar2({namedOptional}) => -1; // //# 01: continued
+ bar3(x, [var optional]) => -1; // //# 01: continued
+ bar4(x, {namedOptional}) => -1; //# 01: continued
+
+ gee([var optional]) => -1; // //# 01: continued
+ gee2({namedOptional}) => -1; // //# 01: continued
+ gee3(x, [var optional]) => -1; // //# 01: continued
+ gee4(x, {namedOptional}) => -1; //# 01: continued
+
+ add([var optional = 33]) => -1;
+ trim({namedOptional: 22}) => -1;
+ sublist(x, [optional = 44]) => -1;
+ splitMapJoin(x, {onMatch: 55, onNonMatch: 66}) => -1;
+
+ shuffle([var optional = 121]) => -1;
+ toList({growable: 2233}) => -1;
+ lastIndexOf(x, [optional = 424]) => -1;
+ lastWhere(x, {orElse: 555}) => -1;
+}
+
+confuse(x) {
+ if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+ return x;
+}
+
+main() {
+ var list = [new A(), new B(), [], "foo"];
+ var a = list[confuse(0)];
+ dynamic b = list[confuse(1)];
+ var ignored = list[confuse(2)];
+ var ignored2 = list[confuse(3)];
+
+ var t = b.gee() + b.gee2() + b.gee3(9) + b.gee4(19);
+ Expect.equals(-4, t); //# 01: continued
+ t = b.shuffle() + b.toList() + b.lastIndexOf(1) + b.lastWhere(2);
+ Expect.equals(-4, t);
+
+ Expect.equals(499, b.foo()); // //# 01: continued
+ Expect.equals(500, b.foo2()); //# 01: continued
+ Expect.equals(42, b.foo3()); // //# 01: continued
+ Expect.equals(117, b.foo4()); //# 01: continued
+ Expect.equals(498, b.foo5()); //# 01: continued
+ Expect.equals(468, b.foo6()); //# 01: continued
+ Expect.equals(426, b.foo7()); //# 01: continued
+ Expect.equals(502, b.foo8()); //# 01: continued
+
+ Expect.equals(499, b.fooGee()); // //# 01: continued
+ Expect.equals(500, b.fooGee2()); //# 01: continued
+ Expect.equals(42, b.fooGee3()); // //# 01: continued
+ Expect.equals(117, b.fooGee4()); //# 01: continued
+ Expect.equals(498, b.fooGee5()); //# 01: continued
+ Expect.equals(468, b.fooGee6()); //# 01: continued
+ Expect.equals(426, b.fooGee7()); //# 01: continued
+ Expect.equals(502, b.fooGee8()); //# 01: continued
+
+ Expect.equals(1267, b.fooIntercept());
+ Expect.equals(1236, b.fooIntercept2());
+ Expect.equals(1335, b.fooIntercept3());
+ Expect.equals(1390, b.fooIntercept4());
+ Expect.equals(4362, b.fooIntercept5());
+ Expect.equals(4291, b.fooIntercept6());
+ Expect.equals(232, b.fooIntercept7());
+ Expect.equals(199, b.fooIntercept8());
+
+ Expect.equals(12463, b.fooIntercept21());
+ Expect.equals(12344, b.fooIntercept22());
+ Expect.equals(15364, b.fooIntercept23());
+ Expect.equals(13208, b.fooIntercept24());
+ Expect.equals(14742, b.fooIntercept25());
+ Expect.equals(14291, b.fooIntercept26());
+ Expect.equals(1768, b.fooIntercept27());
+ Expect.equals(1771, b.fooIntercept28());
+}
diff --git a/tests/language/super/call2_test.dart b/tests/language/super/call2_test.dart
new file mode 100644
index 0000000..13ae089
--- /dev/null
+++ b/tests/language/super/call2_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regresion test for bug discovered in frog handling super calls: the test case
+// mixes generics, super calls, and purposely doesn't allocate the base type.
+//
+// Also is a regression test for https://github.com/dart-lang/sdk/issues/31973
+
+import 'package:expect/expect.dart';
+
+class C<T> {
+ foo(T a) {}
+}
+
+class D<T> extends C<T> {
+ foo(T a) {
+ super.foo(a); // used to be resolved incorrectly and generate this.foo(a).
+ }
+}
+
+class A {
+ static int _value = -1;
+ Function foo = (int x) => _value = x + 1;
+}
+
+class B extends A {
+ void m(int x) {
+ super.foo(x);
+ }
+}
+
+main() {
+ var d = new D();
+ d.foo(null);
+
+ var b = new B();
+ b.m(41);
+ Expect.equals(42, A._value);
+}
diff --git a/tests/language/super/call3_runtime_test.dart b/tests/language/super/call3_runtime_test.dart
new file mode 100644
index 0000000..1df0b3c
--- /dev/null
+++ b/tests/language/super/call3_runtime_test.dart
@@ -0,0 +1,49 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing implicit super calls with bad arguments or no default
+// constructor in super class.
+
+import "package:expect/expect.dart";
+
+class A {
+ A(
+
+ );
+ final foo = 499;
+}
+
+class B extends A {}
+
+class B2 extends A {
+ B2();
+ B2.named() : this.x = 499;
+ var x;
+}
+
+class C {
+ C
+
+ ();
+ final foo = 499;
+}
+
+class D extends C {}
+
+class D2 extends C {
+ D2();
+ D2.named() : this.x = 499;
+ var x;
+}
+
+main() {
+ Expect.equals(499, new B().foo);
+ Expect.equals(499, new B2().foo);
+ Expect.equals(499, new B2.named().foo);
+ Expect.equals(499, new D().foo);
+ Expect.equals(499, new D2().foo);
+ Expect.equals(499, new D2.named().foo);
+}
diff --git a/tests/language/super/call3_test.dart b/tests/language/super/call3_test.dart
new file mode 100644
index 0000000..7c43edf
--- /dev/null
+++ b/tests/language/super/call3_test.dart
@@ -0,0 +1,68 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing implicit super calls with bad arguments or no default
+// constructor in super class.
+
+import "package:expect/expect.dart";
+
+class A {
+ A(
+ this.x
+// ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD
+// ^
+// [cfe] 'x' isn't an instance field of this class.
+ );
+ final foo = 499;
+}
+
+class B extends A {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.NO_DEFAULT_SUPER_CONSTRUCTOR
+// [cfe] The superclass, 'A', has no unnamed constructor that takes no arguments.
+
+class B2 extends A {
+ B2();
+//^^
+// [analyzer] COMPILE_TIME_ERROR.NO_DEFAULT_SUPER_CONSTRUCTOR
+// [cfe] The superclass, 'A', has no unnamed constructor that takes no arguments.
+ B2.named() : this.x = 499;
+//^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.NO_DEFAULT_SUPER_CONSTRUCTOR
+// [cfe] The superclass, 'A', has no unnamed constructor that takes no arguments.
+ var x;
+}
+
+class C {
+ C
+ .named
+ ();
+ final foo = 499;
+}
+
+class D extends C {}
+// ^
+// [analyzer] COMPILE_TIME_ERROR.NO_DEFAULT_SUPER_CONSTRUCTOR
+// [cfe] The superclass, 'C', has no unnamed constructor that takes no arguments.
+
+class D2 extends C {
+ D2();
+//^^
+// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER
+// [cfe] The superclass, 'C', has no unnamed constructor that takes no arguments.
+ D2.named() : this.x = 499;
+//^^
+// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER
+// [cfe] The superclass, 'C', has no unnamed constructor that takes no arguments.
+ var x;
+}
+
+main() {
+ Expect.equals(499, new B().foo);
+ Expect.equals(499, new B2().foo);
+ Expect.equals(499, new B2.named().foo);
+ Expect.equals(499, new D().foo);
+ Expect.equals(499, new D2().foo);
+ Expect.equals(499, new D2.named().foo);
+}
diff --git a/tests/language/super/call4_test.dart b/tests/language/super/call4_test.dart
new file mode 100644
index 0000000..aced9d7
--- /dev/null
+++ b/tests/language/super/call4_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class C {
+ bool foo();
+ bool bar(int a);
+ bool baz({int b});
+ bool boz(int a, {int c});
+
+ bool noSuchMethod(Invocation im) => true;
+}
+
+class D extends C {
+ bool noSuchMethod(Invocation im) => false;
+
+ // `super.foo()` et al. will statically use [C]'s [noSuchMethod] forwarder,
+ // but the forwarder will (virtually) call [D]'s [noSuchMethod] at runtime.
+
+ test1() {
+ return super.foo();
+ }
+
+ test2() {
+ return super.bar(1);
+ }
+
+ test3() {
+ return super.baz(b: 2);
+ }
+
+ test4() {
+ return super.boz(1, c: 2);
+ }
+}
+
+main() {
+ var d = new D();
+ Expect.isFalse(d.test1());
+ Expect.isFalse(d.test2());
+ Expect.isFalse(d.test3());
+ Expect.isFalse(d.test4());
+}
diff --git a/tests/language/super/call_test.dart b/tests/language/super/call_test.dart
new file mode 100644
index 0000000..384ee61
--- /dev/null
+++ b/tests/language/super/call_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing super calls
+
+import "package:expect/expect.dart";
+
+class A {
+ A() : field = 0 {}
+ int field;
+ incrField() {
+ field++;
+ }
+
+ timesX(v) {
+ return v * 2;
+ }
+}
+
+class B extends A {
+ incrField() {
+ field++;
+ super.incrField();
+ }
+
+ timesX(v) {
+ return super.timesX(v) * 3;
+ }
+
+ B() : super() {}
+}
+
+class SuperCallTest {
+ static testMain() {
+ var b = new B();
+ b.incrField();
+ Expect.equals(2, b.field);
+ Expect.equals(12, b.timesX(2));
+ }
+}
+
+main() {
+ SuperCallTest.testMain();
+}
diff --git a/tests/language/super/closure_test.dart b/tests/language/super/closure_test.dart
new file mode 100644
index 0000000..ad159ce
--- /dev/null
+++ b/tests/language/super/closure_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Dart test program for testing access to super from closure.
+
+class Super {
+ var superX = "super";
+ get x => superX;
+}
+
+class Sub extends Super {
+ var subX = "sub";
+ get x => subX;
+
+ buildClosures() => [() => x, () => this.x, () => super.x];
+}
+
+main() {
+ var closures = new Sub().buildClosures();
+ Expect.equals(3, closures.length);
+ Expect.equals("sub", closures[0]());
+ Expect.equals("sub", closures[1]());
+ Expect.equals("super", closures[2]());
+}
diff --git a/tests/language/super/conditional_operator_runtime_test.dart b/tests/language/super/conditional_operator_runtime_test.dart
new file mode 100644
index 0000000..2529639
--- /dev/null
+++ b/tests/language/super/conditional_operator_runtime_test.dart
@@ -0,0 +1,45 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the ?. operator cannot be used with "super".
+
+class B {
+ B();
+ B.namedConstructor();
+ var field = 1;
+ method() => 1;
+}
+
+class C extends B {
+ C()
+
+ ;
+
+ test() {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+}
+
+main() {
+ new C().test();
+}
diff --git a/tests/language/super/conditional_operator_test.dart b/tests/language/super/conditional_operator_test.dart
new file mode 100644
index 0000000..7f09c55
--- /dev/null
+++ b/tests/language/super/conditional_operator_test.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the ?. operator cannot be used with "super".
+
+class B {
+ B();
+ B.namedConstructor();
+ var field = 1;
+ method() => 1;
+}
+
+class C extends B {
+ C()
+ : super?.namedConstructor()
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ // [cfe] Cannot use '?.' here.
+ // ^
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ ;
+
+ test() {
+ super?.field = 1;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ super?.field += 1;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ super?.field ??= 1;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ // ^
+ // [analyzer] STATIC_WARNING.DEAD_NULL_AWARE_EXPRESSION
+ super?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ 1 * super?.field;
+ // ^^^^^^^^^^^^
+ // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ -super?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ ~super?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ !super?.field;
+// ^^^^^^^^^^^^
+// [analyzer] STATIC_TYPE_WARNING.NON_BOOL_NEGATION_EXPRESSION
+// ^^
+// [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+// [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+// ^^
+// [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+// ^
+// [cfe] A value of type 'int' can't be assigned to a variable of type 'bool'.
+ --super?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ ++super?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ 1 * super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ -super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ ~super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ !super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ --super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ // ^
+ // [cfe] Can't assign to this.
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_ASSIGNABLE_SELECTOR
+ ++super?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ // [cfe] The operator '?.' cannot be used with 'super' because 'super' cannot be null.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
+ // ^
+ // [cfe] Can't assign to this.
+ // ^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_ASSIGNABLE_SELECTOR
+ }
+}
+
+main() {
+ new C().test();
+}
diff --git a/tests/language/super/field_2_test.dart b/tests/language/super/field_2_test.dart
new file mode 100644
index 0000000..51cc926
--- /dev/null
+++ b/tests/language/super/field_2_test.dart
@@ -0,0 +1,87 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:meta/meta.dart" show virtual;
+
+class A {
+ @virtual
+ var foo;
+ A(this.foo);
+
+ B_Sfoo() => 'A.B_Sfoo()';
+}
+
+class B extends A {
+ B(x) : super(x);
+
+ B_Sfoo() => super.foo;
+ BC_Sfoo() => super.foo;
+ BCD_Sfoo() => super.foo;
+}
+
+class C extends B {
+ var foo;
+ C(x, this.foo) : super(x);
+
+ BC_Sfoo() => super.foo;
+ BCD_Sfoo() => super.foo;
+}
+
+class D extends C {
+ D(x, y) : super(x, y);
+
+ BCD_Sfoo() => super.foo;
+}
+
+var inscrutable;
+
+main() {
+ inscrutable = (x) => x;
+
+ var b = new B('Ba');
+ var c = new C('Ca', 'Cc');
+ var d = new D('Da', 'Dc');
+
+ // Check access via plain getter.
+ var b_bc = inscrutable(true) ? b : c; // B, but compiler thinks can also be C
+ var c_bc = inscrutable(true) ? c : b; // C, but compiler thinks can also be B
+
+ Expect.equals('Ba', b.foo);
+ Expect.equals('Cc', c.foo);
+ Expect.equals('Dc', d.foo);
+ Expect.equals('Ba', b_bc.foo);
+ Expect.equals('Cc', c_bc.foo);
+
+ Expect.equals('Ba', inscrutable(b).foo);
+ Expect.equals('Cc', inscrutable(c).foo);
+ Expect.equals('Dc', inscrutable(d).foo);
+ Expect.equals('Ba', inscrutable(b_bc).foo);
+ Expect.equals('Cc', inscrutable(c_bc).foo);
+
+ // Check access via super.foo in various contexts
+ Expect.equals('Ba', b.B_Sfoo());
+ Expect.equals('Ca', c.B_Sfoo());
+ Expect.equals('Da', d.B_Sfoo());
+
+ Expect.equals('Ba', b.BC_Sfoo());
+ Expect.equals('Ca', c.BC_Sfoo());
+ Expect.equals('Da', d.BC_Sfoo());
+
+ Expect.equals('Ba', b.BCD_Sfoo());
+ Expect.equals('Ca', c.BCD_Sfoo());
+ Expect.equals('Dc', d.BCD_Sfoo());
+
+ Expect.equals('Ba', inscrutable(b).B_Sfoo());
+ Expect.equals('Ca', inscrutable(c).B_Sfoo());
+ Expect.equals('Da', inscrutable(d).B_Sfoo());
+
+ Expect.equals('Ba', inscrutable(b).BC_Sfoo());
+ Expect.equals('Ca', inscrutable(c).BC_Sfoo());
+ Expect.equals('Da', inscrutable(d).BC_Sfoo());
+
+ Expect.equals('Ba', inscrutable(b).BCD_Sfoo());
+ Expect.equals('Ca', inscrutable(c).BCD_Sfoo());
+ Expect.equals('Dc', inscrutable(d).BCD_Sfoo());
+}
diff --git a/tests/language/super/field_access_test.dart b/tests/language/super/field_access_test.dart
new file mode 100644
index 0000000..ffd1897
--- /dev/null
+++ b/tests/language/super/field_access_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ int foo;
+ A(this.foo);
+
+ raw$foo() => foo;
+ this$foo() => this.foo;
+}
+
+class B extends A {
+ int foo;
+ B.b1(x, this.foo) : super(x);
+ B.b2(x, y)
+ : this.foo = y,
+ super(x);
+ B.b3(x, y)
+ : this.foo = y,
+ super(x);
+
+ super$foo() => super.foo;
+ sum() => foo + super.foo;
+}
+
+test(b) {
+ Expect.equals(10, b.foo);
+ Expect.equals(10, b.raw$foo());
+ Expect.equals(10, b.this$foo());
+ Expect.equals(100, b.super$foo());
+ Expect.equals(110, b.sum());
+}
+
+main() {
+ test(new B.b1(100, 10));
+ test(new B.b2(100, 10));
+ test(new B.b3(100, 10));
+}
diff --git a/tests/language/super/field_test.dart b/tests/language/super/field_test.dart
new file mode 100644
index 0000000..e4dd127
--- /dev/null
+++ b/tests/language/super/field_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing super field access.
+
+import "package:expect/expect.dart";
+import "package:meta/meta.dart" show virtual;
+
+class A {
+ A() {
+ city = "Bern";
+ }
+ String greeting() {
+ return "Gruezi";
+ }
+
+ @virtual
+ String city = "";
+}
+
+class B extends A {
+ B() : super() {}
+ String greeting() {
+ return "Hola " + super.greeting();
+ }
+}
+
+class C extends B {
+ C() : super() {}
+ String greeting() {
+ return "Servus " + super.greeting();
+ }
+
+ String get city {
+ return "Basel " + super.city;
+ }
+}
+
+class SuperFieldTest {
+ static testMain() {
+ A a = new A();
+ B b = new B();
+ C c = new C();
+ Expect.equals("Gruezi", a.greeting());
+ Expect.equals("Hola Gruezi", b.greeting());
+ Expect.equals("Servus Hola Gruezi", c.greeting());
+
+ Expect.equals("Bern", a.city);
+ Expect.equals("Bern", b.city);
+ Expect.equals("Basel Bern", c.city);
+ c.city = "Zurich";
+ Expect.equals("Basel Zurich", c.city);
+ }
+}
+
+main() {
+ SuperFieldTest.testMain();
+}
diff --git a/tests/language/super/from_constructor_test.dart b/tests/language/super/from_constructor_test.dart
new file mode 100644
index 0000000..02e86fa
--- /dev/null
+++ b/tests/language/super/from_constructor_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+final results = [];
+
+int invoke(int f()) => f();
+
+class Base {
+ var f;
+ var z;
+
+ m(x) => results.add(x);
+
+ int g() {
+ return 42;
+ }
+}
+
+class C extends Base {
+ final Iterable _iter;
+
+ C(this._iter) {
+ _iter.map((x) => super.m(x)).toList();
+ super.f = _iter;
+ z = invoke(super.g);
+ }
+
+ int g() {
+ return -1;
+ }
+}
+
+main() {
+ var c = new C([1, 2, 3]);
+ Expect.listEquals([1, 2, 3], results);
+ Expect.listEquals([1, 2, 3], c.f);
+ Expect.equals(42, c.z);
+}
diff --git a/tests/language/super/implicit_closure_test.dart b/tests/language/super/implicit_closure_test.dart
new file mode 100644
index 0000000..c94997b
--- /dev/null
+++ b/tests/language/super/implicit_closure_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program for testing invocation of implicit closures.
+
+import "package:expect/expect.dart";
+
+class BaseClass {
+ BaseClass(this._i) {}
+ int foo() {
+ return _i;
+ }
+
+ int _i;
+}
+
+class DerivedClass extends BaseClass {
+ DerivedClass(this._y, int j) : super(j) {}
+ int foo() {
+ return _y;
+ }
+
+ getSuper() {
+ return super.foo;
+ }
+
+ int _y;
+}
+
+class SuperImplicitClosureTest {
+ static void testMain() {
+ DerivedClass obj = new DerivedClass(20, 10);
+
+ var ib = obj.foo;
+ Expect.equals(obj._y, ib());
+
+ ib = obj.getSuper();
+ Expect.equals(obj._i, ib());
+ }
+}
+
+main() {
+ SuperImplicitClosureTest.testMain();
+}
diff --git a/tests/language/super/in_async1_test.dart b/tests/language/super/in_async1_test.dart
new file mode 100644
index 0000000..b5cb4bd
--- /dev/null
+++ b/tests/language/super/in_async1_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<int> foo() async => 42;
+}
+
+class B extends A {
+ Future<int> foo() async {
+ var x = await super.foo();
+ return x + 1;
+ }
+}
+
+main() async {
+ Expect.equals(43, await new B().foo());
+}
diff --git a/tests/language/super/in_async2_test.dart b/tests/language/super/in_async2_test.dart
new file mode 100644
index 0000000..70df51f
--- /dev/null
+++ b/tests/language/super/in_async2_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<int> foo() async => 42;
+}
+
+class B extends A {
+ Future<int> foo() async {
+ var x = await super.foo();
+ var y = await super.foo();
+ return x + y;
+ }
+}
+
+main() async {
+ Expect.equals(84, await new B().foo());
+}
diff --git a/tests/language/super/in_async3_test.dart b/tests/language/super/in_async3_test.dart
new file mode 100644
index 0000000..9798010
--- /dev/null
+++ b/tests/language/super/in_async3_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<T> foo<T>(T x) async => x;
+}
+
+class B extends A {
+ Future<int> bar() async {
+ var x = await super.foo(41);
+ return x + 1;
+ }
+}
+
+main() async {
+ Expect.equals(42, await new B().bar());
+}
diff --git a/tests/language/super/in_async4_test.dart b/tests/language/super/in_async4_test.dart
new file mode 100644
index 0000000..2effbad
--- /dev/null
+++ b/tests/language/super/in_async4_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<T> foo<T>({required T x}) async => x;
+}
+
+class B extends A {
+ Future<int> bar() async {
+ var x = await super.foo(x: 41);
+ return x + 1;
+ }
+}
+
+main() async {
+ Expect.equals(42, await new B().bar());
+}
diff --git a/tests/language/super/in_async5_test.dart b/tests/language/super/in_async5_test.dart
new file mode 100644
index 0000000..acf6fe8
--- /dev/null
+++ b/tests/language/super/in_async5_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<int> get foo async => 42;
+}
+
+class B extends A {
+ Future<int> bar() async {
+ var x = await super.foo;
+ return x + 1;
+ }
+}
+
+main() async {
+ Expect.equals(43, await new B().bar());
+}
diff --git a/tests/language/super/in_async6_test.dart b/tests/language/super/in_async6_test.dart
new file mode 100644
index 0000000..3f51313
--- /dev/null
+++ b/tests/language/super/in_async6_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+import 'dart:async';
+
+class A {
+ Future<int> foo(int x, int y, int z) async => x + y + z;
+}
+
+class B extends A {
+ Future<int> foo(int x, int y, int z) async {
+ var w = await super.foo(x, y, z);
+ return w + 1;
+ }
+}
+
+main() async {
+ Expect.equals(7, await new B().foo(1, 2, 3));
+}
diff --git a/tests/language/super/in_constructor_test.dart b/tests/language/super/in_constructor_test.dart
new file mode 100644
index 0000000..621eee9
--- /dev/null
+++ b/tests/language/super/in_constructor_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class Foo {
+ bool myBoolean = false;
+
+ void set foo(bool b) {
+ print("Setting foo in Foo");
+ myBoolean = b;
+ }
+}
+
+class Baz extends Foo {
+ Baz() {
+ super.foo = true;
+ Expect.equals(true, super.myBoolean);
+ }
+}
+
+main() {
+ new Baz();
+}
diff --git a/tests/language/super/in_finally_test.dart b/tests/language/super/in_finally_test.dart
new file mode 100644
index 0000000..2610c7a
--- /dev/null
+++ b/tests/language/super/in_finally_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ T foo<T>({required T x}) => x;
+}
+
+class B extends A {
+ int bar() {
+ try {
+ throw 'bar';
+ return 1;
+ } finally {
+ var x = super.foo(x: 41);
+ return x + 1;
+ }
+ }
+}
+
+main() {
+ Expect.equals(42, new B().bar());
+}
diff --git a/tests/language/super/inferrer_test.dart b/tests/language/super/inferrer_test.dart
new file mode 100644
index 0000000..6fcaf8e
--- /dev/null
+++ b/tests/language/super/inferrer_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that dart2js's backend type inference handles super calls.
+
+import "package:expect/expect.dart";
+
+class A {
+ foo(a) => a + 42;
+}
+
+class B extends A {
+ bar() {
+ super.foo(null);
+ }
+}
+
+var a = [new A()];
+
+main() {
+ analyzeFirst();
+ analyzeSecond();
+}
+
+analyzeFirst() {
+ Expect.equals(84, a[0].foo(42));
+}
+
+analyzeSecond() {
+ Expect.throwsNoSuchMethodError(() => new B().bar());
+}
diff --git a/tests/language/super/mixin_test.dart b/tests/language/super/mixin_test.dart
new file mode 100644
index 0000000..e76a282
--- /dev/null
+++ b/tests/language/super/mixin_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Dart2js regression test: Test that the type mask for non-null exact Mixin is
+// created for Mixin.getter.
+
+import 'package:expect/expect.dart';
+
+class Mixin {
+ @pragma('dart2js:noInline')
+ get getter => 42;
+}
+
+class Superclass {}
+
+class Subclass extends Superclass with Mixin {
+ method() => super.getter;
+}
+
+void main() {
+ Expect.equals(42, new Subclass().method());
+}
diff --git a/tests/language/super/no_such_method1_test.dart b/tests/language/super/no_such_method1_test.dart
new file mode 100644
index 0000000..1b990b8
--- /dev/null
+++ b/tests/language/super/no_such_method1_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int foo();
+ noSuchMethod(im) => 42;
+}
+
+class B extends A {
+ noSuchMethod(im) => 87;
+
+ int foo() => super.foo();
+}
+
+main() {
+ Expect.equals(87, new B().foo());
+}
diff --git a/tests/language/super/no_such_method2_test.dart b/tests/language/super/no_such_method2_test.dart
new file mode 100644
index 0000000..a85c675
--- /dev/null
+++ b/tests/language/super/no_such_method2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int get foo;
+ noSuchMethod(im) => 42;
+}
+
+class B extends A {
+ noSuchMethod(im) => 87;
+
+ get foo => super.foo;
+}
+
+main() {
+ Expect.equals(87, new B().foo);
+}
diff --git a/tests/language/super/no_such_method3_test.dart b/tests/language/super/no_such_method3_test.dart
new file mode 100644
index 0000000..16433d8
--- /dev/null
+++ b/tests/language/super/no_such_method3_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+var result;
+
+class A {
+ set foo(int a);
+
+ noSuchMethod(im) {
+ result = 42;
+ }
+}
+
+class B extends A {
+ noSuchMethod(im) {
+ result = 87;
+ }
+
+ set foo(v) => super.foo = v;
+}
+
+main() {
+ new B().foo = 0;
+ Expect.equals(87, result);
+}
diff --git a/tests/language/super/no_such_method4_runtime_test.dart b/tests/language/super/no_such_method4_runtime_test.dart
new file mode 100644
index 0000000..f8d4880
--- /dev/null
+++ b/tests/language/super/no_such_method4_runtime_test.dart
@@ -0,0 +1,24 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int foo();
+
+ noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+ noSuchMethod(im) => 87;
+
+
+}
+
+main() {
+ Expect.equals(87, new B().foo());
+}
diff --git a/tests/language/super/no_such_method4_test.dart b/tests/language/super/no_such_method4_test.dart
new file mode 100644
index 0000000..9e83146
--- /dev/null
+++ b/tests/language/super/no_such_method4_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int foo();
+
+ noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+ noSuchMethod(im) => 87;
+
+ foo() => super.foo();
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.ABSTRACT_SUPER_MEMBER_REFERENCE
+ // [cfe] Superclass has no method named 'foo'.
+}
+
+main() {
+ Expect.equals(87, new B().foo());
+}
diff --git a/tests/language/super/no_such_method5_runtime_test.dart b/tests/language/super/no_such_method5_runtime_test.dart
new file mode 100644
index 0000000..94adb24
--- /dev/null
+++ b/tests/language/super/no_such_method5_runtime_test.dart
@@ -0,0 +1,22 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int foo();
+
+ noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+
+}
+
+main() {
+ Expect.equals(42, new B().foo());
+}
diff --git a/tests/language/super/no_such_method5_test.dart b/tests/language/super/no_such_method5_test.dart
new file mode 100644
index 0000000..eb923c1
--- /dev/null
+++ b/tests/language/super/no_such_method5_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+class A {
+ int foo();
+
+ noSuchMethod(im) => 42;
+}
+
+class B extends Object with A {
+ foo() => super.foo();
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.ABSTRACT_SUPER_MEMBER_REFERENCE
+ // [cfe] Superclass has no method named 'foo'.
+}
+
+main() {
+ Expect.equals(42, new B().foo());
+}
diff --git a/tests/language/super/non_const_test.dart b/tests/language/super/non_const_test.dart
new file mode 100644
index 0000000..06c9f73
--- /dev/null
+++ b/tests/language/super/non_const_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Check fails because const class extends from non const class.
+
+class Base {
+ Base() {}
+}
+
+class Sub extends Base {
+ const Sub(a) : a_ = a;
+ // ^^^
+ // [analyzer] COMPILE_TIME_ERROR.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER
+ // [cfe] A constant constructor can't call a non-constant super constructor.
+ final a_;
+}
+
+main() {
+ Sub(0);
+}
diff --git a/tests/language/super/operator_index2_test.dart b/tests/language/super/operator_index2_test.dart
new file mode 100644
index 0000000..d17c41e
--- /dev/null
+++ b/tests/language/super/operator_index2_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for super indexing operations.
+
+import "package:expect/expect.dart";
+
+class A {
+ var map = new Map<int, int>();
+ operator []=(a, b) {
+ map[a] = b;
+ }
+
+ operator [](a) => map[a];
+}
+
+class B extends A {
+ foo() {
+ super[4] = 42;
+ Expect.equals(42, super[4]);
+ super[4] += 5;
+ Expect.equals(47, super[4]);
+ }
+}
+
+main() {
+ new B().foo();
+}
diff --git a/tests/language/super/operator_index3_test.dart b/tests/language/super/operator_index3_test.dart
new file mode 100644
index 0000000..6162efd
--- /dev/null
+++ b/tests/language/super/operator_index3_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for operator[]= resolved in super class.
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+ operator []=(index, value) {
+ indexField[index] = value;
+ }
+}
+
+class B extends A {
+ operator [](index) => indexField[index];
+}
+
+class C extends B {
+ test() {
+ Expect.equals(42, super[0] = 42);
+ Expect.equals(42, super[0]);
+ Expect.equals(43, super[0] += 1);
+ Expect.equals(43, super[0]);
+ Expect.equals(43, super[0]++);
+ Expect.equals(44, super[0]);
+
+ Expect.equals(2, super[0] = 2);
+ Expect.equals(2, super[0]);
+ Expect.equals(3, super[0] += 1);
+ Expect.equals(3, super[0]);
+ Expect.equals(3, super[0]++);
+ Expect.equals(4, super[0]);
+ }
+}
+
+main() {
+ new C().test();
+}
diff --git a/tests/language/super/operator_index4_test.dart b/tests/language/super/operator_index4_test.dart
new file mode 100644
index 0000000..08f9608
--- /dev/null
+++ b/tests/language/super/operator_index4_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for operator[] resolved in the super class.
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+ operator [](index) => indexField[index];
+}
+
+class B extends A {
+ operator []=(index, value) {
+ indexField[index] = value;
+ }
+}
+
+class C extends B {
+ test() {
+ Expect.equals(42, super[0] = 42);
+ Expect.equals(42, super[0]);
+ Expect.equals(43, super[0] += 1);
+ Expect.equals(43, super[0]);
+ Expect.equals(43, super[0]++);
+ Expect.equals(44, super[0]);
+
+ Expect.equals(2, super[0] = 2);
+ Expect.equals(2, super[0]);
+ Expect.equals(3, super[0] += 1);
+ Expect.equals(3, super[0]);
+ Expect.equals(3, super[0]++);
+ Expect.equals(4, super[0]);
+ }
+}
+
+main() {
+ new C().test();
+}
diff --git a/tests/language/super/operator_index5_test.dart b/tests/language/super/operator_index5_test.dart
new file mode 100644
index 0000000..86c5522
--- /dev/null
+++ b/tests/language/super/operator_index5_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for unresolved super[]=.
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+ operator [](index) => indexField[index];
+
+ operator []=(index, value);
+
+ noSuchMethod(Invocation im) {
+ if (im.memberName == const Symbol('[]=')) {
+ Expect.equals(2, im.positionalArguments.length);
+ indexField[im.positionalArguments[0]] = im.positionalArguments[1];
+ } else {
+ Expect.fail('Should not reach here');
+ }
+ }
+}
+
+class B extends A {
+ test() {
+ Expect.equals(42, super[0] = 42);
+ Expect.equals(42, super[0]);
+ Expect.equals(43, super[0] += 1);
+ Expect.equals(43, super[0]);
+ Expect.equals(43, super[0]++);
+ Expect.equals(44, super[0]);
+
+ Expect.equals(2, super[0] = 2);
+ Expect.equals(2, super[0]);
+ Expect.equals(3, super[0] += 1);
+ Expect.equals(3, super[0]);
+ Expect.equals(3, super[0]++);
+ Expect.equals(4, super[0]);
+ }
+}
+
+main() {
+ new B().test();
+}
diff --git a/tests/language/super/operator_index6_test.dart b/tests/language/super/operator_index6_test.dart
new file mode 100644
index 0000000..b97d048
--- /dev/null
+++ b/tests/language/super/operator_index6_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for unresolved super[].
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+ operator []=(index, value) {
+ indexField[index] = value;
+ }
+
+ operator [](index);
+
+ noSuchMethod(Invocation im) {
+ if (im.memberName == const Symbol('[]')) {
+ Expect.equals(1, im.positionalArguments.length);
+ return indexField[im.positionalArguments[0]];
+ } else {
+ Expect.fail('Should not reach here');
+ }
+ }
+}
+
+class B extends A {
+ test() {
+ Expect.equals(42, super[0] = 42);
+ Expect.equals(42, super[0]);
+ Expect.equals(43, super[0] += 1);
+ Expect.equals(43, super[0]);
+ Expect.equals(43, super[0]++);
+ Expect.equals(44, super[0]);
+
+ Expect.equals(2, super[0] = 2);
+ Expect.equals(2, super[0]);
+ Expect.equals(3, super[0] += 1);
+ Expect.equals(3, super[0]);
+ Expect.equals(3, super[0]++);
+ Expect.equals(4, super[0]);
+ }
+}
+
+main() {
+ new B().test();
+}
diff --git a/tests/language/super/operator_index7_test.dart b/tests/language/super/operator_index7_test.dart
new file mode 100644
index 0000000..0b2334a
--- /dev/null
+++ b/tests/language/super/operator_index7_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for unresolved super[] and super[]=.
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+
+ operator []=(index, value);
+ operator [](index);
+
+ noSuchMethod(Invocation im) {
+ if (im.memberName == const Symbol('[]=')) {
+ Expect.equals(2, im.positionalArguments.length);
+ indexField[im.positionalArguments[0]] = im.positionalArguments[1];
+ } else if (im.memberName == const Symbol('[]')) {
+ Expect.equals(1, im.positionalArguments.length);
+ return indexField[im.positionalArguments[0]];
+ } else {
+ Expect.fail('Should not reach here');
+ }
+ }
+}
+
+class B extends A {
+ test() {
+ Expect.equals(42, super[0] = 42);
+ Expect.equals(42, super[0]);
+ Expect.equals(43, super[0] += 1);
+ Expect.equals(43, super[0]);
+ Expect.equals(43, super[0]++);
+ Expect.equals(44, super[0]);
+
+ Expect.equals(2, super[0] = 2);
+ Expect.equals(2, super[0]);
+ Expect.equals(3, super[0] += 1);
+ Expect.equals(3, super[0]);
+ Expect.equals(3, super[0]++);
+ Expect.equals(4, super[0]);
+ }
+}
+
+main() {
+ new B().test();
+}
diff --git a/tests/language/super/operator_index8_test.dart b/tests/language/super/operator_index8_test.dart
new file mode 100644
index 0000000..100e895
--- /dev/null
+++ b/tests/language/super/operator_index8_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test for unresolved super[] and super[]= and correct evaluation order.
+
+import "package:expect/expect.dart";
+
+class A {
+ var indexField = <int?>[null, null];
+
+ operator []=(index, value);
+ operator [](index);
+
+ noSuchMethod(Invocation im) {
+ if (im.memberName == const Symbol('[]=')) {
+ Expect.equals(2, im.positionalArguments.length);
+ indexField[im.positionalArguments[0]] = im.positionalArguments[1];
+ } else if (im.memberName == const Symbol('[]')) {
+ Expect.equals(1, im.positionalArguments.length);
+ return indexField[im.positionalArguments[0]];
+ } else {
+ Expect.fail('Should not reach here');
+ }
+ }
+}
+
+var global = 0;
+
+f() {
+ Expect.equals(0, global++);
+ return 0;
+}
+
+g() {
+ Expect.equals(1, global++);
+ return 42;
+}
+
+class B extends A {
+ test() {
+ Expect.equals(42, super[f()] = g());
+ Expect.equals(2, global);
+ }
+}
+
+main() {
+ new B().test();
+}
diff --git a/tests/language/super/operator_index_test.dart b/tests/language/super/operator_index_test.dart
new file mode 100644
index 0000000..81dd172
--- /dev/null
+++ b/tests/language/super/operator_index_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that we emit errors for unresolved indexing operations on super.
+
+class A {
+ operator []=(a, b) {}
+}
+
+class B extends A {
+ foo() {
+ super[4] = 42;
+ super[4] += 5; //# 01: compile-time error
+ return super[2]; //# 02: compile-time error
+ }
+}
+
+class C {
+ operator [](a) {}
+}
+
+class D extends C {
+ foo() {
+ super[4] = 42; //# 03: compile-time error
+ super[4] += 5; //# 04: compile-time error
+ return super[2];
+ }
+}
+
+class E {
+ foo() {
+ super[4] = 42; //# 05: compile-time error
+ super[4] += 5; //# 06: compile-time error
+ return super[2]; //# 07: compile-time error
+ }
+}
+
+main() {
+ new B().foo();
+ new D().foo();
+ new E().foo();
+}
diff --git a/tests/language/super/operator_test.dart b/tests/language/super/operator_test.dart
new file mode 100644
index 0000000..5953e7a
--- /dev/null
+++ b/tests/language/super/operator_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing super operator calls
+
+import "package:expect/expect.dart";
+
+class A {
+ String val = "";
+ List things;
+
+ A() : things = ['D', 'a', 'r', 't', 42];
+
+ operator +(String s) {
+ val = "${val}${s}";
+ return this;
+ }
+
+ operator [](i) {
+ return things[i];
+ }
+
+ operator []=(i, val) {
+ return things[i] = val;
+ }
+}
+
+class B extends A {
+ operator +(String s) {
+ super + ("${s}${s}"); // Call A.operator+(this, "${s}${s}").
+ return this;
+ }
+
+ operator [](i) {
+ var temp = super[i];
+ if (temp is String) {
+ return "$temp$temp";
+ }
+ return temp + temp;
+ }
+
+ operator []=(i, val) {
+ // Make sure the index expression is only evaluated
+ // once in the presence of a compound assignment.
+ return super[i++] += val;
+ }
+}
+
+
+main() {
+ var a = new A();
+ a = a + "William"; // operator + of class A.
+ Expect.equals("William", a.val);
+ Expect.equals("r", a[2]); // operator [] of class A.
+
+ a = new B();
+ a += "Tell"; // operator + of class B.
+ Expect.equals("TellTell", a.val);
+ Expect.equals("rr", a[2]); // operator [] of class B.
+
+ a[4] = 1; // operator []= of class B.
+ Expect.equals(43, a.things[4]);
+ Expect.equals(86, a[4]);
+}
diff --git a/tests/language/super/setter_interceptor_test.dart b/tests/language/super/setter_interceptor_test.dart
new file mode 100644
index 0000000..339dc6f
--- /dev/null
+++ b/tests/language/super/setter_interceptor_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that we correctly intercept super getter and setter calls.
+
+import "package:expect/expect.dart";
+
+var expected;
+
+class A {
+ set length(a) {
+ Expect.equals(expected, a);
+ }
+
+ get length => 41;
+}
+
+class B extends A {
+ test() {
+ expected = 42;
+ Expect.equals(42, super.length = 42);
+ expected = 42;
+ Expect.equals(42, super.length += 1);
+ expected = 42;
+ Expect.equals(42, ++super.length);
+ expected = 40;
+ Expect.equals(40, --super.length);
+ expected = 42;
+ Expect.equals(41, super.length++);
+ expected = 40;
+ Expect.equals(41, super.length--);
+ Expect.equals(41, super.length);
+ }
+}
+
+main() {
+ // Ensures the list class is instantiated.
+ print([]);
+ new B().test();
+}
diff --git a/tests/language/super/setter_test.dart b/tests/language/super/setter_test.dart
new file mode 100644
index 0000000..3d02906
--- /dev/null
+++ b/tests/language/super/setter_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test for testing super setters and getters.
+
+import "package:expect/expect.dart";
+
+class Base {
+ Base() {}
+ String value_ = "";
+
+ String get value { return value_; }
+ set value(String newValue) {
+ value_ = 'Base:$newValue';
+ }
+}
+
+
+class Derived extends Base {
+ Derived() : super() {}
+
+ set value(String newValue) {
+ super.value = 'Derived:$newValue';
+ }
+ String get value { return super.value; }
+}
+
+
+class SuperSetterTest {
+ static void testMain() {
+ final b = new Derived();
+ b.value = "foo";
+ Expect.equals("Base:Derived:foo", b.value);
+ }
+}
+
+main() {
+ SuperSetterTest.testMain();
+}
diff --git a/tests/language/super/super_test.dart b/tests/language/super/super_test.dart
new file mode 100644
index 0000000..f96f4fe
--- /dev/null
+++ b/tests/language/super/super_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+int i = 0;
+
+// Tests super calls and constructors.
+main() {
+ Sub sub = new Sub(1, 2);
+ Expect.equals(1, sub.x);
+ Expect.equals(2, sub.y);
+ Expect.equals(3, sub.z);
+ Expect.equals(1, sub.v);
+ Expect.equals(2, sub.w);
+ Expect.equals(3, sub.u);
+
+ sub = new Sub.stat();
+ Expect.equals(2, sub.x);
+ Expect.equals(3, sub.y);
+ Expect.equals(0, sub.v);
+ Expect.equals(1, sub.w);
+ Expect.equals(4, sub.z);
+ Expect.equals(5, sub.u);
+}
+
+class Sup {
+ var x, y, z;
+
+ Sup(a, b)
+ : this.x = a,
+ this.y = b {
+ z = a + b;
+ }
+
+ Sup.stat()
+ : this.x = i++,
+ this.y = i++ {
+ z = i++;
+ }
+}
+
+class Sub extends Sup {
+ var u, v, w;
+
+ Sub(a, b)
+ : this.v = a,
+ this.w = b,
+ super(a, b) {
+ u = a + b;
+ }
+
+ Sub.stat()
+ : this.v = i++,
+ this.w = i++,
+ super.stat() {
+ u = i++;
+ }
+}
diff --git a/tests/language/switch/bad_case_runtime_test.dart b/tests/language/switch/bad_case_runtime_test.dart
new file mode 100644
index 0000000..0119fa5
--- /dev/null
+++ b/tests/language/switch/bad_case_runtime_test.dart
@@ -0,0 +1,39 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test reporting a compile-time error if case expressions do not all have
+// the same type or are of type double.
+
+import "package:expect/expect.dart";
+
+void main() {
+ Expect.equals("IV", caesarSays(4));
+ Expect.equals(null, caesarSays(2));
+ Expect.equals(null, archimedesSays(3.14));
+}
+
+caesarSays(n) {
+ switch (n) {
+ case 1:
+ return "I";
+ case 4:
+ return "IV";
+
+
+ }
+ return null;
+}
+
+archimedesSays(n) {
+
+
+
+
+
+
+ return null;
+}
diff --git a/tests/language/switch/bad_case_test.dart b/tests/language/switch/bad_case_test.dart
new file mode 100644
index 0000000..57e40a5
--- /dev/null
+++ b/tests/language/switch/bad_case_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test reporting a compile-time error if case expressions are of type double.
+
+import "package:expect/expect.dart";
+
+void main() {
+ Expect.equals("IV", caesarSays(4));
+ Expect.equals(null, caesarSays(2));
+ Expect.equals(null, archimedesSays(3.14));
+}
+
+/// Before null safety, it was an error if the cases in a switch were not of
+/// the same type, regardless of the value expression's type. Now it is only an
+/// error if the cases are not a subtype of the value's type.
+caesarSays(n) {
+ switch (n) {
+ case 1:
+ return "I";
+ case 4:
+ return "IV";
+ case "M":
+ return 1000;
+ }
+ return null;
+}
+
+archimedesSays(n) {
+ switch (n) {
+ case 3.14:
+ // ^^^^
+ // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
+ // [cfe] Case expression '3.14' does not have a primitive operator '=='.
+ return "Pi";
+ case 2.71828:
+ // ^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
+ // [cfe] Case expression '2.71828' does not have a primitive operator '=='.
+ return "Huh?";
+ }
+ return null;
+}
diff --git a/tests/language/switch/case_expression_with_assignment_runtime_test.dart b/tests/language/switch/case_expression_with_assignment_runtime_test.dart
new file mode 100644
index 0000000..8b534c6
--- /dev/null
+++ b/tests/language/switch/case_expression_with_assignment_runtime_test.dart
@@ -0,0 +1,31 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for crash in VM parser (issue 29370).
+
+import "package:expect/expect.dart";
+
+const ERROR_A = 0;
+const ERROR_B = 1;
+
+errorToString(error) {
+ switch (error) {
+ case ERROR_A:
+ return "ERROR_A";
+
+ case ERROR_B:
+ return "ERROR_B";
+ default:
+ return "Unknown error";
+ }
+}
+
+main() {
+ Expect.equals(errorToString(ERROR_A), "ERROR_A");
+ Expect.equals(errorToString(ERROR_B), "ERROR_B");
+ Expect.equals(errorToString(55), "Unknown error");
+}
diff --git a/tests/language/switch/case_expression_with_assignment_test.dart b/tests/language/switch/case_expression_with_assignment_test.dart
new file mode 100644
index 0000000..115cb94
--- /dev/null
+++ b/tests/language/switch/case_expression_with_assignment_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for crash in VM parser (issue 29370).
+
+import "package:expect/expect.dart";
+
+const ERROR_A = 0;
+const ERROR_B = 1;
+
+errorToString(error) {
+ switch (error) {
+ case ERROR_A:
+ return "ERROR_A";
+ case ERROR_B = 1:
+ // ^^^^^^^
+ // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_CONST
+ // ^^^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.NON_CONSTANT_CASE_EXPRESSION
+ // ^
+ // [cfe] Not a constant expression.
+ case ERROR_B:
+ return "ERROR_B";
+ default:
+ return "Unknown error";
+ }
+}
+
+main() {
+ Expect.equals(errorToString(ERROR_A), "ERROR_A");
+ Expect.equals(errorToString(ERROR_B), "ERROR_B");
+ Expect.equals(errorToString(55), "Unknown error");
+}
diff --git a/tests/language/switch/case_runtime_test.dart b/tests/language/switch/case_runtime_test.dart
new file mode 100644
index 0000000..44f2412
--- /dev/null
+++ b/tests/language/switch/case_runtime_test.dart
@@ -0,0 +1,58 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ const A();
+ const factory A.B() = B;
+ const factory A.C() = C;
+ const factory A.C2() = D;
+}
+
+class B implements A {
+ const B();
+
+
+}
+
+class C implements D {
+ final int x;
+ const C() : x = 0;
+ const C.fromD() : x = 1;
+}
+
+class D implements A {
+ int get x => 0;
+ const factory D() = C.fromD;
+}
+
+main() {
+ switch (new B()) {
+
+ }
+
+ switch (new C()) {
+ case const C():
+ Expect.fail("bad switch");
+ break;
+ case const A.C() as C:
+ Expect.fail("bad switch");
+ break;
+ case const A.C2() as C:
+ Expect.fail("bad switch");
+ break;
+
+ }
+
+ switch (new A()) {
+ case const A():
+ Expect.fail("bad switch");
+ break;
+
+ }
+}
diff --git a/tests/language/switch/case_static_const_test.dart b/tests/language/switch/case_static_const_test.dart
new file mode 100644
index 0000000..e15a9f4
--- /dev/null
+++ b/tests/language/switch/case_static_const_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ static const S = 'A.S';
+}
+
+const S = 'S';
+
+foo(var p) {
+ switch (p) {
+ case S:
+ break;
+ case A.S:
+ break;
+ case 'abc':
+ break;
+ }
+}
+
+main() {
+ foo('p');
+}
diff --git a/tests/language/switch/case_test.dart b/tests/language/switch/case_test.dart
new file mode 100644
index 0000000..9432bc2
--- /dev/null
+++ b/tests/language/switch/case_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ const A();
+ const factory A.B() = B;
+ const factory A.C() = C;
+ const factory A.C2() = D;
+}
+
+class B implements A {
+ const B();
+
+ operator ==(o) => true;
+}
+
+class C implements D {
+ final int x;
+ const C() : x = 0;
+ const C.fromD() : x = 1;
+}
+
+class D implements A {
+ int get x => 0;
+ const factory D() = C.fromD;
+}
+
+main() {
+ switch (new B()) {
+ case const A.B() as B: Expect.fail("bad switch"); break;
+ // ^^^^^^^^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
+ // ^
+ // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
+ }
+
+ switch (new C()) {
+ case const C():
+ Expect.fail("bad switch");
+ break;
+ case const A.C() as C:
+ Expect.fail("bad switch");
+ break;
+ case const A.C2() as C:
+ Expect.fail("bad switch");
+ break;
+ case const A(): Expect.fail("bad switch"); break;
+ // ^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IS_NOT_SWITCH_EXPRESSION_SUBTYPE
+ // ^
+ // [cfe] Type 'A' of the case expression is not a subtype of type 'C' of this switch expression.
+ }
+
+ switch (new A()) {
+ case const A():
+ Expect.fail("bad switch");
+ break;
+ case const A.B(): Expect.fail("bad switch"); break;
+ // ^^^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.CASE_EXPRESSION_TYPE_IMPLEMENTS_EQUALS
+ // ^
+ // [cfe] Case expression 'B {}' does not have a primitive operator '=='.
+ }
+}
diff --git a/tests/language/switch/case_warn_test.dart b/tests/language/switch/case_warn_test.dart
new file mode 100644
index 0000000..cf0a896
--- /dev/null
+++ b/tests/language/switch/case_warn_test.dart
@@ -0,0 +1,220 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test switch statement.
+
+// Tests some switch-case statements blocks that should and should not
+// cause static warnings.
+// This test is not testing runtime behavior, only static warnings.
+
+// None of the cases blocks should cause a warning.
+dynamic testSwitch(int x) {
+ // Catch all control flow leaving the switch.
+ // Run switch in catch clause to check rethrow.
+ TRY:
+ try {
+ throw x;
+ } catch (x) {
+ // Add loop as break/continue target.
+ LOOP:
+ do {
+ switch (x) {
+ case 0:
+ case 1:
+ nop(x);
+ break; // Break switch.
+ case 2:
+ nop(x);
+ break LOOP;
+ case 3:
+ nop(x);
+ continue; // Continue loop.
+ case 4:
+ nop(x);
+ continue LOOP;
+ case 5:
+ nop(x);
+ continue LAST;
+ // Avoid warning for "return;"" and "return e;" in same function.
+ case 6: // //# retnon: ok
+ nop(x); // //# retnon: continued
+ return; // //# retnon: continued
+ case 7: // //# retval: ok
+ nop(x); // //# retval: continued
+ return x; // //# retval: continued
+ case 8:
+ nop(x);
+ throw x;
+ case 9:
+ nop(x);
+ rethrow;
+ case 10:
+ case 11:
+ {
+ nop(x);
+ break; // Break switch.
+ }
+ case 12:
+ {
+ nop(x);
+ break LOOP;
+ }
+ case 13:
+ {
+ nop(x);
+ continue; // Continue loop.
+ }
+ case 14:
+ {
+ nop(x);
+ continue LOOP;
+ }
+ case 15:
+ {
+ nop(x);
+ continue LAST;
+ }
+ case 16: { // //# retnon: continued
+ nop(x); // //# retnon: continued
+ return; // //# retnon: continued
+ } // //# retnon: continued
+ case 17: { // //# retval: continued
+ nop(x); // //# retval: continued
+ return x; // //# retval: continued
+ } // //# retval: continued
+ case 18:
+ {
+ nop(x);
+ throw x;
+ }
+ case 19:
+ {
+ nop(x);
+ rethrow;
+ }
+ LAST:
+ case 20:
+ {
+ nop(x);
+ // Fallthrough allowed on last statements.
+ }
+ }
+ } while (false);
+ } finally {
+ // Catch all control flow leaving the switch and ignore it.
+ // Use break instead of return to avoid warning for `return` and `return e`
+ // in same function.
+ break TRY;
+ }
+}
+
+/// In Dart 2.0, all of these switch cases should cause warnings because the
+/// fallthrough analysis was very limited and syntax-based. Null safety
+/// includes more precise flow analysis so most of these are now valid code
+/// because in fact no fallthrough will occur.
+void testSwitchWarn(x) {
+ // Catch all control flow from the switch and ignore it.
+ TRY:
+ try {
+ throw 0;
+ } catch (e) {
+ // Wrap in loop as target for continue/break.
+ LOOP:
+ do {
+ switch (x) {
+ case 0: // //# 01: ok
+ case 1: { // //# 01: continued
+ { // //# 01: continued
+ nop(x); // //# 01: continued
+ break; // Break switch. // //# 01: continued
+ } // //# 01: continued
+ } // //# 01: continued
+ case 2: { // //# 02: ok
+ { // //# 02: continued
+ nop(x); // //# 02: continued
+ break LOOP; // //# 02: continued
+ } // //# 02: continued
+ } // //# 02: continued
+ case 3: { // //# 03: ok
+ { // //# 03: continued
+ nop(x); // //# 03: continued
+ continue; // Continue loop. //# 03: continued
+ } // //# 03: continued
+ } // //# 03: continued
+ case 4: { // //# 04: ok
+ { // //# 04: continued
+ nop(x); // //# 04: continued
+ continue LOOP; // //# 04: continued
+ } // //# 04: continued
+ } // //# 04: continued
+ case 5: { // //# 05: ok
+ { // //# 05: continued
+ nop(x); // //# 05: continued
+ continue LAST; // //# 05: continued
+ } // //# 05: continued
+ } // //# 05: continued
+ case 6: { // //# 06: ok
+ { // //# 06: continued
+ nop(x); // //# 06: continued
+ return; // //# 06: continued
+ } // //# 06: continued
+ } // //# 06: continued
+ case 7: { // //# 07: ok
+ { // //# 07: continued
+ nop(x); // //# 07: continued
+ return x; // //# 07: continued
+ } // //# 07: continued
+ } // //# 07: continued
+ case 8: { // //# 08: ok
+ { // //# 08: continued
+ nop(x); // //# 08: continued
+ throw x; // //# 08: continued
+ } // //# 08: continued
+ } // //# 08: continued
+ case 9: { // //# 09: ok
+ { // //# 09: continued
+ nop(x); // //# 09: continued
+ rethrow; // //# 09: continued
+ } // //# 09: continued
+ } // //# 09: continued
+ case 10: // //# 10: compile-time error
+ while (true) break; // //# 10: continued
+ case 11: // //# 11: compile-time error
+ do break; while (true); // //# 11: continued
+ case 12: // //# 12: compile-time error
+ for (;;) break; // //# 12: continued
+ case 13: // //# 13: compile-time error
+ for (var _ in []) break; // //# 13: continued
+ case 14: // //# 14: ok
+ if (x) break; else break; // //# 14: continued
+ case 15: // //# 15: ok
+ (throw 0); // //# 15: continued
+ case 16: // //# 16: compile-time error
+ nop(x); // fallthrough. // //# 16: continued
+ case 17: // //# 17: ok
+ L: break; // //# 17: continued
+ LAST:
+ case 99:
+ // Last case can't cause static warning.
+ }
+ } while (false);
+ } finally {
+ // Catch all control flow leaving the switch and ignore it.
+ // Use break instead of return to avoid warning for `return` and `return e`
+ // in same function.
+ break TRY;
+ }
+}
+
+main() {
+ // Ensure that all the cases compile and run (even if they might throw).
+ for (int i = 0; i <= 20; i++) {
+ testSwitch(i); // Just make sure it runs.
+ }
+ for (int i = 0; i <= 18; i++) {
+ testSwitchWarn(i);
+ }
+}
+
+/// Don't make it obvious that a switch case isn't doing anything.
+void nop(x) {}
diff --git a/tests/language/switch/empty_block_case_test.dart b/tests/language/switch/empty_block_case_test.dart
new file mode 100644
index 0000000..6edaff4
--- /dev/null
+++ b/tests/language/switch/empty_block_case_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that a case with an empty block does not fall through.
+
+class EmptyBlockCaseTest {
+ static testMain() {
+ var exception = null;
+ try {
+ switch (1) {
+ case 1: /*@compile-error=unspecified*/
+ {}
+ case 2:
+ Expect.equals(true, false);
+ }
+ } on FallThroughError catch (e) {
+ exception = e;
+ }
+ Expect.equals(true, exception != null);
+ }
+}
+
+main() {
+ EmptyBlockCaseTest.testMain();
+}
diff --git a/tests/language/switch/fallthru_runtime_test.dart b/tests/language/switch/fallthru_runtime_test.dart
new file mode 100644
index 0000000..b1dd57d
--- /dev/null
+++ b/tests/language/switch/fallthru_runtime_test.dart
@@ -0,0 +1,32 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Check that FallThroughError is thrown if switch clause does not terminate.
+
+import "package:expect/expect.dart";
+
+String test(int n) {
+ String result = "foo";
+ switch (n) {
+ case 0:
+ result = "zero";
+ break;
+ case 1:
+
+ // fall-through, error if case is non-empty
+ case 9:
+ result = "nine";
+ // No implicit FallThroughError at end of switch statement.
+ }
+ return result;
+}
+
+main() {
+ Expect.equals("zero", test(0));
+ Expect.equals("nine", test(1));
+ Expect.equals("nine", test(9));
+ Expect.equals("foo", test(99));
+}
diff --git a/tests/language/switch/fallthru_test.dart b/tests/language/switch/fallthru_test.dart
new file mode 100644
index 0000000..667e3ce
--- /dev/null
+++ b/tests/language/switch/fallthru_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Check that FallThroughError is thrown if switch clause does not terminate.
+
+import "package:expect/expect.dart";
+
+String test(int n) {
+ String result = "foo";
+ switch (n) {
+ case 0:
+ result = "zero";
+ break;
+ case 1:
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.SWITCH_CASE_COMPLETES_NORMALLY
+// [cfe] Switch case may fall through to the next case.
+ result = "one";
+ // fall-through, error if case is non-empty
+ case 9:
+ result = "nine";
+ // No implicit FallThroughError at end of switch statement.
+ }
+ return result;
+}
+
+main() {
+ Expect.equals("zero", test(0));
+ Expect.equals("nine", test(1));
+ Expect.equals("nine", test(9));
+ Expect.equals("foo", test(99));
+}
diff --git a/tests/language/switch/infinite_switch_label_test.dart b/tests/language/switch/infinite_switch_label_test.dart
new file mode 100644
index 0000000..7f484cc
--- /dev/null
+++ b/tests/language/switch/infinite_switch_label_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test nested switch statement using labels.
+
+library nested_switch_label;
+
+import "package:expect/expect.dart";
+
+void main() {
+ Expect.throws(() => doSwitch(0), (list) {
+ Expect.listEquals([0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0], list as List);
+ return true;
+ });
+ Expect.throws(() => doSwitch(2), (list) {
+ Expect.listEquals([2, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0], list as List);
+ return true;
+ });
+}
+
+void doSwitch(int target) {
+ List list = [];
+ switch (target) {
+ l0:
+ case 0:
+ if (list.length > 10) throw list;
+ list.add(0);
+ continue l1;
+ l1:
+ case 1:
+ if (list.length > 10) throw list;
+ list.add(1);
+ continue l0;
+ default:
+ list.add(2);
+ continue l1;
+ }
+}
diff --git a/tests/language/switch/label2_test.dart b/tests/language/switch/label2_test.dart
new file mode 100644
index 0000000..612e6a9
--- /dev/null
+++ b/tests/language/switch/label2_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test switch statement using labels.
+
+import 'package:expect/expect.dart';
+
+void main() {
+ doSwitch(0, [0, 2]);
+ doSwitch(1, [1]);
+ doSwitch(2, [2]);
+ doSwitch(3, [3, 1]);
+}
+
+void doSwitch(int target, List expect) {
+ List list = [];
+ switch (target) {
+ case 0:
+ list.add(0);
+ continue case2;
+ case1:
+ case 1:
+ list.add(1);
+ break;
+ case2:
+ case 2:
+ list.add(2);
+ break;
+ case 3:
+ list.add(3);
+ continue case1;
+ }
+ Expect.listEquals(expect, list);
+}
diff --git a/tests/language/switch/label_test.dart b/tests/language/switch/label_test.dart
new file mode 100644
index 0000000..290c84f
--- /dev/null
+++ b/tests/language/switch/label_test.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test switch statement using labels.
+
+import "package:expect/expect.dart";
+
+class Switcher {
+ Switcher() {}
+
+ say1(sound) {
+ var x = 0;
+ switch (sound) {
+ MOO:
+ case "moo":
+ x = 100;
+ break;
+ case "woof":
+ x = 200;
+ continue MOO;
+ default:
+ x = 300;
+ break;
+ }
+ return x;
+ }
+
+ say2(sound) {
+ var x = 0;
+ switch (sound) {
+ WOOF:
+ case "woof":
+ x = 200;
+ break;
+ case "moo":
+ x = 100;
+ continue WOOF;
+ default:
+ x = 300;
+ break;
+ }
+ return x;
+ }
+
+ // forward label to outer switch
+ say3(animal, sound) {
+ var x = 0;
+ switch (animal) {
+ case "cow":
+ switch (sound) {
+ case "moo":
+ x = 100;
+ break;
+ case "muh":
+ x = 200;
+ break;
+ default:
+ continue NIX_UNDERSTAND;
+ }
+ break;
+ case "dog":
+ if (sound == "woof") {
+ x = 300;
+ } else {
+ continue NIX_UNDERSTAND;
+ }
+ break;
+ NIX_UNDERSTAND:
+ case "unicorn":
+ x = 400;
+ break;
+ default:
+ x = 500;
+ break;
+ }
+ return x;
+ }
+}
+
+class SwitchLabelTest {
+ static testMain() {
+ Switcher s = new Switcher();
+ Expect.equals(100, s.say1("moo"));
+ Expect.equals(100, s.say1("woof"));
+ Expect.equals(300, s.say1("cockadoodledoo"));
+
+ Expect.equals(200, s.say2("moo"));
+ Expect.equals(200, s.say2("woof"));
+ Expect.equals(300, s.say2("")); // Dead unicorn says nothing.
+
+ Expect.equals(100, s.say3("cow", "moo"));
+ Expect.equals(200, s.say3("cow", "muh"));
+ Expect.equals(400, s.say3("cow", "boeh")); // Don't ask.
+ Expect.equals(300, s.say3("dog", "woof"));
+ Expect.equals(400, s.say3("dog", "boj")); // Ĉu vi parolas Esperanton?
+ Expect.equals(400, s.say3("unicorn", "")); // Still dead.
+ Expect.equals(500, s.say3("angry bird", "whoooo"));
+ }
+}
+
+main() {
+ SwitchLabelTest.testMain();
+}
diff --git a/tests/language/switch/nested_switch_label_test.dart b/tests/language/switch/nested_switch_label_test.dart
new file mode 100644
index 0000000..49c2754
--- /dev/null
+++ b/tests/language/switch/nested_switch_label_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test nested switch statement using labels.
+
+library nested_switch_label;
+
+import "package:expect/expect.dart";
+
+void main() {
+ doSwitch(0, ['0', '2:0', '1', 'default']);
+ doSwitch(2, ['2:2', '2:1', '2', '1', 'default']);
+}
+
+void doSwitch(int target, List expect) {
+ List list = [];
+ switch (target) {
+ outer0:
+ case 0:
+ list.add('0');
+ continue outer2;
+ outer1:
+ case 1:
+ list.add('1');
+ continue outerDefault;
+ outer2:
+ case 2:
+ switch (target) {
+ inner0:
+ case 0:
+ list.add('2:0');
+ continue outer1;
+ inner2:
+ case 2:
+ list.add('2:2');
+ continue inner1;
+ inner1:
+ case 1:
+ list.add('2:1');
+ }
+ list.add('2');
+ continue outer1;
+ outerDefault:
+ default:
+ list.add('default');
+ }
+ Expect.listEquals(expect, list);
+}
diff --git a/tests/language/switch/scope_test.dart b/tests/language/switch/scope_test.dart
new file mode 100644
index 0000000..938a393
--- /dev/null
+++ b/tests/language/switch/scope_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test that a new scope is introduced for each switch case.
+
+import "package:expect/expect.dart";
+
+class SwitchScopeTest {
+ static testMain() {
+ switch (1) {
+ case 1:
+ final v = 1;
+ break;
+ case 2:
+ final v = 2;
+ Expect.equals(2, v);
+ break;
+ default:
+ final v = 3;
+ break;
+ }
+ }
+}
+
+main() {
+ SwitchScopeTest.testMain();
+}
diff --git a/tests/language/switch/switch1_test.dart b/tests/language/switch/switch1_test.dart
new file mode 100644
index 0000000..ffae0f2
--- /dev/null
+++ b/tests/language/switch/switch1_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Check that default clause must be last case.
+
+main() {
+ var a = 5;
+ var x;
+ S: switch (a) {
+ case 1: x = 1; break;
+ case 6: x = 2; break S;
+ default:
+// ^
+// [cfe] Switch case may fall through to the next case.
+ case 8: break;
+// ^^^^
+// [analyzer] SYNTACTIC_ERROR.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE
+// [cfe] The default case should be the last case in a switch statement.
+ }
+ return a;
+}
diff --git a/tests/language/switch/switch3_test.dart b/tests/language/switch/switch3_test.dart
new file mode 100644
index 0000000..406cb31
--- /dev/null
+++ b/tests/language/switch/switch3_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Check that 'continue' to switch statement is illegal.
+
+main() {
+ var a = 5;
+ var x;
+ switch (a) {
+ case 1: x = 1; break;
+ case 6: x = 2; continue;
+// ^^^^^^^^
+// [analyzer] SYNTACTIC_ERROR.CONTINUE_WITHOUT_LABEL_IN_CASE
+// [cfe] A continue statement in a switch statement must have a label as a target.
+ case 8: break;
+ }
+ return a;
+}
diff --git a/tests/language/switch/switch4_test.dart b/tests/language/switch/switch4_test.dart
new file mode 100644
index 0000000..7a99b69
--- /dev/null
+++ b/tests/language/switch/switch4_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Discover unresolved case labels.
+
+main() {
+ var a = 5;
+ var x;
+ switch (a) {
+ case 1:
+// ^
+// [cfe] Switch case may fall through to the next case.
+ x = 1;
+ continue L;
+// ^
+// [cfe] Can't find label 'L'.
+// ^
+// [analyzer] COMPILE_TIME_ERROR.LABEL_UNDEFINED
+ case 6:
+ x = 2;
+ break;
+ case 8:
+ break;
+ }
+ return a;
+}
diff --git a/tests/language/switch/switch5_test.dart b/tests/language/switch/switch5_test.dart
new file mode 100644
index 0000000..d026d06
--- /dev/null
+++ b/tests/language/switch/switch5_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Break' to case label is illegal.
+
+main() {
+ var a = 5;
+ var x;
+ switch (a) {
+ L:
+ case 1:
+ x = 1;
+ break;
+ case 6:
+ x = 2;
+ break L;
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.BREAK_LABEL_ON_SWITCH_MEMBER
+ // [cfe] Can't break to 'L'.
+ default:
+ break;
+ }
+ return a;
+}
diff --git a/tests/language/switch/switch6_test.dart b/tests/language/switch/switch6_test.dart
new file mode 100644
index 0000000..43e09dc
--- /dev/null
+++ b/tests/language/switch/switch6_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// The break is in the right scope, http://b/3428700 was agreed upon.
+
+import "package:expect/expect.dart";
+
+class Switch6Test {
+ static testMain() {
+ var a = 0;
+ var x = -1;
+ switch (a) {
+ case 0:
+ {
+ x = 0;
+ break;
+ }
+ case 1:
+ x = 1;
+ break;
+ }
+ Expect.equals(0, x);
+ }
+}
+
+main() {
+ Switch6Test.testMain();
+}
diff --git a/tests/language/switch/switch7_test.dart b/tests/language/switch/switch7_test.dart
new file mode 100644
index 0000000..e47d7e5
--- /dev/null
+++ b/tests/language/switch/switch7_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Illegal to reference a labeled case statement with break.
+
+main() {
+ var x = 1;
+ L:
+ while (true) {
+ switch (x) {
+ L:
+ case 1: // Shadowing another label is OK.
+ break L; // Illegal, can't reference labeled case from break.
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.BREAK_LABEL_ON_SWITCH_MEMBER
+ // [cfe] Can't break to 'L'.
+ }
+ }
+}
diff --git a/tests/language/switch/switch8_test.dart b/tests/language/switch/switch8_test.dart
new file mode 100644
index 0000000..796bf76
--- /dev/null
+++ b/tests/language/switch/switch8_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to not generate code for
+// compile-time constants only seen in case expressions.
+
+class A {
+ const A();
+}
+
+main() {
+ switch (<dynamic>[null][0]) {
+ case const A():
+ throw 'Test failed';
+ }
+}
diff --git a/tests/language/switch/switch_test.dart b/tests/language/switch/switch_test.dart
new file mode 100644
index 0000000..032c2b7
--- /dev/null
+++ b/tests/language/switch/switch_test.dart
@@ -0,0 +1,168 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test switch statement.
+
+import "package:expect/expect.dart";
+
+class Switcher {
+ Switcher() {}
+
+ test1(val) {
+ var x = 0;
+ switch (val) {
+ case 1:
+ x = 100;
+ break;
+ case 2:
+ case 3:
+ x = 200;
+ break;
+ case 4:
+ default:
+ {
+ x = 400;
+ break;
+ }
+ }
+ return x;
+ }
+
+ test2(val) {
+ switch (val) {
+ case 1:
+ return 200;
+ default:
+ return 400;
+ }
+ }
+}
+
+class SwitchTest {
+ static testMain() {
+ Switcher s = new Switcher();
+ Expect.equals(100, s.test1(1));
+ Expect.equals(200, s.test1(2));
+ Expect.equals(200, s.test1(3));
+ Expect.equals(400, s.test1(4));
+ Expect.equals(400, s.test1(5));
+
+ Expect.equals(200, s.test2(1));
+ Expect.equals(400, s.test2(2));
+ }
+}
+
+class Enum {
+ static const Enum e1 = const Enum(1);
+ static const Enum e2 = const Enum(2);
+ static const Enum e3 = const Enum(3);
+ final int id;
+ const Enum(this.id);
+}
+
+void testSwitchEnum(Enum? input, int expect) {
+ int? result = null;
+ switch (input) {
+ case Enum.e1:
+ result = 10;
+ break;
+ case Enum.e2:
+ result = 20;
+ break;
+ case Enum.e3:
+ result = 30;
+ break;
+ default:
+ result = 40;
+ }
+ Expect.equals(expect, result);
+}
+
+const int ic1 = 1;
+const int ic2 = 2;
+void testSwitchIntExpression(int input, int? expect) {
+ int? result = null;
+ switch (input) {
+ case 1 + 1: // 2
+ case ic1 + 2: // 3
+ result = 11;
+ break;
+ case ic2 * 2: // 4
+ case 1 * 5: // 5
+ result = 21;
+ break;
+ case ic1 % ic2 + 5: // 6
+ result = 31;
+ break;
+ }
+ Expect.equals(expect, result);
+}
+
+void testSwitchBool(bool input, int expect) {
+ int? result = null;
+ switch (input) {
+ case true:
+ result = 12;
+ break;
+ case false:
+ result = 22;
+ }
+ Expect.equals(expect, result);
+}
+
+void testSwitchString(String? input, int? expect) {
+ int? result = null;
+ switch (input) {
+ case 'one':
+ result = 1;
+ break;
+ case 'two':
+ result = 2;
+ break;
+ }
+ Expect.equals(expect, result);
+}
+
+switchConstString() {
+ const c = 'a';
+ switch (c) {
+ case 'a':
+ return 'aa';
+ case 'b':
+ return 'bb';
+ case 'c':
+ return 'cc';
+ case 'd':
+ return 'dd';
+ case 'e':
+ return 'ee';
+ case 'f':
+ return 'ff';
+ }
+}
+
+main() {
+ SwitchTest.testMain();
+
+ testSwitchEnum(Enum.e1, 10);
+ testSwitchEnum(Enum.e2, 20);
+ testSwitchEnum(Enum.e3, 30);
+ testSwitchEnum(null, 40);
+
+ testSwitchIntExpression(2, 11);
+ testSwitchIntExpression(3, 11);
+ testSwitchIntExpression(4, 21);
+ testSwitchIntExpression(5, 21);
+ testSwitchIntExpression(6, 31);
+ testSwitchIntExpression(7, null);
+
+ testSwitchBool(true, 12);
+ testSwitchBool(false, 22);
+
+ testSwitchString(null, null);
+ testSwitchString('one', 1);
+ testSwitchString('two', 2);
+ testSwitchString('three', null);
+
+ Expect.equals('aa', switchConstString());
+}
diff --git a/tests/language/switch/try_catch_test.dart b/tests/language/switch/try_catch_test.dart
new file mode 100644
index 0000000..beee717
--- /dev/null
+++ b/tests/language/switch/try_catch_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for issue 18869: Check that try-catch is working correctly
+// inside switch-case clauses.
+
+import "package:expect/expect.dart";
+
+test_switch() {
+ switch (0) {
+ _0:
+ case 0:
+ print("_0");
+ continue _5;
+ _1:
+ case 1:
+ try {
+ print("bunny");
+ continue _6;
+ } catch (e) {}
+ break;
+ _5:
+ case 5:
+ print("_5");
+ continue _6;
+ _6:
+ case 6:
+ print("_6");
+ throw 555;
+ }
+}
+
+main() {
+ Expect.throws(() => test_switch(), (e) => e == 555);
+}
diff --git a/tests/language/symbol/conflict_test.dart b/tests/language/symbol/conflict_test.dart
new file mode 100644
index 0000000..9c95e05
--- /dev/null
+++ b/tests/language/symbol/conflict_test.dart
@@ -0,0 +1,2815 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that const symbols are only equal to the symbol they represent.
+
+import 'package:expect/expect.dart';
+
+class A {
+ noSuchMethod(invocation) {
+ Expect.isFalse(oneAndTwoCharacterSymbols.contains(invocation.memberName));
+ }
+}
+
+main() {
+ var a = new A() as dynamic;
+ a.foo = 23;
+ a.foo;
+ a.bar;
+ a.longer;
+ a.anotherOne;
+ a.add(1);
+ a.isEmpty;
+}
+
+/**
+ The following constant was generated with the following program:
+
+ const RESERVED_WORDS = const [
+ 'assert', 'break', 'case', 'catch', 'class', 'const', 'continue',
+ 'default', 'do', 'else', 'enum', 'extends', 'false', 'final',
+ 'finally', 'for', 'if', 'in', 'is', 'new', 'null', 'rethrow',
+ 'return', 'super', 'switch', 'this', 'throw', 'true', 'try',
+ 'var', 'void', 'while', 'with'];
+
+ get chars sync* {
+ for (int i = "a".codeUnitAt(0); i <= "z".codeUnitAt(0); i++) {
+ yield new String.fromCharCodes([i]);
+ }
+ for (int i = "A".codeUnitAt(0); i <= "Z".codeUnitAt(0); i++) {
+ yield new String.fromCharCodes([i]);
+ }
+ }
+
+ main() {
+ print("const oneAndTwoCharacterSymbols = const [");
+ // One character symbols.
+ for (String c in chars) {
+ print(" const Symbol('$c'),");
+ }
+ // Two character symbols.
+ for (String c1 in chars) {
+ for (String c2 in chars) {
+ if (!RESERVED_WORDS.contains('$c1$c2')) {
+ print(" const Symbol('$c1$c2'),");
+ }
+ }
+ }
+ print("];");
+ }
+*/
+const oneAndTwoCharacterSymbols = const [
+ const Symbol('a'),
+ const Symbol('b'),
+ const Symbol('c'),
+ const Symbol('d'),
+ const Symbol('e'),
+ const Symbol('f'),
+ const Symbol('g'),
+ const Symbol('h'),
+ const Symbol('i'),
+ const Symbol('j'),
+ const Symbol('k'),
+ const Symbol('l'),
+ const Symbol('m'),
+ const Symbol('n'),
+ const Symbol('o'),
+ const Symbol('p'),
+ const Symbol('q'),
+ const Symbol('r'),
+ const Symbol('s'),
+ const Symbol('t'),
+ const Symbol('u'),
+ const Symbol('v'),
+ const Symbol('w'),
+ const Symbol('x'),
+ const Symbol('y'),
+ const Symbol('z'),
+ const Symbol('A'),
+ const Symbol('B'),
+ const Symbol('C'),
+ const Symbol('D'),
+ const Symbol('E'),
+ const Symbol('F'),
+ const Symbol('G'),
+ const Symbol('H'),
+ const Symbol('I'),
+ const Symbol('J'),
+ const Symbol('K'),
+ const Symbol('L'),
+ const Symbol('M'),
+ const Symbol('N'),
+ const Symbol('O'),
+ const Symbol('P'),
+ const Symbol('Q'),
+ const Symbol('R'),
+ const Symbol('S'),
+ const Symbol('T'),
+ const Symbol('U'),
+ const Symbol('V'),
+ const Symbol('W'),
+ const Symbol('X'),
+ const Symbol('Y'),
+ const Symbol('Z'),
+ const Symbol('aa'),
+ const Symbol('ab'),
+ const Symbol('ac'),
+ const Symbol('ad'),
+ const Symbol('ae'),
+ const Symbol('af'),
+ const Symbol('ag'),
+ const Symbol('ah'),
+ const Symbol('ai'),
+ const Symbol('aj'),
+ const Symbol('ak'),
+ const Symbol('al'),
+ const Symbol('am'),
+ const Symbol('an'),
+ const Symbol('ao'),
+ const Symbol('ap'),
+ const Symbol('aq'),
+ const Symbol('ar'),
+ const Symbol('as'),
+ const Symbol('at'),
+ const Symbol('au'),
+ const Symbol('av'),
+ const Symbol('aw'),
+ const Symbol('ax'),
+ const Symbol('ay'),
+ const Symbol('az'),
+ const Symbol('aA'),
+ const Symbol('aB'),
+ const Symbol('aC'),
+ const Symbol('aD'),
+ const Symbol('aE'),
+ const Symbol('aF'),
+ const Symbol('aG'),
+ const Symbol('aH'),
+ const Symbol('aI'),
+ const Symbol('aJ'),
+ const Symbol('aK'),
+ const Symbol('aL'),
+ const Symbol('aM'),
+ const Symbol('aN'),
+ const Symbol('aO'),
+ const Symbol('aP'),
+ const Symbol('aQ'),
+ const Symbol('aR'),
+ const Symbol('aS'),
+ const Symbol('aT'),
+ const Symbol('aU'),
+ const Symbol('aV'),
+ const Symbol('aW'),
+ const Symbol('aX'),
+ const Symbol('aY'),
+ const Symbol('aZ'),
+ const Symbol('ba'),
+ const Symbol('bb'),
+ const Symbol('bc'),
+ const Symbol('bd'),
+ const Symbol('be'),
+ const Symbol('bf'),
+ const Symbol('bg'),
+ const Symbol('bh'),
+ const Symbol('bi'),
+ const Symbol('bj'),
+ const Symbol('bk'),
+ const Symbol('bl'),
+ const Symbol('bm'),
+ const Symbol('bn'),
+ const Symbol('bo'),
+ const Symbol('bp'),
+ const Symbol('bq'),
+ const Symbol('br'),
+ const Symbol('bs'),
+ const Symbol('bt'),
+ const Symbol('bu'),
+ const Symbol('bv'),
+ const Symbol('bw'),
+ const Symbol('bx'),
+ const Symbol('by'),
+ const Symbol('bz'),
+ const Symbol('bA'),
+ const Symbol('bB'),
+ const Symbol('bC'),
+ const Symbol('bD'),
+ const Symbol('bE'),
+ const Symbol('bF'),
+ const Symbol('bG'),
+ const Symbol('bH'),
+ const Symbol('bI'),
+ const Symbol('bJ'),
+ const Symbol('bK'),
+ const Symbol('bL'),
+ const Symbol('bM'),
+ const Symbol('bN'),
+ const Symbol('bO'),
+ const Symbol('bP'),
+ const Symbol('bQ'),
+ const Symbol('bR'),
+ const Symbol('bS'),
+ const Symbol('bT'),
+ const Symbol('bU'),
+ const Symbol('bV'),
+ const Symbol('bW'),
+ const Symbol('bX'),
+ const Symbol('bY'),
+ const Symbol('bZ'),
+ const Symbol('ca'),
+ const Symbol('cb'),
+ const Symbol('cc'),
+ const Symbol('cd'),
+ const Symbol('ce'),
+ const Symbol('cf'),
+ const Symbol('cg'),
+ const Symbol('ch'),
+ const Symbol('ci'),
+ const Symbol('cj'),
+ const Symbol('ck'),
+ const Symbol('cl'),
+ const Symbol('cm'),
+ const Symbol('cn'),
+ const Symbol('co'),
+ const Symbol('cp'),
+ const Symbol('cq'),
+ const Symbol('cr'),
+ const Symbol('cs'),
+ const Symbol('ct'),
+ const Symbol('cu'),
+ const Symbol('cv'),
+ const Symbol('cw'),
+ const Symbol('cx'),
+ const Symbol('cy'),
+ const Symbol('cz'),
+ const Symbol('cA'),
+ const Symbol('cB'),
+ const Symbol('cC'),
+ const Symbol('cD'),
+ const Symbol('cE'),
+ const Symbol('cF'),
+ const Symbol('cG'),
+ const Symbol('cH'),
+ const Symbol('cI'),
+ const Symbol('cJ'),
+ const Symbol('cK'),
+ const Symbol('cL'),
+ const Symbol('cM'),
+ const Symbol('cN'),
+ const Symbol('cO'),
+ const Symbol('cP'),
+ const Symbol('cQ'),
+ const Symbol('cR'),
+ const Symbol('cS'),
+ const Symbol('cT'),
+ const Symbol('cU'),
+ const Symbol('cV'),
+ const Symbol('cW'),
+ const Symbol('cX'),
+ const Symbol('cY'),
+ const Symbol('cZ'),
+ const Symbol('da'),
+ const Symbol('db'),
+ const Symbol('dc'),
+ const Symbol('dd'),
+ const Symbol('de'),
+ const Symbol('df'),
+ const Symbol('dg'),
+ const Symbol('dh'),
+ const Symbol('di'),
+ const Symbol('dj'),
+ const Symbol('dk'),
+ const Symbol('dl'),
+ const Symbol('dm'),
+ const Symbol('dn'),
+ const Symbol('dp'),
+ const Symbol('dq'),
+ const Symbol('dr'),
+ const Symbol('ds'),
+ const Symbol('dt'),
+ const Symbol('du'),
+ const Symbol('dv'),
+ const Symbol('dw'),
+ const Symbol('dx'),
+ const Symbol('dy'),
+ const Symbol('dz'),
+ const Symbol('dA'),
+ const Symbol('dB'),
+ const Symbol('dC'),
+ const Symbol('dD'),
+ const Symbol('dE'),
+ const Symbol('dF'),
+ const Symbol('dG'),
+ const Symbol('dH'),
+ const Symbol('dI'),
+ const Symbol('dJ'),
+ const Symbol('dK'),
+ const Symbol('dL'),
+ const Symbol('dM'),
+ const Symbol('dN'),
+ const Symbol('dO'),
+ const Symbol('dP'),
+ const Symbol('dQ'),
+ const Symbol('dR'),
+ const Symbol('dS'),
+ const Symbol('dT'),
+ const Symbol('dU'),
+ const Symbol('dV'),
+ const Symbol('dW'),
+ const Symbol('dX'),
+ const Symbol('dY'),
+ const Symbol('dZ'),
+ const Symbol('ea'),
+ const Symbol('eb'),
+ const Symbol('ec'),
+ const Symbol('ed'),
+ const Symbol('ee'),
+ const Symbol('ef'),
+ const Symbol('eg'),
+ const Symbol('eh'),
+ const Symbol('ei'),
+ const Symbol('ej'),
+ const Symbol('ek'),
+ const Symbol('el'),
+ const Symbol('em'),
+ const Symbol('en'),
+ const Symbol('eo'),
+ const Symbol('ep'),
+ const Symbol('eq'),
+ const Symbol('er'),
+ const Symbol('es'),
+ const Symbol('et'),
+ const Symbol('eu'),
+ const Symbol('ev'),
+ const Symbol('ew'),
+ const Symbol('ex'),
+ const Symbol('ey'),
+ const Symbol('ez'),
+ const Symbol('eA'),
+ const Symbol('eB'),
+ const Symbol('eC'),
+ const Symbol('eD'),
+ const Symbol('eE'),
+ const Symbol('eF'),
+ const Symbol('eG'),
+ const Symbol('eH'),
+ const Symbol('eI'),
+ const Symbol('eJ'),
+ const Symbol('eK'),
+ const Symbol('eL'),
+ const Symbol('eM'),
+ const Symbol('eN'),
+ const Symbol('eO'),
+ const Symbol('eP'),
+ const Symbol('eQ'),
+ const Symbol('eR'),
+ const Symbol('eS'),
+ const Symbol('eT'),
+ const Symbol('eU'),
+ const Symbol('eV'),
+ const Symbol('eW'),
+ const Symbol('eX'),
+ const Symbol('eY'),
+ const Symbol('eZ'),
+ const Symbol('fa'),
+ const Symbol('fb'),
+ const Symbol('fc'),
+ const Symbol('fd'),
+ const Symbol('fe'),
+ const Symbol('ff'),
+ const Symbol('fg'),
+ const Symbol('fh'),
+ const Symbol('fi'),
+ const Symbol('fj'),
+ const Symbol('fk'),
+ const Symbol('fl'),
+ const Symbol('fm'),
+ const Symbol('fn'),
+ const Symbol('fo'),
+ const Symbol('fp'),
+ const Symbol('fq'),
+ const Symbol('fr'),
+ const Symbol('fs'),
+ const Symbol('ft'),
+ const Symbol('fu'),
+ const Symbol('fv'),
+ const Symbol('fw'),
+ const Symbol('fx'),
+ const Symbol('fy'),
+ const Symbol('fz'),
+ const Symbol('fA'),
+ const Symbol('fB'),
+ const Symbol('fC'),
+ const Symbol('fD'),
+ const Symbol('fE'),
+ const Symbol('fF'),
+ const Symbol('fG'),
+ const Symbol('fH'),
+ const Symbol('fI'),
+ const Symbol('fJ'),
+ const Symbol('fK'),
+ const Symbol('fL'),
+ const Symbol('fM'),
+ const Symbol('fN'),
+ const Symbol('fO'),
+ const Symbol('fP'),
+ const Symbol('fQ'),
+ const Symbol('fR'),
+ const Symbol('fS'),
+ const Symbol('fT'),
+ const Symbol('fU'),
+ const Symbol('fV'),
+ const Symbol('fW'),
+ const Symbol('fX'),
+ const Symbol('fY'),
+ const Symbol('fZ'),
+ const Symbol('ga'),
+ const Symbol('gb'),
+ const Symbol('gc'),
+ const Symbol('gd'),
+ const Symbol('ge'),
+ const Symbol('gf'),
+ const Symbol('gg'),
+ const Symbol('gh'),
+ const Symbol('gi'),
+ const Symbol('gj'),
+ const Symbol('gk'),
+ const Symbol('gl'),
+ const Symbol('gm'),
+ const Symbol('gn'),
+ const Symbol('go'),
+ const Symbol('gp'),
+ const Symbol('gq'),
+ const Symbol('gr'),
+ const Symbol('gs'),
+ const Symbol('gt'),
+ const Symbol('gu'),
+ const Symbol('gv'),
+ const Symbol('gw'),
+ const Symbol('gx'),
+ const Symbol('gy'),
+ const Symbol('gz'),
+ const Symbol('gA'),
+ const Symbol('gB'),
+ const Symbol('gC'),
+ const Symbol('gD'),
+ const Symbol('gE'),
+ const Symbol('gF'),
+ const Symbol('gG'),
+ const Symbol('gH'),
+ const Symbol('gI'),
+ const Symbol('gJ'),
+ const Symbol('gK'),
+ const Symbol('gL'),
+ const Symbol('gM'),
+ const Symbol('gN'),
+ const Symbol('gO'),
+ const Symbol('gP'),
+ const Symbol('gQ'),
+ const Symbol('gR'),
+ const Symbol('gS'),
+ const Symbol('gT'),
+ const Symbol('gU'),
+ const Symbol('gV'),
+ const Symbol('gW'),
+ const Symbol('gX'),
+ const Symbol('gY'),
+ const Symbol('gZ'),
+ const Symbol('ha'),
+ const Symbol('hb'),
+ const Symbol('hc'),
+ const Symbol('hd'),
+ const Symbol('he'),
+ const Symbol('hf'),
+ const Symbol('hg'),
+ const Symbol('hh'),
+ const Symbol('hi'),
+ const Symbol('hj'),
+ const Symbol('hk'),
+ const Symbol('hl'),
+ const Symbol('hm'),
+ const Symbol('hn'),
+ const Symbol('ho'),
+ const Symbol('hp'),
+ const Symbol('hq'),
+ const Symbol('hr'),
+ const Symbol('hs'),
+ const Symbol('ht'),
+ const Symbol('hu'),
+ const Symbol('hv'),
+ const Symbol('hw'),
+ const Symbol('hx'),
+ const Symbol('hy'),
+ const Symbol('hz'),
+ const Symbol('hA'),
+ const Symbol('hB'),
+ const Symbol('hC'),
+ const Symbol('hD'),
+ const Symbol('hE'),
+ const Symbol('hF'),
+ const Symbol('hG'),
+ const Symbol('hH'),
+ const Symbol('hI'),
+ const Symbol('hJ'),
+ const Symbol('hK'),
+ const Symbol('hL'),
+ const Symbol('hM'),
+ const Symbol('hN'),
+ const Symbol('hO'),
+ const Symbol('hP'),
+ const Symbol('hQ'),
+ const Symbol('hR'),
+ const Symbol('hS'),
+ const Symbol('hT'),
+ const Symbol('hU'),
+ const Symbol('hV'),
+ const Symbol('hW'),
+ const Symbol('hX'),
+ const Symbol('hY'),
+ const Symbol('hZ'),
+ const Symbol('ia'),
+ const Symbol('ib'),
+ const Symbol('ic'),
+ const Symbol('id'),
+ const Symbol('ie'),
+ const Symbol('ig'),
+ const Symbol('ih'),
+ const Symbol('ii'),
+ const Symbol('ij'),
+ const Symbol('ik'),
+ const Symbol('il'),
+ const Symbol('im'),
+ const Symbol('io'),
+ const Symbol('ip'),
+ const Symbol('iq'),
+ const Symbol('ir'),
+ const Symbol('it'),
+ const Symbol('iu'),
+ const Symbol('iv'),
+ const Symbol('iw'),
+ const Symbol('ix'),
+ const Symbol('iy'),
+ const Symbol('iz'),
+ const Symbol('iA'),
+ const Symbol('iB'),
+ const Symbol('iC'),
+ const Symbol('iD'),
+ const Symbol('iE'),
+ const Symbol('iF'),
+ const Symbol('iG'),
+ const Symbol('iH'),
+ const Symbol('iI'),
+ const Symbol('iJ'),
+ const Symbol('iK'),
+ const Symbol('iL'),
+ const Symbol('iM'),
+ const Symbol('iN'),
+ const Symbol('iO'),
+ const Symbol('iP'),
+ const Symbol('iQ'),
+ const Symbol('iR'),
+ const Symbol('iS'),
+ const Symbol('iT'),
+ const Symbol('iU'),
+ const Symbol('iV'),
+ const Symbol('iW'),
+ const Symbol('iX'),
+ const Symbol('iY'),
+ const Symbol('iZ'),
+ const Symbol('ja'),
+ const Symbol('jb'),
+ const Symbol('jc'),
+ const Symbol('jd'),
+ const Symbol('je'),
+ const Symbol('jf'),
+ const Symbol('jg'),
+ const Symbol('jh'),
+ const Symbol('ji'),
+ const Symbol('jj'),
+ const Symbol('jk'),
+ const Symbol('jl'),
+ const Symbol('jm'),
+ const Symbol('jn'),
+ const Symbol('jo'),
+ const Symbol('jp'),
+ const Symbol('jq'),
+ const Symbol('jr'),
+ const Symbol('js'),
+ const Symbol('jt'),
+ const Symbol('ju'),
+ const Symbol('jv'),
+ const Symbol('jw'),
+ const Symbol('jx'),
+ const Symbol('jy'),
+ const Symbol('jz'),
+ const Symbol('jA'),
+ const Symbol('jB'),
+ const Symbol('jC'),
+ const Symbol('jD'),
+ const Symbol('jE'),
+ const Symbol('jF'),
+ const Symbol('jG'),
+ const Symbol('jH'),
+ const Symbol('jI'),
+ const Symbol('jJ'),
+ const Symbol('jK'),
+ const Symbol('jL'),
+ const Symbol('jM'),
+ const Symbol('jN'),
+ const Symbol('jO'),
+ const Symbol('jP'),
+ const Symbol('jQ'),
+ const Symbol('jR'),
+ const Symbol('jS'),
+ const Symbol('jT'),
+ const Symbol('jU'),
+ const Symbol('jV'),
+ const Symbol('jW'),
+ const Symbol('jX'),
+ const Symbol('jY'),
+ const Symbol('jZ'),
+ const Symbol('ka'),
+ const Symbol('kb'),
+ const Symbol('kc'),
+ const Symbol('kd'),
+ const Symbol('ke'),
+ const Symbol('kf'),
+ const Symbol('kg'),
+ const Symbol('kh'),
+ const Symbol('ki'),
+ const Symbol('kj'),
+ const Symbol('kk'),
+ const Symbol('kl'),
+ const Symbol('km'),
+ const Symbol('kn'),
+ const Symbol('ko'),
+ const Symbol('kp'),
+ const Symbol('kq'),
+ const Symbol('kr'),
+ const Symbol('ks'),
+ const Symbol('kt'),
+ const Symbol('ku'),
+ const Symbol('kv'),
+ const Symbol('kw'),
+ const Symbol('kx'),
+ const Symbol('ky'),
+ const Symbol('kz'),
+ const Symbol('kA'),
+ const Symbol('kB'),
+ const Symbol('kC'),
+ const Symbol('kD'),
+ const Symbol('kE'),
+ const Symbol('kF'),
+ const Symbol('kG'),
+ const Symbol('kH'),
+ const Symbol('kI'),
+ const Symbol('kJ'),
+ const Symbol('kK'),
+ const Symbol('kL'),
+ const Symbol('kM'),
+ const Symbol('kN'),
+ const Symbol('kO'),
+ const Symbol('kP'),
+ const Symbol('kQ'),
+ const Symbol('kR'),
+ const Symbol('kS'),
+ const Symbol('kT'),
+ const Symbol('kU'),
+ const Symbol('kV'),
+ const Symbol('kW'),
+ const Symbol('kX'),
+ const Symbol('kY'),
+ const Symbol('kZ'),
+ const Symbol('la'),
+ const Symbol('lb'),
+ const Symbol('lc'),
+ const Symbol('ld'),
+ const Symbol('le'),
+ const Symbol('lf'),
+ const Symbol('lg'),
+ const Symbol('lh'),
+ const Symbol('li'),
+ const Symbol('lj'),
+ const Symbol('lk'),
+ const Symbol('ll'),
+ const Symbol('lm'),
+ const Symbol('ln'),
+ const Symbol('lo'),
+ const Symbol('lp'),
+ const Symbol('lq'),
+ const Symbol('lr'),
+ const Symbol('ls'),
+ const Symbol('lt'),
+ const Symbol('lu'),
+ const Symbol('lv'),
+ const Symbol('lw'),
+ const Symbol('lx'),
+ const Symbol('ly'),
+ const Symbol('lz'),
+ const Symbol('lA'),
+ const Symbol('lB'),
+ const Symbol('lC'),
+ const Symbol('lD'),
+ const Symbol('lE'),
+ const Symbol('lF'),
+ const Symbol('lG'),
+ const Symbol('lH'),
+ const Symbol('lI'),
+ const Symbol('lJ'),
+ const Symbol('lK'),
+ const Symbol('lL'),
+ const Symbol('lM'),
+ const Symbol('lN'),
+ const Symbol('lO'),
+ const Symbol('lP'),
+ const Symbol('lQ'),
+ const Symbol('lR'),
+ const Symbol('lS'),
+ const Symbol('lT'),
+ const Symbol('lU'),
+ const Symbol('lV'),
+ const Symbol('lW'),
+ const Symbol('lX'),
+ const Symbol('lY'),
+ const Symbol('lZ'),
+ const Symbol('ma'),
+ const Symbol('mb'),
+ const Symbol('mc'),
+ const Symbol('md'),
+ const Symbol('me'),
+ const Symbol('mf'),
+ const Symbol('mg'),
+ const Symbol('mh'),
+ const Symbol('mi'),
+ const Symbol('mj'),
+ const Symbol('mk'),
+ const Symbol('ml'),
+ const Symbol('mm'),
+ const Symbol('mn'),
+ const Symbol('mo'),
+ const Symbol('mp'),
+ const Symbol('mq'),
+ const Symbol('mr'),
+ const Symbol('ms'),
+ const Symbol('mt'),
+ const Symbol('mu'),
+ const Symbol('mv'),
+ const Symbol('mw'),
+ const Symbol('mx'),
+ const Symbol('my'),
+ const Symbol('mz'),
+ const Symbol('mA'),
+ const Symbol('mB'),
+ const Symbol('mC'),
+ const Symbol('mD'),
+ const Symbol('mE'),
+ const Symbol('mF'),
+ const Symbol('mG'),
+ const Symbol('mH'),
+ const Symbol('mI'),
+ const Symbol('mJ'),
+ const Symbol('mK'),
+ const Symbol('mL'),
+ const Symbol('mM'),
+ const Symbol('mN'),
+ const Symbol('mO'),
+ const Symbol('mP'),
+ const Symbol('mQ'),
+ const Symbol('mR'),
+ const Symbol('mS'),
+ const Symbol('mT'),
+ const Symbol('mU'),
+ const Symbol('mV'),
+ const Symbol('mW'),
+ const Symbol('mX'),
+ const Symbol('mY'),
+ const Symbol('mZ'),
+ const Symbol('na'),
+ const Symbol('nb'),
+ const Symbol('nc'),
+ const Symbol('nd'),
+ const Symbol('ne'),
+ const Symbol('nf'),
+ const Symbol('ng'),
+ const Symbol('nh'),
+ const Symbol('ni'),
+ const Symbol('nj'),
+ const Symbol('nk'),
+ const Symbol('nl'),
+ const Symbol('nm'),
+ const Symbol('nn'),
+ const Symbol('no'),
+ const Symbol('np'),
+ const Symbol('nq'),
+ const Symbol('nr'),
+ const Symbol('ns'),
+ const Symbol('nt'),
+ const Symbol('nu'),
+ const Symbol('nv'),
+ const Symbol('nw'),
+ const Symbol('nx'),
+ const Symbol('ny'),
+ const Symbol('nz'),
+ const Symbol('nA'),
+ const Symbol('nB'),
+ const Symbol('nC'),
+ const Symbol('nD'),
+ const Symbol('nE'),
+ const Symbol('nF'),
+ const Symbol('nG'),
+ const Symbol('nH'),
+ const Symbol('nI'),
+ const Symbol('nJ'),
+ const Symbol('nK'),
+ const Symbol('nL'),
+ const Symbol('nM'),
+ const Symbol('nN'),
+ const Symbol('nO'),
+ const Symbol('nP'),
+ const Symbol('nQ'),
+ const Symbol('nR'),
+ const Symbol('nS'),
+ const Symbol('nT'),
+ const Symbol('nU'),
+ const Symbol('nV'),
+ const Symbol('nW'),
+ const Symbol('nX'),
+ const Symbol('nY'),
+ const Symbol('nZ'),
+ const Symbol('oa'),
+ const Symbol('ob'),
+ const Symbol('oc'),
+ const Symbol('od'),
+ const Symbol('oe'),
+ const Symbol('of'),
+ const Symbol('og'),
+ const Symbol('oh'),
+ const Symbol('oi'),
+ const Symbol('oj'),
+ const Symbol('ok'),
+ const Symbol('ol'),
+ const Symbol('om'),
+ const Symbol('on'),
+ const Symbol('oo'),
+ const Symbol('op'),
+ const Symbol('oq'),
+ const Symbol('or'),
+ const Symbol('os'),
+ const Symbol('ot'),
+ const Symbol('ou'),
+ const Symbol('ov'),
+ const Symbol('ow'),
+ const Symbol('ox'),
+ const Symbol('oy'),
+ const Symbol('oz'),
+ const Symbol('oA'),
+ const Symbol('oB'),
+ const Symbol('oC'),
+ const Symbol('oD'),
+ const Symbol('oE'),
+ const Symbol('oF'),
+ const Symbol('oG'),
+ const Symbol('oH'),
+ const Symbol('oI'),
+ const Symbol('oJ'),
+ const Symbol('oK'),
+ const Symbol('oL'),
+ const Symbol('oM'),
+ const Symbol('oN'),
+ const Symbol('oO'),
+ const Symbol('oP'),
+ const Symbol('oQ'),
+ const Symbol('oR'),
+ const Symbol('oS'),
+ const Symbol('oT'),
+ const Symbol('oU'),
+ const Symbol('oV'),
+ const Symbol('oW'),
+ const Symbol('oX'),
+ const Symbol('oY'),
+ const Symbol('oZ'),
+ const Symbol('pa'),
+ const Symbol('pb'),
+ const Symbol('pc'),
+ const Symbol('pd'),
+ const Symbol('pe'),
+ const Symbol('pf'),
+ const Symbol('pg'),
+ const Symbol('ph'),
+ const Symbol('pi'),
+ const Symbol('pj'),
+ const Symbol('pk'),
+ const Symbol('pl'),
+ const Symbol('pm'),
+ const Symbol('pn'),
+ const Symbol('po'),
+ const Symbol('pp'),
+ const Symbol('pq'),
+ const Symbol('pr'),
+ const Symbol('ps'),
+ const Symbol('pt'),
+ const Symbol('pu'),
+ const Symbol('pv'),
+ const Symbol('pw'),
+ const Symbol('px'),
+ const Symbol('py'),
+ const Symbol('pz'),
+ const Symbol('pA'),
+ const Symbol('pB'),
+ const Symbol('pC'),
+ const Symbol('pD'),
+ const Symbol('pE'),
+ const Symbol('pF'),
+ const Symbol('pG'),
+ const Symbol('pH'),
+ const Symbol('pI'),
+ const Symbol('pJ'),
+ const Symbol('pK'),
+ const Symbol('pL'),
+ const Symbol('pM'),
+ const Symbol('pN'),
+ const Symbol('pO'),
+ const Symbol('pP'),
+ const Symbol('pQ'),
+ const Symbol('pR'),
+ const Symbol('pS'),
+ const Symbol('pT'),
+ const Symbol('pU'),
+ const Symbol('pV'),
+ const Symbol('pW'),
+ const Symbol('pX'),
+ const Symbol('pY'),
+ const Symbol('pZ'),
+ const Symbol('qa'),
+ const Symbol('qb'),
+ const Symbol('qc'),
+ const Symbol('qd'),
+ const Symbol('qe'),
+ const Symbol('qf'),
+ const Symbol('qg'),
+ const Symbol('qh'),
+ const Symbol('qi'),
+ const Symbol('qj'),
+ const Symbol('qk'),
+ const Symbol('ql'),
+ const Symbol('qm'),
+ const Symbol('qn'),
+ const Symbol('qo'),
+ const Symbol('qp'),
+ const Symbol('qq'),
+ const Symbol('qr'),
+ const Symbol('qs'),
+ const Symbol('qt'),
+ const Symbol('qu'),
+ const Symbol('qv'),
+ const Symbol('qw'),
+ const Symbol('qx'),
+ const Symbol('qy'),
+ const Symbol('qz'),
+ const Symbol('qA'),
+ const Symbol('qB'),
+ const Symbol('qC'),
+ const Symbol('qD'),
+ const Symbol('qE'),
+ const Symbol('qF'),
+ const Symbol('qG'),
+ const Symbol('qH'),
+ const Symbol('qI'),
+ const Symbol('qJ'),
+ const Symbol('qK'),
+ const Symbol('qL'),
+ const Symbol('qM'),
+ const Symbol('qN'),
+ const Symbol('qO'),
+ const Symbol('qP'),
+ const Symbol('qQ'),
+ const Symbol('qR'),
+ const Symbol('qS'),
+ const Symbol('qT'),
+ const Symbol('qU'),
+ const Symbol('qV'),
+ const Symbol('qW'),
+ const Symbol('qX'),
+ const Symbol('qY'),
+ const Symbol('qZ'),
+ const Symbol('ra'),
+ const Symbol('rb'),
+ const Symbol('rc'),
+ const Symbol('rd'),
+ const Symbol('re'),
+ const Symbol('rf'),
+ const Symbol('rg'),
+ const Symbol('rh'),
+ const Symbol('ri'),
+ const Symbol('rj'),
+ const Symbol('rk'),
+ const Symbol('rl'),
+ const Symbol('rm'),
+ const Symbol('rn'),
+ const Symbol('ro'),
+ const Symbol('rp'),
+ const Symbol('rq'),
+ const Symbol('rr'),
+ const Symbol('rs'),
+ const Symbol('rt'),
+ const Symbol('ru'),
+ const Symbol('rv'),
+ const Symbol('rw'),
+ const Symbol('rx'),
+ const Symbol('ry'),
+ const Symbol('rz'),
+ const Symbol('rA'),
+ const Symbol('rB'),
+ const Symbol('rC'),
+ const Symbol('rD'),
+ const Symbol('rE'),
+ const Symbol('rF'),
+ const Symbol('rG'),
+ const Symbol('rH'),
+ const Symbol('rI'),
+ const Symbol('rJ'),
+ const Symbol('rK'),
+ const Symbol('rL'),
+ const Symbol('rM'),
+ const Symbol('rN'),
+ const Symbol('rO'),
+ const Symbol('rP'),
+ const Symbol('rQ'),
+ const Symbol('rR'),
+ const Symbol('rS'),
+ const Symbol('rT'),
+ const Symbol('rU'),
+ const Symbol('rV'),
+ const Symbol('rW'),
+ const Symbol('rX'),
+ const Symbol('rY'),
+ const Symbol('rZ'),
+ const Symbol('sa'),
+ const Symbol('sb'),
+ const Symbol('sc'),
+ const Symbol('sd'),
+ const Symbol('se'),
+ const Symbol('sf'),
+ const Symbol('sg'),
+ const Symbol('sh'),
+ const Symbol('si'),
+ const Symbol('sj'),
+ const Symbol('sk'),
+ const Symbol('sl'),
+ const Symbol('sm'),
+ const Symbol('sn'),
+ const Symbol('so'),
+ const Symbol('sp'),
+ const Symbol('sq'),
+ const Symbol('sr'),
+ const Symbol('ss'),
+ const Symbol('st'),
+ const Symbol('su'),
+ const Symbol('sv'),
+ const Symbol('sw'),
+ const Symbol('sx'),
+ const Symbol('sy'),
+ const Symbol('sz'),
+ const Symbol('sA'),
+ const Symbol('sB'),
+ const Symbol('sC'),
+ const Symbol('sD'),
+ const Symbol('sE'),
+ const Symbol('sF'),
+ const Symbol('sG'),
+ const Symbol('sH'),
+ const Symbol('sI'),
+ const Symbol('sJ'),
+ const Symbol('sK'),
+ const Symbol('sL'),
+ const Symbol('sM'),
+ const Symbol('sN'),
+ const Symbol('sO'),
+ const Symbol('sP'),
+ const Symbol('sQ'),
+ const Symbol('sR'),
+ const Symbol('sS'),
+ const Symbol('sT'),
+ const Symbol('sU'),
+ const Symbol('sV'),
+ const Symbol('sW'),
+ const Symbol('sX'),
+ const Symbol('sY'),
+ const Symbol('sZ'),
+ const Symbol('ta'),
+ const Symbol('tb'),
+ const Symbol('tc'),
+ const Symbol('td'),
+ const Symbol('te'),
+ const Symbol('tf'),
+ const Symbol('tg'),
+ const Symbol('th'),
+ const Symbol('ti'),
+ const Symbol('tj'),
+ const Symbol('tk'),
+ const Symbol('tl'),
+ const Symbol('tm'),
+ const Symbol('tn'),
+ const Symbol('to'),
+ const Symbol('tp'),
+ const Symbol('tq'),
+ const Symbol('tr'),
+ const Symbol('ts'),
+ const Symbol('tt'),
+ const Symbol('tu'),
+ const Symbol('tv'),
+ const Symbol('tw'),
+ const Symbol('tx'),
+ const Symbol('ty'),
+ const Symbol('tz'),
+ const Symbol('tA'),
+ const Symbol('tB'),
+ const Symbol('tC'),
+ const Symbol('tD'),
+ const Symbol('tE'),
+ const Symbol('tF'),
+ const Symbol('tG'),
+ const Symbol('tH'),
+ const Symbol('tI'),
+ const Symbol('tJ'),
+ const Symbol('tK'),
+ const Symbol('tL'),
+ const Symbol('tM'),
+ const Symbol('tN'),
+ const Symbol('tO'),
+ const Symbol('tP'),
+ const Symbol('tQ'),
+ const Symbol('tR'),
+ const Symbol('tS'),
+ const Symbol('tT'),
+ const Symbol('tU'),
+ const Symbol('tV'),
+ const Symbol('tW'),
+ const Symbol('tX'),
+ const Symbol('tY'),
+ const Symbol('tZ'),
+ const Symbol('ua'),
+ const Symbol('ub'),
+ const Symbol('uc'),
+ const Symbol('ud'),
+ const Symbol('ue'),
+ const Symbol('uf'),
+ const Symbol('ug'),
+ const Symbol('uh'),
+ const Symbol('ui'),
+ const Symbol('uj'),
+ const Symbol('uk'),
+ const Symbol('ul'),
+ const Symbol('um'),
+ const Symbol('un'),
+ const Symbol('uo'),
+ const Symbol('up'),
+ const Symbol('uq'),
+ const Symbol('ur'),
+ const Symbol('us'),
+ const Symbol('ut'),
+ const Symbol('uu'),
+ const Symbol('uv'),
+ const Symbol('uw'),
+ const Symbol('ux'),
+ const Symbol('uy'),
+ const Symbol('uz'),
+ const Symbol('uA'),
+ const Symbol('uB'),
+ const Symbol('uC'),
+ const Symbol('uD'),
+ const Symbol('uE'),
+ const Symbol('uF'),
+ const Symbol('uG'),
+ const Symbol('uH'),
+ const Symbol('uI'),
+ const Symbol('uJ'),
+ const Symbol('uK'),
+ const Symbol('uL'),
+ const Symbol('uM'),
+ const Symbol('uN'),
+ const Symbol('uO'),
+ const Symbol('uP'),
+ const Symbol('uQ'),
+ const Symbol('uR'),
+ const Symbol('uS'),
+ const Symbol('uT'),
+ const Symbol('uU'),
+ const Symbol('uV'),
+ const Symbol('uW'),
+ const Symbol('uX'),
+ const Symbol('uY'),
+ const Symbol('uZ'),
+ const Symbol('va'),
+ const Symbol('vb'),
+ const Symbol('vc'),
+ const Symbol('vd'),
+ const Symbol('ve'),
+ const Symbol('vf'),
+ const Symbol('vg'),
+ const Symbol('vh'),
+ const Symbol('vi'),
+ const Symbol('vj'),
+ const Symbol('vk'),
+ const Symbol('vl'),
+ const Symbol('vm'),
+ const Symbol('vn'),
+ const Symbol('vo'),
+ const Symbol('vp'),
+ const Symbol('vq'),
+ const Symbol('vr'),
+ const Symbol('vs'),
+ const Symbol('vt'),
+ const Symbol('vu'),
+ const Symbol('vv'),
+ const Symbol('vw'),
+ const Symbol('vx'),
+ const Symbol('vy'),
+ const Symbol('vz'),
+ const Symbol('vA'),
+ const Symbol('vB'),
+ const Symbol('vC'),
+ const Symbol('vD'),
+ const Symbol('vE'),
+ const Symbol('vF'),
+ const Symbol('vG'),
+ const Symbol('vH'),
+ const Symbol('vI'),
+ const Symbol('vJ'),
+ const Symbol('vK'),
+ const Symbol('vL'),
+ const Symbol('vM'),
+ const Symbol('vN'),
+ const Symbol('vO'),
+ const Symbol('vP'),
+ const Symbol('vQ'),
+ const Symbol('vR'),
+ const Symbol('vS'),
+ const Symbol('vT'),
+ const Symbol('vU'),
+ const Symbol('vV'),
+ const Symbol('vW'),
+ const Symbol('vX'),
+ const Symbol('vY'),
+ const Symbol('vZ'),
+ const Symbol('wa'),
+ const Symbol('wb'),
+ const Symbol('wc'),
+ const Symbol('wd'),
+ const Symbol('we'),
+ const Symbol('wf'),
+ const Symbol('wg'),
+ const Symbol('wh'),
+ const Symbol('wi'),
+ const Symbol('wj'),
+ const Symbol('wk'),
+ const Symbol('wl'),
+ const Symbol('wm'),
+ const Symbol('wn'),
+ const Symbol('wo'),
+ const Symbol('wp'),
+ const Symbol('wq'),
+ const Symbol('wr'),
+ const Symbol('ws'),
+ const Symbol('wt'),
+ const Symbol('wu'),
+ const Symbol('wv'),
+ const Symbol('ww'),
+ const Symbol('wx'),
+ const Symbol('wy'),
+ const Symbol('wz'),
+ const Symbol('wA'),
+ const Symbol('wB'),
+ const Symbol('wC'),
+ const Symbol('wD'),
+ const Symbol('wE'),
+ const Symbol('wF'),
+ const Symbol('wG'),
+ const Symbol('wH'),
+ const Symbol('wI'),
+ const Symbol('wJ'),
+ const Symbol('wK'),
+ const Symbol('wL'),
+ const Symbol('wM'),
+ const Symbol('wN'),
+ const Symbol('wO'),
+ const Symbol('wP'),
+ const Symbol('wQ'),
+ const Symbol('wR'),
+ const Symbol('wS'),
+ const Symbol('wT'),
+ const Symbol('wU'),
+ const Symbol('wV'),
+ const Symbol('wW'),
+ const Symbol('wX'),
+ const Symbol('wY'),
+ const Symbol('wZ'),
+ const Symbol('xa'),
+ const Symbol('xb'),
+ const Symbol('xc'),
+ const Symbol('xd'),
+ const Symbol('xe'),
+ const Symbol('xf'),
+ const Symbol('xg'),
+ const Symbol('xh'),
+ const Symbol('xi'),
+ const Symbol('xj'),
+ const Symbol('xk'),
+ const Symbol('xl'),
+ const Symbol('xm'),
+ const Symbol('xn'),
+ const Symbol('xo'),
+ const Symbol('xp'),
+ const Symbol('xq'),
+ const Symbol('xr'),
+ const Symbol('xs'),
+ const Symbol('xt'),
+ const Symbol('xu'),
+ const Symbol('xv'),
+ const Symbol('xw'),
+ const Symbol('xx'),
+ const Symbol('xy'),
+ const Symbol('xz'),
+ const Symbol('xA'),
+ const Symbol('xB'),
+ const Symbol('xC'),
+ const Symbol('xD'),
+ const Symbol('xE'),
+ const Symbol('xF'),
+ const Symbol('xG'),
+ const Symbol('xH'),
+ const Symbol('xI'),
+ const Symbol('xJ'),
+ const Symbol('xK'),
+ const Symbol('xL'),
+ const Symbol('xM'),
+ const Symbol('xN'),
+ const Symbol('xO'),
+ const Symbol('xP'),
+ const Symbol('xQ'),
+ const Symbol('xR'),
+ const Symbol('xS'),
+ const Symbol('xT'),
+ const Symbol('xU'),
+ const Symbol('xV'),
+ const Symbol('xW'),
+ const Symbol('xX'),
+ const Symbol('xY'),
+ const Symbol('xZ'),
+ const Symbol('ya'),
+ const Symbol('yb'),
+ const Symbol('yc'),
+ const Symbol('yd'),
+ const Symbol('ye'),
+ const Symbol('yf'),
+ const Symbol('yg'),
+ const Symbol('yh'),
+ const Symbol('yi'),
+ const Symbol('yj'),
+ const Symbol('yk'),
+ const Symbol('yl'),
+ const Symbol('ym'),
+ const Symbol('yn'),
+ const Symbol('yo'),
+ const Symbol('yp'),
+ const Symbol('yq'),
+ const Symbol('yr'),
+ const Symbol('ys'),
+ const Symbol('yt'),
+ const Symbol('yu'),
+ const Symbol('yv'),
+ const Symbol('yw'),
+ const Symbol('yx'),
+ const Symbol('yy'),
+ const Symbol('yz'),
+ const Symbol('yA'),
+ const Symbol('yB'),
+ const Symbol('yC'),
+ const Symbol('yD'),
+ const Symbol('yE'),
+ const Symbol('yF'),
+ const Symbol('yG'),
+ const Symbol('yH'),
+ const Symbol('yI'),
+ const Symbol('yJ'),
+ const Symbol('yK'),
+ const Symbol('yL'),
+ const Symbol('yM'),
+ const Symbol('yN'),
+ const Symbol('yO'),
+ const Symbol('yP'),
+ const Symbol('yQ'),
+ const Symbol('yR'),
+ const Symbol('yS'),
+ const Symbol('yT'),
+ const Symbol('yU'),
+ const Symbol('yV'),
+ const Symbol('yW'),
+ const Symbol('yX'),
+ const Symbol('yY'),
+ const Symbol('yZ'),
+ const Symbol('za'),
+ const Symbol('zb'),
+ const Symbol('zc'),
+ const Symbol('zd'),
+ const Symbol('ze'),
+ const Symbol('zf'),
+ const Symbol('zg'),
+ const Symbol('zh'),
+ const Symbol('zi'),
+ const Symbol('zj'),
+ const Symbol('zk'),
+ const Symbol('zl'),
+ const Symbol('zm'),
+ const Symbol('zn'),
+ const Symbol('zo'),
+ const Symbol('zp'),
+ const Symbol('zq'),
+ const Symbol('zr'),
+ const Symbol('zs'),
+ const Symbol('zt'),
+ const Symbol('zu'),
+ const Symbol('zv'),
+ const Symbol('zw'),
+ const Symbol('zx'),
+ const Symbol('zy'),
+ const Symbol('zz'),
+ const Symbol('zA'),
+ const Symbol('zB'),
+ const Symbol('zC'),
+ const Symbol('zD'),
+ const Symbol('zE'),
+ const Symbol('zF'),
+ const Symbol('zG'),
+ const Symbol('zH'),
+ const Symbol('zI'),
+ const Symbol('zJ'),
+ const Symbol('zK'),
+ const Symbol('zL'),
+ const Symbol('zM'),
+ const Symbol('zN'),
+ const Symbol('zO'),
+ const Symbol('zP'),
+ const Symbol('zQ'),
+ const Symbol('zR'),
+ const Symbol('zS'),
+ const Symbol('zT'),
+ const Symbol('zU'),
+ const Symbol('zV'),
+ const Symbol('zW'),
+ const Symbol('zX'),
+ const Symbol('zY'),
+ const Symbol('zZ'),
+ const Symbol('Aa'),
+ const Symbol('Ab'),
+ const Symbol('Ac'),
+ const Symbol('Ad'),
+ const Symbol('Ae'),
+ const Symbol('Af'),
+ const Symbol('Ag'),
+ const Symbol('Ah'),
+ const Symbol('Ai'),
+ const Symbol('Aj'),
+ const Symbol('Ak'),
+ const Symbol('Al'),
+ const Symbol('Am'),
+ const Symbol('An'),
+ const Symbol('Ao'),
+ const Symbol('Ap'),
+ const Symbol('Aq'),
+ const Symbol('Ar'),
+ const Symbol('As'),
+ const Symbol('At'),
+ const Symbol('Au'),
+ const Symbol('Av'),
+ const Symbol('Aw'),
+ const Symbol('Ax'),
+ const Symbol('Ay'),
+ const Symbol('Az'),
+ const Symbol('AA'),
+ const Symbol('AB'),
+ const Symbol('AC'),
+ const Symbol('AD'),
+ const Symbol('AE'),
+ const Symbol('AF'),
+ const Symbol('AG'),
+ const Symbol('AH'),
+ const Symbol('AI'),
+ const Symbol('AJ'),
+ const Symbol('AK'),
+ const Symbol('AL'),
+ const Symbol('AM'),
+ const Symbol('AN'),
+ const Symbol('AO'),
+ const Symbol('AP'),
+ const Symbol('AQ'),
+ const Symbol('AR'),
+ const Symbol('AS'),
+ const Symbol('AT'),
+ const Symbol('AU'),
+ const Symbol('AV'),
+ const Symbol('AW'),
+ const Symbol('AX'),
+ const Symbol('AY'),
+ const Symbol('AZ'),
+ const Symbol('Ba'),
+ const Symbol('Bb'),
+ const Symbol('Bc'),
+ const Symbol('Bd'),
+ const Symbol('Be'),
+ const Symbol('Bf'),
+ const Symbol('Bg'),
+ const Symbol('Bh'),
+ const Symbol('Bi'),
+ const Symbol('Bj'),
+ const Symbol('Bk'),
+ const Symbol('Bl'),
+ const Symbol('Bm'),
+ const Symbol('Bn'),
+ const Symbol('Bo'),
+ const Symbol('Bp'),
+ const Symbol('Bq'),
+ const Symbol('Br'),
+ const Symbol('Bs'),
+ const Symbol('Bt'),
+ const Symbol('Bu'),
+ const Symbol('Bv'),
+ const Symbol('Bw'),
+ const Symbol('Bx'),
+ const Symbol('By'),
+ const Symbol('Bz'),
+ const Symbol('BA'),
+ const Symbol('BB'),
+ const Symbol('BC'),
+ const Symbol('BD'),
+ const Symbol('BE'),
+ const Symbol('BF'),
+ const Symbol('BG'),
+ const Symbol('BH'),
+ const Symbol('BI'),
+ const Symbol('BJ'),
+ const Symbol('BK'),
+ const Symbol('BL'),
+ const Symbol('BM'),
+ const Symbol('BN'),
+ const Symbol('BO'),
+ const Symbol('BP'),
+ const Symbol('BQ'),
+ const Symbol('BR'),
+ const Symbol('BS'),
+ const Symbol('BT'),
+ const Symbol('BU'),
+ const Symbol('BV'),
+ const Symbol('BW'),
+ const Symbol('BX'),
+ const Symbol('BY'),
+ const Symbol('BZ'),
+ const Symbol('Ca'),
+ const Symbol('Cb'),
+ const Symbol('Cc'),
+ const Symbol('Cd'),
+ const Symbol('Ce'),
+ const Symbol('Cf'),
+ const Symbol('Cg'),
+ const Symbol('Ch'),
+ const Symbol('Ci'),
+ const Symbol('Cj'),
+ const Symbol('Ck'),
+ const Symbol('Cl'),
+ const Symbol('Cm'),
+ const Symbol('Cn'),
+ const Symbol('Co'),
+ const Symbol('Cp'),
+ const Symbol('Cq'),
+ const Symbol('Cr'),
+ const Symbol('Cs'),
+ const Symbol('Ct'),
+ const Symbol('Cu'),
+ const Symbol('Cv'),
+ const Symbol('Cw'),
+ const Symbol('Cx'),
+ const Symbol('Cy'),
+ const Symbol('Cz'),
+ const Symbol('CA'),
+ const Symbol('CB'),
+ const Symbol('CC'),
+ const Symbol('CD'),
+ const Symbol('CE'),
+ const Symbol('CF'),
+ const Symbol('CG'),
+ const Symbol('CH'),
+ const Symbol('CI'),
+ const Symbol('CJ'),
+ const Symbol('CK'),
+ const Symbol('CL'),
+ const Symbol('CM'),
+ const Symbol('CN'),
+ const Symbol('CO'),
+ const Symbol('CP'),
+ const Symbol('CQ'),
+ const Symbol('CR'),
+ const Symbol('CS'),
+ const Symbol('CT'),
+ const Symbol('CU'),
+ const Symbol('CV'),
+ const Symbol('CW'),
+ const Symbol('CX'),
+ const Symbol('CY'),
+ const Symbol('CZ'),
+ const Symbol('Da'),
+ const Symbol('Db'),
+ const Symbol('Dc'),
+ const Symbol('Dd'),
+ const Symbol('De'),
+ const Symbol('Df'),
+ const Symbol('Dg'),
+ const Symbol('Dh'),
+ const Symbol('Di'),
+ const Symbol('Dj'),
+ const Symbol('Dk'),
+ const Symbol('Dl'),
+ const Symbol('Dm'),
+ const Symbol('Dn'),
+ const Symbol('Do'),
+ const Symbol('Dp'),
+ const Symbol('Dq'),
+ const Symbol('Dr'),
+ const Symbol('Ds'),
+ const Symbol('Dt'),
+ const Symbol('Du'),
+ const Symbol('Dv'),
+ const Symbol('Dw'),
+ const Symbol('Dx'),
+ const Symbol('Dy'),
+ const Symbol('Dz'),
+ const Symbol('DA'),
+ const Symbol('DB'),
+ const Symbol('DC'),
+ const Symbol('DD'),
+ const Symbol('DE'),
+ const Symbol('DF'),
+ const Symbol('DG'),
+ const Symbol('DH'),
+ const Symbol('DI'),
+ const Symbol('DJ'),
+ const Symbol('DK'),
+ const Symbol('DL'),
+ const Symbol('DM'),
+ const Symbol('DN'),
+ const Symbol('DO'),
+ const Symbol('DP'),
+ const Symbol('DQ'),
+ const Symbol('DR'),
+ const Symbol('DS'),
+ const Symbol('DT'),
+ const Symbol('DU'),
+ const Symbol('DV'),
+ const Symbol('DW'),
+ const Symbol('DX'),
+ const Symbol('DY'),
+ const Symbol('DZ'),
+ const Symbol('Ea'),
+ const Symbol('Eb'),
+ const Symbol('Ec'),
+ const Symbol('Ed'),
+ const Symbol('Ee'),
+ const Symbol('Ef'),
+ const Symbol('Eg'),
+ const Symbol('Eh'),
+ const Symbol('Ei'),
+ const Symbol('Ej'),
+ const Symbol('Ek'),
+ const Symbol('El'),
+ const Symbol('Em'),
+ const Symbol('En'),
+ const Symbol('Eo'),
+ const Symbol('Ep'),
+ const Symbol('Eq'),
+ const Symbol('Er'),
+ const Symbol('Es'),
+ const Symbol('Et'),
+ const Symbol('Eu'),
+ const Symbol('Ev'),
+ const Symbol('Ew'),
+ const Symbol('Ex'),
+ const Symbol('Ey'),
+ const Symbol('Ez'),
+ const Symbol('EA'),
+ const Symbol('EB'),
+ const Symbol('EC'),
+ const Symbol('ED'),
+ const Symbol('EE'),
+ const Symbol('EF'),
+ const Symbol('EG'),
+ const Symbol('EH'),
+ const Symbol('EI'),
+ const Symbol('EJ'),
+ const Symbol('EK'),
+ const Symbol('EL'),
+ const Symbol('EM'),
+ const Symbol('EN'),
+ const Symbol('EO'),
+ const Symbol('EP'),
+ const Symbol('EQ'),
+ const Symbol('ER'),
+ const Symbol('ES'),
+ const Symbol('ET'),
+ const Symbol('EU'),
+ const Symbol('EV'),
+ const Symbol('EW'),
+ const Symbol('EX'),
+ const Symbol('EY'),
+ const Symbol('EZ'),
+ const Symbol('Fa'),
+ const Symbol('Fb'),
+ const Symbol('Fc'),
+ const Symbol('Fd'),
+ const Symbol('Fe'),
+ const Symbol('Ff'),
+ const Symbol('Fg'),
+ const Symbol('Fh'),
+ const Symbol('Fi'),
+ const Symbol('Fj'),
+ const Symbol('Fk'),
+ const Symbol('Fl'),
+ const Symbol('Fm'),
+ const Symbol('Fn'),
+ const Symbol('Fo'),
+ const Symbol('Fp'),
+ const Symbol('Fq'),
+ const Symbol('Fr'),
+ const Symbol('Fs'),
+ const Symbol('Ft'),
+ const Symbol('Fu'),
+ const Symbol('Fv'),
+ const Symbol('Fw'),
+ const Symbol('Fx'),
+ const Symbol('Fy'),
+ const Symbol('Fz'),
+ const Symbol('FA'),
+ const Symbol('FB'),
+ const Symbol('FC'),
+ const Symbol('FD'),
+ const Symbol('FE'),
+ const Symbol('FF'),
+ const Symbol('FG'),
+ const Symbol('FH'),
+ const Symbol('FI'),
+ const Symbol('FJ'),
+ const Symbol('FK'),
+ const Symbol('FL'),
+ const Symbol('FM'),
+ const Symbol('FN'),
+ const Symbol('FO'),
+ const Symbol('FP'),
+ const Symbol('FQ'),
+ const Symbol('FR'),
+ const Symbol('FS'),
+ const Symbol('FT'),
+ const Symbol('FU'),
+ const Symbol('FV'),
+ const Symbol('FW'),
+ const Symbol('FX'),
+ const Symbol('FY'),
+ const Symbol('FZ'),
+ const Symbol('Ga'),
+ const Symbol('Gb'),
+ const Symbol('Gc'),
+ const Symbol('Gd'),
+ const Symbol('Ge'),
+ const Symbol('Gf'),
+ const Symbol('Gg'),
+ const Symbol('Gh'),
+ const Symbol('Gi'),
+ const Symbol('Gj'),
+ const Symbol('Gk'),
+ const Symbol('Gl'),
+ const Symbol('Gm'),
+ const Symbol('Gn'),
+ const Symbol('Go'),
+ const Symbol('Gp'),
+ const Symbol('Gq'),
+ const Symbol('Gr'),
+ const Symbol('Gs'),
+ const Symbol('Gt'),
+ const Symbol('Gu'),
+ const Symbol('Gv'),
+ const Symbol('Gw'),
+ const Symbol('Gx'),
+ const Symbol('Gy'),
+ const Symbol('Gz'),
+ const Symbol('GA'),
+ const Symbol('GB'),
+ const Symbol('GC'),
+ const Symbol('GD'),
+ const Symbol('GE'),
+ const Symbol('GF'),
+ const Symbol('GG'),
+ const Symbol('GH'),
+ const Symbol('GI'),
+ const Symbol('GJ'),
+ const Symbol('GK'),
+ const Symbol('GL'),
+ const Symbol('GM'),
+ const Symbol('GN'),
+ const Symbol('GO'),
+ const Symbol('GP'),
+ const Symbol('GQ'),
+ const Symbol('GR'),
+ const Symbol('GS'),
+ const Symbol('GT'),
+ const Symbol('GU'),
+ const Symbol('GV'),
+ const Symbol('GW'),
+ const Symbol('GX'),
+ const Symbol('GY'),
+ const Symbol('GZ'),
+ const Symbol('Ha'),
+ const Symbol('Hb'),
+ const Symbol('Hc'),
+ const Symbol('Hd'),
+ const Symbol('He'),
+ const Symbol('Hf'),
+ const Symbol('Hg'),
+ const Symbol('Hh'),
+ const Symbol('Hi'),
+ const Symbol('Hj'),
+ const Symbol('Hk'),
+ const Symbol('Hl'),
+ const Symbol('Hm'),
+ const Symbol('Hn'),
+ const Symbol('Ho'),
+ const Symbol('Hp'),
+ const Symbol('Hq'),
+ const Symbol('Hr'),
+ const Symbol('Hs'),
+ const Symbol('Ht'),
+ const Symbol('Hu'),
+ const Symbol('Hv'),
+ const Symbol('Hw'),
+ const Symbol('Hx'),
+ const Symbol('Hy'),
+ const Symbol('Hz'),
+ const Symbol('HA'),
+ const Symbol('HB'),
+ const Symbol('HC'),
+ const Symbol('HD'),
+ const Symbol('HE'),
+ const Symbol('HF'),
+ const Symbol('HG'),
+ const Symbol('HH'),
+ const Symbol('HI'),
+ const Symbol('HJ'),
+ const Symbol('HK'),
+ const Symbol('HL'),
+ const Symbol('HM'),
+ const Symbol('HN'),
+ const Symbol('HO'),
+ const Symbol('HP'),
+ const Symbol('HQ'),
+ const Symbol('HR'),
+ const Symbol('HS'),
+ const Symbol('HT'),
+ const Symbol('HU'),
+ const Symbol('HV'),
+ const Symbol('HW'),
+ const Symbol('HX'),
+ const Symbol('HY'),
+ const Symbol('HZ'),
+ const Symbol('Ia'),
+ const Symbol('Ib'),
+ const Symbol('Ic'),
+ const Symbol('Id'),
+ const Symbol('Ie'),
+ const Symbol('If'),
+ const Symbol('Ig'),
+ const Symbol('Ih'),
+ const Symbol('Ii'),
+ const Symbol('Ij'),
+ const Symbol('Ik'),
+ const Symbol('Il'),
+ const Symbol('Im'),
+ const Symbol('In'),
+ const Symbol('Io'),
+ const Symbol('Ip'),
+ const Symbol('Iq'),
+ const Symbol('Ir'),
+ const Symbol('Is'),
+ const Symbol('It'),
+ const Symbol('Iu'),
+ const Symbol('Iv'),
+ const Symbol('Iw'),
+ const Symbol('Ix'),
+ const Symbol('Iy'),
+ const Symbol('Iz'),
+ const Symbol('IA'),
+ const Symbol('IB'),
+ const Symbol('IC'),
+ const Symbol('ID'),
+ const Symbol('IE'),
+ const Symbol('IF'),
+ const Symbol('IG'),
+ const Symbol('IH'),
+ const Symbol('II'),
+ const Symbol('IJ'),
+ const Symbol('IK'),
+ const Symbol('IL'),
+ const Symbol('IM'),
+ const Symbol('IN'),
+ const Symbol('IO'),
+ const Symbol('IP'),
+ const Symbol('IQ'),
+ const Symbol('IR'),
+ const Symbol('IS'),
+ const Symbol('IT'),
+ const Symbol('IU'),
+ const Symbol('IV'),
+ const Symbol('IW'),
+ const Symbol('IX'),
+ const Symbol('IY'),
+ const Symbol('IZ'),
+ const Symbol('Ja'),
+ const Symbol('Jb'),
+ const Symbol('Jc'),
+ const Symbol('Jd'),
+ const Symbol('Je'),
+ const Symbol('Jf'),
+ const Symbol('Jg'),
+ const Symbol('Jh'),
+ const Symbol('Ji'),
+ const Symbol('Jj'),
+ const Symbol('Jk'),
+ const Symbol('Jl'),
+ const Symbol('Jm'),
+ const Symbol('Jn'),
+ const Symbol('Jo'),
+ const Symbol('Jp'),
+ const Symbol('Jq'),
+ const Symbol('Jr'),
+ const Symbol('Js'),
+ const Symbol('Jt'),
+ const Symbol('Ju'),
+ const Symbol('Jv'),
+ const Symbol('Jw'),
+ const Symbol('Jx'),
+ const Symbol('Jy'),
+ const Symbol('Jz'),
+ const Symbol('JA'),
+ const Symbol('JB'),
+ const Symbol('JC'),
+ const Symbol('JD'),
+ const Symbol('JE'),
+ const Symbol('JF'),
+ const Symbol('JG'),
+ const Symbol('JH'),
+ const Symbol('JI'),
+ const Symbol('JJ'),
+ const Symbol('JK'),
+ const Symbol('JL'),
+ const Symbol('JM'),
+ const Symbol('JN'),
+ const Symbol('JO'),
+ const Symbol('JP'),
+ const Symbol('JQ'),
+ const Symbol('JR'),
+ const Symbol('JS'),
+ const Symbol('JT'),
+ const Symbol('JU'),
+ const Symbol('JV'),
+ const Symbol('JW'),
+ const Symbol('JX'),
+ const Symbol('JY'),
+ const Symbol('JZ'),
+ const Symbol('Ka'),
+ const Symbol('Kb'),
+ const Symbol('Kc'),
+ const Symbol('Kd'),
+ const Symbol('Ke'),
+ const Symbol('Kf'),
+ const Symbol('Kg'),
+ const Symbol('Kh'),
+ const Symbol('Ki'),
+ const Symbol('Kj'),
+ const Symbol('Kk'),
+ const Symbol('Kl'),
+ const Symbol('Km'),
+ const Symbol('Kn'),
+ const Symbol('Ko'),
+ const Symbol('Kp'),
+ const Symbol('Kq'),
+ const Symbol('Kr'),
+ const Symbol('Ks'),
+ const Symbol('Kt'),
+ const Symbol('Ku'),
+ const Symbol('Kv'),
+ const Symbol('Kw'),
+ const Symbol('Kx'),
+ const Symbol('Ky'),
+ const Symbol('Kz'),
+ const Symbol('KA'),
+ const Symbol('KB'),
+ const Symbol('KC'),
+ const Symbol('KD'),
+ const Symbol('KE'),
+ const Symbol('KF'),
+ const Symbol('KG'),
+ const Symbol('KH'),
+ const Symbol('KI'),
+ const Symbol('KJ'),
+ const Symbol('KK'),
+ const Symbol('KL'),
+ const Symbol('KM'),
+ const Symbol('KN'),
+ const Symbol('KO'),
+ const Symbol('KP'),
+ const Symbol('KQ'),
+ const Symbol('KR'),
+ const Symbol('KS'),
+ const Symbol('KT'),
+ const Symbol('KU'),
+ const Symbol('KV'),
+ const Symbol('KW'),
+ const Symbol('KX'),
+ const Symbol('KY'),
+ const Symbol('KZ'),
+ const Symbol('La'),
+ const Symbol('Lb'),
+ const Symbol('Lc'),
+ const Symbol('Ld'),
+ const Symbol('Le'),
+ const Symbol('Lf'),
+ const Symbol('Lg'),
+ const Symbol('Lh'),
+ const Symbol('Li'),
+ const Symbol('Lj'),
+ const Symbol('Lk'),
+ const Symbol('Ll'),
+ const Symbol('Lm'),
+ const Symbol('Ln'),
+ const Symbol('Lo'),
+ const Symbol('Lp'),
+ const Symbol('Lq'),
+ const Symbol('Lr'),
+ const Symbol('Ls'),
+ const Symbol('Lt'),
+ const Symbol('Lu'),
+ const Symbol('Lv'),
+ const Symbol('Lw'),
+ const Symbol('Lx'),
+ const Symbol('Ly'),
+ const Symbol('Lz'),
+ const Symbol('LA'),
+ const Symbol('LB'),
+ const Symbol('LC'),
+ const Symbol('LD'),
+ const Symbol('LE'),
+ const Symbol('LF'),
+ const Symbol('LG'),
+ const Symbol('LH'),
+ const Symbol('LI'),
+ const Symbol('LJ'),
+ const Symbol('LK'),
+ const Symbol('LL'),
+ const Symbol('LM'),
+ const Symbol('LN'),
+ const Symbol('LO'),
+ const Symbol('LP'),
+ const Symbol('LQ'),
+ const Symbol('LR'),
+ const Symbol('LS'),
+ const Symbol('LT'),
+ const Symbol('LU'),
+ const Symbol('LV'),
+ const Symbol('LW'),
+ const Symbol('LX'),
+ const Symbol('LY'),
+ const Symbol('LZ'),
+ const Symbol('Ma'),
+ const Symbol('Mb'),
+ const Symbol('Mc'),
+ const Symbol('Md'),
+ const Symbol('Me'),
+ const Symbol('Mf'),
+ const Symbol('Mg'),
+ const Symbol('Mh'),
+ const Symbol('Mi'),
+ const Symbol('Mj'),
+ const Symbol('Mk'),
+ const Symbol('Ml'),
+ const Symbol('Mm'),
+ const Symbol('Mn'),
+ const Symbol('Mo'),
+ const Symbol('Mp'),
+ const Symbol('Mq'),
+ const Symbol('Mr'),
+ const Symbol('Ms'),
+ const Symbol('Mt'),
+ const Symbol('Mu'),
+ const Symbol('Mv'),
+ const Symbol('Mw'),
+ const Symbol('Mx'),
+ const Symbol('My'),
+ const Symbol('Mz'),
+ const Symbol('MA'),
+ const Symbol('MB'),
+ const Symbol('MC'),
+ const Symbol('MD'),
+ const Symbol('ME'),
+ const Symbol('MF'),
+ const Symbol('MG'),
+ const Symbol('MH'),
+ const Symbol('MI'),
+ const Symbol('MJ'),
+ const Symbol('MK'),
+ const Symbol('ML'),
+ const Symbol('MM'),
+ const Symbol('MN'),
+ const Symbol('MO'),
+ const Symbol('MP'),
+ const Symbol('MQ'),
+ const Symbol('MR'),
+ const Symbol('MS'),
+ const Symbol('MT'),
+ const Symbol('MU'),
+ const Symbol('MV'),
+ const Symbol('MW'),
+ const Symbol('MX'),
+ const Symbol('MY'),
+ const Symbol('MZ'),
+ const Symbol('Na'),
+ const Symbol('Nb'),
+ const Symbol('Nc'),
+ const Symbol('Nd'),
+ const Symbol('Ne'),
+ const Symbol('Nf'),
+ const Symbol('Ng'),
+ const Symbol('Nh'),
+ const Symbol('Ni'),
+ const Symbol('Nj'),
+ const Symbol('Nk'),
+ const Symbol('Nl'),
+ const Symbol('Nm'),
+ const Symbol('Nn'),
+ const Symbol('No'),
+ const Symbol('Np'),
+ const Symbol('Nq'),
+ const Symbol('Nr'),
+ const Symbol('Ns'),
+ const Symbol('Nt'),
+ const Symbol('Nu'),
+ const Symbol('Nv'),
+ const Symbol('Nw'),
+ const Symbol('Nx'),
+ const Symbol('Ny'),
+ const Symbol('Nz'),
+ const Symbol('NA'),
+ const Symbol('NB'),
+ const Symbol('NC'),
+ const Symbol('ND'),
+ const Symbol('NE'),
+ const Symbol('NF'),
+ const Symbol('NG'),
+ const Symbol('NH'),
+ const Symbol('NI'),
+ const Symbol('NJ'),
+ const Symbol('NK'),
+ const Symbol('NL'),
+ const Symbol('NM'),
+ const Symbol('NN'),
+ const Symbol('NO'),
+ const Symbol('NP'),
+ const Symbol('NQ'),
+ const Symbol('NR'),
+ const Symbol('NS'),
+ const Symbol('NT'),
+ const Symbol('NU'),
+ const Symbol('NV'),
+ const Symbol('NW'),
+ const Symbol('NX'),
+ const Symbol('NY'),
+ const Symbol('NZ'),
+ const Symbol('Oa'),
+ const Symbol('Ob'),
+ const Symbol('Oc'),
+ const Symbol('Od'),
+ const Symbol('Oe'),
+ const Symbol('Of'),
+ const Symbol('Og'),
+ const Symbol('Oh'),
+ const Symbol('Oi'),
+ const Symbol('Oj'),
+ const Symbol('Ok'),
+ const Symbol('Ol'),
+ const Symbol('Om'),
+ const Symbol('On'),
+ const Symbol('Oo'),
+ const Symbol('Op'),
+ const Symbol('Oq'),
+ const Symbol('Or'),
+ const Symbol('Os'),
+ const Symbol('Ot'),
+ const Symbol('Ou'),
+ const Symbol('Ov'),
+ const Symbol('Ow'),
+ const Symbol('Ox'),
+ const Symbol('Oy'),
+ const Symbol('Oz'),
+ const Symbol('OA'),
+ const Symbol('OB'),
+ const Symbol('OC'),
+ const Symbol('OD'),
+ const Symbol('OE'),
+ const Symbol('OF'),
+ const Symbol('OG'),
+ const Symbol('OH'),
+ const Symbol('OI'),
+ const Symbol('OJ'),
+ const Symbol('OK'),
+ const Symbol('OL'),
+ const Symbol('OM'),
+ const Symbol('ON'),
+ const Symbol('OO'),
+ const Symbol('OP'),
+ const Symbol('OQ'),
+ const Symbol('OR'),
+ const Symbol('OS'),
+ const Symbol('OT'),
+ const Symbol('OU'),
+ const Symbol('OV'),
+ const Symbol('OW'),
+ const Symbol('OX'),
+ const Symbol('OY'),
+ const Symbol('OZ'),
+ const Symbol('Pa'),
+ const Symbol('Pb'),
+ const Symbol('Pc'),
+ const Symbol('Pd'),
+ const Symbol('Pe'),
+ const Symbol('Pf'),
+ const Symbol('Pg'),
+ const Symbol('Ph'),
+ const Symbol('Pi'),
+ const Symbol('Pj'),
+ const Symbol('Pk'),
+ const Symbol('Pl'),
+ const Symbol('Pm'),
+ const Symbol('Pn'),
+ const Symbol('Po'),
+ const Symbol('Pp'),
+ const Symbol('Pq'),
+ const Symbol('Pr'),
+ const Symbol('Ps'),
+ const Symbol('Pt'),
+ const Symbol('Pu'),
+ const Symbol('Pv'),
+ const Symbol('Pw'),
+ const Symbol('Px'),
+ const Symbol('Py'),
+ const Symbol('Pz'),
+ const Symbol('PA'),
+ const Symbol('PB'),
+ const Symbol('PC'),
+ const Symbol('PD'),
+ const Symbol('PE'),
+ const Symbol('PF'),
+ const Symbol('PG'),
+ const Symbol('PH'),
+ const Symbol('PI'),
+ const Symbol('PJ'),
+ const Symbol('PK'),
+ const Symbol('PL'),
+ const Symbol('PM'),
+ const Symbol('PN'),
+ const Symbol('PO'),
+ const Symbol('PP'),
+ const Symbol('PQ'),
+ const Symbol('PR'),
+ const Symbol('PS'),
+ const Symbol('PT'),
+ const Symbol('PU'),
+ const Symbol('PV'),
+ const Symbol('PW'),
+ const Symbol('PX'),
+ const Symbol('PY'),
+ const Symbol('PZ'),
+ const Symbol('Qa'),
+ const Symbol('Qb'),
+ const Symbol('Qc'),
+ const Symbol('Qd'),
+ const Symbol('Qe'),
+ const Symbol('Qf'),
+ const Symbol('Qg'),
+ const Symbol('Qh'),
+ const Symbol('Qi'),
+ const Symbol('Qj'),
+ const Symbol('Qk'),
+ const Symbol('Ql'),
+ const Symbol('Qm'),
+ const Symbol('Qn'),
+ const Symbol('Qo'),
+ const Symbol('Qp'),
+ const Symbol('Qq'),
+ const Symbol('Qr'),
+ const Symbol('Qs'),
+ const Symbol('Qt'),
+ const Symbol('Qu'),
+ const Symbol('Qv'),
+ const Symbol('Qw'),
+ const Symbol('Qx'),
+ const Symbol('Qy'),
+ const Symbol('Qz'),
+ const Symbol('QA'),
+ const Symbol('QB'),
+ const Symbol('QC'),
+ const Symbol('QD'),
+ const Symbol('QE'),
+ const Symbol('QF'),
+ const Symbol('QG'),
+ const Symbol('QH'),
+ const Symbol('QI'),
+ const Symbol('QJ'),
+ const Symbol('QK'),
+ const Symbol('QL'),
+ const Symbol('QM'),
+ const Symbol('QN'),
+ const Symbol('QO'),
+ const Symbol('QP'),
+ const Symbol('QQ'),
+ const Symbol('QR'),
+ const Symbol('QS'),
+ const Symbol('QT'),
+ const Symbol('QU'),
+ const Symbol('QV'),
+ const Symbol('QW'),
+ const Symbol('QX'),
+ const Symbol('QY'),
+ const Symbol('QZ'),
+ const Symbol('Ra'),
+ const Symbol('Rb'),
+ const Symbol('Rc'),
+ const Symbol('Rd'),
+ const Symbol('Re'),
+ const Symbol('Rf'),
+ const Symbol('Rg'),
+ const Symbol('Rh'),
+ const Symbol('Ri'),
+ const Symbol('Rj'),
+ const Symbol('Rk'),
+ const Symbol('Rl'),
+ const Symbol('Rm'),
+ const Symbol('Rn'),
+ const Symbol('Ro'),
+ const Symbol('Rp'),
+ const Symbol('Rq'),
+ const Symbol('Rr'),
+ const Symbol('Rs'),
+ const Symbol('Rt'),
+ const Symbol('Ru'),
+ const Symbol('Rv'),
+ const Symbol('Rw'),
+ const Symbol('Rx'),
+ const Symbol('Ry'),
+ const Symbol('Rz'),
+ const Symbol('RA'),
+ const Symbol('RB'),
+ const Symbol('RC'),
+ const Symbol('RD'),
+ const Symbol('RE'),
+ const Symbol('RF'),
+ const Symbol('RG'),
+ const Symbol('RH'),
+ const Symbol('RI'),
+ const Symbol('RJ'),
+ const Symbol('RK'),
+ const Symbol('RL'),
+ const Symbol('RM'),
+ const Symbol('RN'),
+ const Symbol('RO'),
+ const Symbol('RP'),
+ const Symbol('RQ'),
+ const Symbol('RR'),
+ const Symbol('RS'),
+ const Symbol('RT'),
+ const Symbol('RU'),
+ const Symbol('RV'),
+ const Symbol('RW'),
+ const Symbol('RX'),
+ const Symbol('RY'),
+ const Symbol('RZ'),
+ const Symbol('Sa'),
+ const Symbol('Sb'),
+ const Symbol('Sc'),
+ const Symbol('Sd'),
+ const Symbol('Se'),
+ const Symbol('Sf'),
+ const Symbol('Sg'),
+ const Symbol('Sh'),
+ const Symbol('Si'),
+ const Symbol('Sj'),
+ const Symbol('Sk'),
+ const Symbol('Sl'),
+ const Symbol('Sm'),
+ const Symbol('Sn'),
+ const Symbol('So'),
+ const Symbol('Sp'),
+ const Symbol('Sq'),
+ const Symbol('Sr'),
+ const Symbol('Ss'),
+ const Symbol('St'),
+ const Symbol('Su'),
+ const Symbol('Sv'),
+ const Symbol('Sw'),
+ const Symbol('Sx'),
+ const Symbol('Sy'),
+ const Symbol('Sz'),
+ const Symbol('SA'),
+ const Symbol('SB'),
+ const Symbol('SC'),
+ const Symbol('SD'),
+ const Symbol('SE'),
+ const Symbol('SF'),
+ const Symbol('SG'),
+ const Symbol('SH'),
+ const Symbol('SI'),
+ const Symbol('SJ'),
+ const Symbol('SK'),
+ const Symbol('SL'),
+ const Symbol('SM'),
+ const Symbol('SN'),
+ const Symbol('SO'),
+ const Symbol('SP'),
+ const Symbol('SQ'),
+ const Symbol('SR'),
+ const Symbol('SS'),
+ const Symbol('ST'),
+ const Symbol('SU'),
+ const Symbol('SV'),
+ const Symbol('SW'),
+ const Symbol('SX'),
+ const Symbol('SY'),
+ const Symbol('SZ'),
+ const Symbol('Ta'),
+ const Symbol('Tb'),
+ const Symbol('Tc'),
+ const Symbol('Td'),
+ const Symbol('Te'),
+ const Symbol('Tf'),
+ const Symbol('Tg'),
+ const Symbol('Th'),
+ const Symbol('Ti'),
+ const Symbol('Tj'),
+ const Symbol('Tk'),
+ const Symbol('Tl'),
+ const Symbol('Tm'),
+ const Symbol('Tn'),
+ const Symbol('To'),
+ const Symbol('Tp'),
+ const Symbol('Tq'),
+ const Symbol('Tr'),
+ const Symbol('Ts'),
+ const Symbol('Tt'),
+ const Symbol('Tu'),
+ const Symbol('Tv'),
+ const Symbol('Tw'),
+ const Symbol('Tx'),
+ const Symbol('Ty'),
+ const Symbol('Tz'),
+ const Symbol('TA'),
+ const Symbol('TB'),
+ const Symbol('TC'),
+ const Symbol('TD'),
+ const Symbol('TE'),
+ const Symbol('TF'),
+ const Symbol('TG'),
+ const Symbol('TH'),
+ const Symbol('TI'),
+ const Symbol('TJ'),
+ const Symbol('TK'),
+ const Symbol('TL'),
+ const Symbol('TM'),
+ const Symbol('TN'),
+ const Symbol('TO'),
+ const Symbol('TP'),
+ const Symbol('TQ'),
+ const Symbol('TR'),
+ const Symbol('TS'),
+ const Symbol('TT'),
+ const Symbol('TU'),
+ const Symbol('TV'),
+ const Symbol('TW'),
+ const Symbol('TX'),
+ const Symbol('TY'),
+ const Symbol('TZ'),
+ const Symbol('Ua'),
+ const Symbol('Ub'),
+ const Symbol('Uc'),
+ const Symbol('Ud'),
+ const Symbol('Ue'),
+ const Symbol('Uf'),
+ const Symbol('Ug'),
+ const Symbol('Uh'),
+ const Symbol('Ui'),
+ const Symbol('Uj'),
+ const Symbol('Uk'),
+ const Symbol('Ul'),
+ const Symbol('Um'),
+ const Symbol('Un'),
+ const Symbol('Uo'),
+ const Symbol('Up'),
+ const Symbol('Uq'),
+ const Symbol('Ur'),
+ const Symbol('Us'),
+ const Symbol('Ut'),
+ const Symbol('Uu'),
+ const Symbol('Uv'),
+ const Symbol('Uw'),
+ const Symbol('Ux'),
+ const Symbol('Uy'),
+ const Symbol('Uz'),
+ const Symbol('UA'),
+ const Symbol('UB'),
+ const Symbol('UC'),
+ const Symbol('UD'),
+ const Symbol('UE'),
+ const Symbol('UF'),
+ const Symbol('UG'),
+ const Symbol('UH'),
+ const Symbol('UI'),
+ const Symbol('UJ'),
+ const Symbol('UK'),
+ const Symbol('UL'),
+ const Symbol('UM'),
+ const Symbol('UN'),
+ const Symbol('UO'),
+ const Symbol('UP'),
+ const Symbol('UQ'),
+ const Symbol('UR'),
+ const Symbol('US'),
+ const Symbol('UT'),
+ const Symbol('UU'),
+ const Symbol('UV'),
+ const Symbol('UW'),
+ const Symbol('UX'),
+ const Symbol('UY'),
+ const Symbol('UZ'),
+ const Symbol('Va'),
+ const Symbol('Vb'),
+ const Symbol('Vc'),
+ const Symbol('Vd'),
+ const Symbol('Ve'),
+ const Symbol('Vf'),
+ const Symbol('Vg'),
+ const Symbol('Vh'),
+ const Symbol('Vi'),
+ const Symbol('Vj'),
+ const Symbol('Vk'),
+ const Symbol('Vl'),
+ const Symbol('Vm'),
+ const Symbol('Vn'),
+ const Symbol('Vo'),
+ const Symbol('Vp'),
+ const Symbol('Vq'),
+ const Symbol('Vr'),
+ const Symbol('Vs'),
+ const Symbol('Vt'),
+ const Symbol('Vu'),
+ const Symbol('Vv'),
+ const Symbol('Vw'),
+ const Symbol('Vx'),
+ const Symbol('Vy'),
+ const Symbol('Vz'),
+ const Symbol('VA'),
+ const Symbol('VB'),
+ const Symbol('VC'),
+ const Symbol('VD'),
+ const Symbol('VE'),
+ const Symbol('VF'),
+ const Symbol('VG'),
+ const Symbol('VH'),
+ const Symbol('VI'),
+ const Symbol('VJ'),
+ const Symbol('VK'),
+ const Symbol('VL'),
+ const Symbol('VM'),
+ const Symbol('VN'),
+ const Symbol('VO'),
+ const Symbol('VP'),
+ const Symbol('VQ'),
+ const Symbol('VR'),
+ const Symbol('VS'),
+ const Symbol('VT'),
+ const Symbol('VU'),
+ const Symbol('VV'),
+ const Symbol('VW'),
+ const Symbol('VX'),
+ const Symbol('VY'),
+ const Symbol('VZ'),
+ const Symbol('Wa'),
+ const Symbol('Wb'),
+ const Symbol('Wc'),
+ const Symbol('Wd'),
+ const Symbol('We'),
+ const Symbol('Wf'),
+ const Symbol('Wg'),
+ const Symbol('Wh'),
+ const Symbol('Wi'),
+ const Symbol('Wj'),
+ const Symbol('Wk'),
+ const Symbol('Wl'),
+ const Symbol('Wm'),
+ const Symbol('Wn'),
+ const Symbol('Wo'),
+ const Symbol('Wp'),
+ const Symbol('Wq'),
+ const Symbol('Wr'),
+ const Symbol('Ws'),
+ const Symbol('Wt'),
+ const Symbol('Wu'),
+ const Symbol('Wv'),
+ const Symbol('Ww'),
+ const Symbol('Wx'),
+ const Symbol('Wy'),
+ const Symbol('Wz'),
+ const Symbol('WA'),
+ const Symbol('WB'),
+ const Symbol('WC'),
+ const Symbol('WD'),
+ const Symbol('WE'),
+ const Symbol('WF'),
+ const Symbol('WG'),
+ const Symbol('WH'),
+ const Symbol('WI'),
+ const Symbol('WJ'),
+ const Symbol('WK'),
+ const Symbol('WL'),
+ const Symbol('WM'),
+ const Symbol('WN'),
+ const Symbol('WO'),
+ const Symbol('WP'),
+ const Symbol('WQ'),
+ const Symbol('WR'),
+ const Symbol('WS'),
+ const Symbol('WT'),
+ const Symbol('WU'),
+ const Symbol('WV'),
+ const Symbol('WW'),
+ const Symbol('WX'),
+ const Symbol('WY'),
+ const Symbol('WZ'),
+ const Symbol('Xa'),
+ const Symbol('Xb'),
+ const Symbol('Xc'),
+ const Symbol('Xd'),
+ const Symbol('Xe'),
+ const Symbol('Xf'),
+ const Symbol('Xg'),
+ const Symbol('Xh'),
+ const Symbol('Xi'),
+ const Symbol('Xj'),
+ const Symbol('Xk'),
+ const Symbol('Xl'),
+ const Symbol('Xm'),
+ const Symbol('Xn'),
+ const Symbol('Xo'),
+ const Symbol('Xp'),
+ const Symbol('Xq'),
+ const Symbol('Xr'),
+ const Symbol('Xs'),
+ const Symbol('Xt'),
+ const Symbol('Xu'),
+ const Symbol('Xv'),
+ const Symbol('Xw'),
+ const Symbol('Xx'),
+ const Symbol('Xy'),
+ const Symbol('Xz'),
+ const Symbol('XA'),
+ const Symbol('XB'),
+ const Symbol('XC'),
+ const Symbol('XD'),
+ const Symbol('XE'),
+ const Symbol('XF'),
+ const Symbol('XG'),
+ const Symbol('XH'),
+ const Symbol('XI'),
+ const Symbol('XJ'),
+ const Symbol('XK'),
+ const Symbol('XL'),
+ const Symbol('XM'),
+ const Symbol('XN'),
+ const Symbol('XO'),
+ const Symbol('XP'),
+ const Symbol('XQ'),
+ const Symbol('XR'),
+ const Symbol('XS'),
+ const Symbol('XT'),
+ const Symbol('XU'),
+ const Symbol('XV'),
+ const Symbol('XW'),
+ const Symbol('XX'),
+ const Symbol('XY'),
+ const Symbol('XZ'),
+ const Symbol('Ya'),
+ const Symbol('Yb'),
+ const Symbol('Yc'),
+ const Symbol('Yd'),
+ const Symbol('Ye'),
+ const Symbol('Yf'),
+ const Symbol('Yg'),
+ const Symbol('Yh'),
+ const Symbol('Yi'),
+ const Symbol('Yj'),
+ const Symbol('Yk'),
+ const Symbol('Yl'),
+ const Symbol('Ym'),
+ const Symbol('Yn'),
+ const Symbol('Yo'),
+ const Symbol('Yp'),
+ const Symbol('Yq'),
+ const Symbol('Yr'),
+ const Symbol('Ys'),
+ const Symbol('Yt'),
+ const Symbol('Yu'),
+ const Symbol('Yv'),
+ const Symbol('Yw'),
+ const Symbol('Yx'),
+ const Symbol('Yy'),
+ const Symbol('Yz'),
+ const Symbol('YA'),
+ const Symbol('YB'),
+ const Symbol('YC'),
+ const Symbol('YD'),
+ const Symbol('YE'),
+ const Symbol('YF'),
+ const Symbol('YG'),
+ const Symbol('YH'),
+ const Symbol('YI'),
+ const Symbol('YJ'),
+ const Symbol('YK'),
+ const Symbol('YL'),
+ const Symbol('YM'),
+ const Symbol('YN'),
+ const Symbol('YO'),
+ const Symbol('YP'),
+ const Symbol('YQ'),
+ const Symbol('YR'),
+ const Symbol('YS'),
+ const Symbol('YT'),
+ const Symbol('YU'),
+ const Symbol('YV'),
+ const Symbol('YW'),
+ const Symbol('YX'),
+ const Symbol('YY'),
+ const Symbol('YZ'),
+ const Symbol('Za'),
+ const Symbol('Zb'),
+ const Symbol('Zc'),
+ const Symbol('Zd'),
+ const Symbol('Ze'),
+ const Symbol('Zf'),
+ const Symbol('Zg'),
+ const Symbol('Zh'),
+ const Symbol('Zi'),
+ const Symbol('Zj'),
+ const Symbol('Zk'),
+ const Symbol('Zl'),
+ const Symbol('Zm'),
+ const Symbol('Zn'),
+ const Symbol('Zo'),
+ const Symbol('Zp'),
+ const Symbol('Zq'),
+ const Symbol('Zr'),
+ const Symbol('Zs'),
+ const Symbol('Zt'),
+ const Symbol('Zu'),
+ const Symbol('Zv'),
+ const Symbol('Zw'),
+ const Symbol('Zx'),
+ const Symbol('Zy'),
+ const Symbol('Zz'),
+ const Symbol('ZA'),
+ const Symbol('ZB'),
+ const Symbol('ZC'),
+ const Symbol('ZD'),
+ const Symbol('ZE'),
+ const Symbol('ZF'),
+ const Symbol('ZG'),
+ const Symbol('ZH'),
+ const Symbol('ZI'),
+ const Symbol('ZJ'),
+ const Symbol('ZK'),
+ const Symbol('ZL'),
+ const Symbol('ZM'),
+ const Symbol('ZN'),
+ const Symbol('ZO'),
+ const Symbol('ZP'),
+ const Symbol('ZQ'),
+ const Symbol('ZR'),
+ const Symbol('ZS'),
+ const Symbol('ZT'),
+ const Symbol('ZU'),
+ const Symbol('ZV'),
+ const Symbol('ZW'),
+ const Symbol('ZX'),
+ const Symbol('ZY'),
+ const Symbol('ZZ'),
+];
diff --git a/tests/language/symbol/literal_runtime_1_test.dart b/tests/language/symbol/literal_runtime_1_test.dart
new file mode 100644
index 0000000..e574d8c
--- /dev/null
+++ b/tests/language/symbol/literal_runtime_1_test.dart
@@ -0,0 +1,51 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test symbol literals.
+
+library symbol_literal_test;
+
+import 'package:expect/expect.dart';
+
+foo(a, b) => Expect.isTrue(identical(a, b));
+
+var check = foo; // Indirection used to avoid inlining.
+
+testSwitch(Symbol s) {
+ switch (s) {
+ case #abc:
+ return 1;
+ case const Symbol("def"):
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+main() {
+ bool doChecks = false;
+ doChecks = true;
+ if (doChecks) {
+ check(const Symbol("a"), #a);
+ check(const Symbol("a"), #a);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("=="), #==);
+ check(const Symbol("=="), #==);
+ check(const Symbol("a.toString"), #a.toString);
+ }
+
+ Expect.equals(1, testSwitch(#abc));
+
+ const m = const <Symbol, int>{#A: 0, #B: 1};
+ Expect.equals(1, m[#B]);
+
+ // Tries to call the symbol literal #a.toString
+
+}
diff --git a/tests/language/symbol/literal_runtime_test.dart b/tests/language/symbol/literal_runtime_test.dart
new file mode 100644
index 0000000..5bc7eed
--- /dev/null
+++ b/tests/language/symbol/literal_runtime_test.dart
@@ -0,0 +1,51 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test symbol literals.
+
+library symbol_literal_test;
+
+import 'package:expect/expect.dart';
+
+foo(a, b) => Expect.isTrue(identical(a, b));
+
+var check = foo; // Indirection used to avoid inlining.
+
+testSwitch(Symbol s) {
+ switch (s) {
+ case #abc:
+ return 1;
+ case const Symbol("def"):
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+main() {
+ bool doChecks = false;
+
+ if (doChecks) {
+ check(const Symbol("a"), #a);
+ check(const Symbol("a"), #a);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("=="), #==);
+ check(const Symbol("=="), #==);
+ check(const Symbol("a.toString"), #a.toString);
+ }
+
+ Expect.equals(1, testSwitch(#abc));
+
+ const m = const <Symbol, int>{#A: 0, #B: 1};
+ Expect.equals(1, m[#B]);
+
+ // Tries to call the symbol literal #a.toString
+
+}
diff --git a/tests/language/symbol/literal_test.dart b/tests/language/symbol/literal_test.dart
new file mode 100644
index 0000000..268b610
--- /dev/null
+++ b/tests/language/symbol/literal_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test symbol literals.
+
+library symbol_literal_test;
+
+import 'package:expect/expect.dart';
+
+foo(a, b) => Expect.isTrue(identical(a, b));
+
+var check = foo; // Indirection used to avoid inlining.
+
+testSwitch(Symbol s) {
+ switch (s) {
+ case #abc:
+ return 1;
+ case const Symbol("def"):
+ return 2;
+ default:
+ return 0;
+ }
+}
+
+main() {
+ bool doChecks = false;
+ doChecks = true;
+ if (doChecks) {
+ check(const Symbol("a"), #a);
+ check(const Symbol("a"), #a);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("ab"), #ab);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("a.b"), #a.b);
+ check(const Symbol("=="), #==);
+ check(const Symbol("=="), #==);
+ check(const Symbol("a.toString"), #a.toString);
+ }
+
+ Expect.equals(1, testSwitch(#abc));
+
+ const m = const <Symbol, int>{#A: 0, #B: 1};
+ Expect.equals(1, m[#B]);
+
+ // Tries to call the symbol literal #a.toString
+ Expect.throwsNoSuchMethodError(() => #a.toString());
+ // ^^^^^^^^^^^
+ // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION_EXPRESSION
+ // ^
+ // [cfe] The method 'call' isn't defined for the class 'Symbol'.
+}
diff --git a/tests/language/sync_star/covariant_type_test.dart b/tests/language/sync_star/covariant_type_test.dart
new file mode 100644
index 0000000..efae12a
--- /dev/null
+++ b/tests/language/sync_star/covariant_type_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that TypeErrors happen for sync* methods without creating iterator.
+
+import 'package:expect/expect.dart';
+
+class D<T> {
+ // Parametric covariance check is usually compiled into method.
+ Iterable<T> add(T n) sync* {
+ yield n;
+ }
+}
+
+main() {
+ D<num> d = new D<int>();
+ Expect.throwsTypeError(() => d.add(4.6));
+}
diff --git a/tests/language/sync_star/dcall_type_test.dart b/tests/language/sync_star/dcall_type_test.dart
new file mode 100644
index 0000000..5561419
--- /dev/null
+++ b/tests/language/sync_star/dcall_type_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that TypeErrors happen for sync* methods without creating iterator.
+
+import 'package:expect/expect.dart';
+
+Iterable<int> iota(int n) sync* {
+ for (int i = 0; i < n; i++) yield i;
+}
+
+class C {
+ Iterable<int> add(int n) sync* {
+ yield n;
+ }
+}
+
+main() {
+ dynamic f = iota;
+ Expect.throwsTypeError(() => f('ten'));
+ Expect.throwsTypeError(() => f(4.7));
+
+ dynamic o = new C();
+ Expect.throwsTypeError(() => o.add('ten'));
+ Expect.throwsTypeError(() => o.add(4.7));
+}
diff --git a/tests/language/sync_star/generator1_runtime_test.dart b/tests/language/sync_star/generator1_runtime_test.dart
new file mode 100644
index 0000000..728a800
--- /dev/null
+++ b/tests/language/sync_star/generator1_runtime_test.dart
@@ -0,0 +1,90 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Simple test program for sync* generator functions.
+
+// VMOptions=--optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+sum10() sync* {
+ var s = 0;
+ for (var k = 1; k <= 10; k++) {
+ s += k;
+ yield s;
+ }
+}
+
+class Range {
+ int start, end;
+ Range(this.start, this.end);
+ elements() sync* {
+ var e = start;
+ while (e <= end) yield e++;
+ }
+
+ get yield sync* {
+ // yield is a legal member name here.
+ var e = start;
+ while (e <= end) yield e++;
+ }
+}
+
+get sync sync* {
+ // sync is a legal identifier.
+ yield "sync";
+}
+
+einsZwei() sync* {
+ yield 1;
+ yield* [2, 3];
+ yield* [];
+ yield 5;
+ yield [6];
+}
+
+dreiVier() sync* {
+ // Throws type error: yielded object is not an iterable.
+
+}
+
+main() {
+ for (int i = 0; i < 10; i++) {
+ var sums = sum10();
+ print(sums);
+ Expect.isTrue(sums is Iterable);
+ Expect.equals(10, sums.length);
+ Expect.equals(1, sums.first);
+ Expect.equals(55, sums.last);
+ var q = "";
+ for (var n in sums.take(3)) {
+ q += "$n ";
+ }
+ Expect.equals("1 3 6 ", q);
+
+ var r = new Range(10, 12);
+ var elems1 = r.elements();
+ print(elems1);
+ var elems2 = r.yield;
+ print(elems2);
+ // Walk the elements of each iterable and compare them.
+ var i = elems1.iterator;
+ Expect.isTrue(i is Iterator);
+ elems2.forEach((e) {
+ Expect.isTrue(i.moveNext());
+ Expect.equals(e, i.current);
+ });
+
+ print(sync);
+ Expect.equals("sync", sync.single);
+
+ print(einsZwei());
+ Expect.equals("(1, 2, 3, 5, [6])", einsZwei().toString());
+
+
+ }
+}
diff --git a/tests/language/sync_star/generator1_test.dart b/tests/language/sync_star/generator1_test.dart
new file mode 100644
index 0000000..79b294d
--- /dev/null
+++ b/tests/language/sync_star/generator1_test.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Simple test program for sync* generator functions.
+
+// VMOptions=--optimization_counter_threshold=10
+
+import "package:expect/expect.dart";
+
+sum10() sync* {
+ var s = 0;
+ for (var k = 1; k <= 10; k++) {
+ s += k;
+ yield s;
+ }
+}
+
+class Range {
+ int start, end;
+ Range(this.start, this.end);
+ elements() sync* {
+ var e = start;
+ while (e <= end) yield e++;
+ }
+
+ get yield sync* {
+ // yield is a legal member name here.
+ var e = start;
+ while (e <= end) yield e++;
+ }
+}
+
+get sync sync* {
+ // sync is a legal identifier.
+ yield "sync";
+}
+
+einsZwei() sync* {
+ yield 1;
+ yield* [2, 3];
+ yield* [];
+ yield 5;
+ yield [6];
+}
+
+dreiVier() sync* {
+ // Throws type error: yielded object is not an iterable.
+ yield* 3;
+ // ^
+ // [analyzer] STATIC_TYPE_WARNING.YIELD_OF_INVALID_TYPE
+ // [cfe] A value of type 'int' can't be assigned to a variable of type 'Iterable<dynamic>'.
+}
+
+main() {
+ for (int i = 0; i < 10; i++) {
+ var sums = sum10();
+ print(sums);
+ Expect.isTrue(sums is Iterable);
+ Expect.equals(10, sums.length);
+ Expect.equals(1, sums.first);
+ Expect.equals(55, sums.last);
+ var q = "";
+ for (var n in sums.take(3)) {
+ q += "$n ";
+ }
+ Expect.equals("1 3 6 ", q);
+
+ var r = new Range(10, 12);
+ var elems1 = r.elements();
+ print(elems1);
+ var elems2 = r.yield;
+ print(elems2);
+ // Walk the elements of each iterable and compare them.
+ var i = elems1.iterator;
+ Expect.isTrue(i is Iterator);
+ elems2.forEach((e) {
+ Expect.isTrue(i.moveNext());
+ Expect.equals(e, i.current);
+ });
+
+ print(sync);
+ Expect.equals("sync", sync.single);
+
+ print(einsZwei());
+ Expect.equals("(1, 2, 3, 5, [6])", einsZwei().toString());
+
+ Expect.throws(() => dreiVier().toString());
+ }
+}
diff --git a/tests/language/sync_star/generator2_test.dart b/tests/language/sync_star/generator2_test.dart
new file mode 100644
index 0000000..feaee63
--- /dev/null
+++ b/tests/language/sync_star/generator2_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Simple test program for sync* generator functions.
+
+import "package:expect/expect.dart";
+import "dart:async";
+
+var sync = "topLevelSync";
+var async = "topLevelAync";
+var await = "topLevelAwait";
+var yield = "topLevelYield";
+
+test01() sync* {
+ var yield = 0; // //# 01: syntax error
+ var await = 0; // //# 02: syntax error
+ bool yield() => false; //# 04: syntax error
+ bool await() => false; //# 05: syntax error
+
+ var x1 = sync;
+ var x3 = await; // //# 08: syntax error
+ var x4 = await 55; // //# 09: compile-time error
+ var x4 = yield; // //# 10: syntax error
+
+ var stream = new Stream.fromIterable([1, 2, 3]);
+ await for (var e in stream) print(e); // //# 11: compile-time error
+}
+
+test02() sync* {
+ yield 12321;
+ return null; // //# 20: compile-time error
+}
+
+test03() sync* => null; // //# 30: syntax error
+
+get test04 sync* => null; // //# 40: syntax error
+set test04(a) sync* { print(a); } // //# 41: compile-time error
+
+class K {
+ K() sync* {} // //# 50: compile-time error
+ get nix sync* {}
+ get garnix sync* => null; // //# 51: syntax error
+ set etwas(var z) sync* { } // //# 52: compile-time error
+ sync() sync* {
+ yield sync; // Yields a tear-off of the sync() method.
+ }
+}
+
+main() {
+ var x;
+ x = test01();
+ Expect.equals("()", x.toString());
+ x = test02();
+ test03(); //# 30: continued
+ Expect.equals("(12321)", x.toString());
+ x = test04; // //# 40: continued
+ test04 = x; // //# 41: continued
+ x = new K();
+ print(x.garnix); //# 51: continued
+ x.etwas = null; //# 52: continued
+ print(x.sync().toList());
+ Expect.equals(1, x.sync().length);
+// Expect.isTrue(x.sync().single is Function);
+}
diff --git a/tests/language/sync_star/generator3_test.dart b/tests/language/sync_star/generator3_test.dart
new file mode 100644
index 0000000..d8646df
--- /dev/null
+++ b/tests/language/sync_star/generator3_test.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test program for sync* generator functions and yielding in try blocks.
+
+import "package:expect/expect.dart";
+
+f() sync* {
+ try {
+ yield 1;
+ throw "three";
+ } catch (e) {
+ yield 2;
+ yield e;
+ } finally {
+ yield 4;
+ }
+}
+
+test1() {
+ var s = f().toString();
+ Expect.equals("(1, 2, three, 4)", s);
+ print(s);
+}
+
+g() sync* {
+ try {
+ yield "a";
+ throw "pow!";
+ } finally {
+ yield "b";
+ }
+}
+
+test2() {
+ Iterator i = g().iterator;
+ Expect.isTrue(i.moveNext());
+ Expect.equals("a", i.current);
+ Expect.isTrue(i.moveNext());
+ Expect.equals("b", i.current);
+ Expect.throws(() => i.moveNext(), (error) => error == "pow!");
+}
+
+main() {
+ test1(); // //# test1: ok
+ test2(); // //# test2: ok
+}
diff --git a/tests/language/sync_star/less_than_test.dart b/tests/language/sync_star/less_than_test.dart
new file mode 100644
index 0000000..8dd197a
--- /dev/null
+++ b/tests/language/sync_star/less_than_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2015, the Dart Team. All rights reserved. Use of this
+// source code is governed by a BSD-style license that can be found in
+// the LICENSE file.
+
+import "package:expect/expect.dart";
+
+confuse(x) => [1, 'x', true, null, x].last;
+
+Iterable<int> foo() sync* {
+ var a = confuse(1);
+ if (a < 10) {
+ yield 2;
+ }
+}
+
+main() {
+ Expect.listEquals([2], foo().toList());
+}
diff --git a/tests/language/sync_star/yield_star_pause_test.dart b/tests/language/sync_star/yield_star_pause_test.dart
new file mode 100644
index 0000000..23fc133
--- /dev/null
+++ b/tests/language/sync_star/yield_star_pause_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+// Regression test for http://dartbug.com/27205
+// If a yield-star completes while the stream is paused, it didn't resume.
+
+main() {
+ asyncTest(() {
+ var c = new Completer();
+ var s = yieldStream(mkStream());
+ var sub;
+ sub = s.listen((v) {
+ sub.pause();
+ print(v);
+ Timer.run(sub.resume);
+ }, onDone: () {
+ print("DONE");
+ c.complete(null);
+ });
+ return c.future;
+ });
+}
+
+Stream yieldStream(Stream s) async* {
+ yield* s;
+}
+
+Stream mkStream() {
+ var s = new StreamController(sync: true);
+ // The close event has to be sent and received between
+ // the pause and resume above.
+ // Using a sync controller and a Timer.run(sub.resume) ensures this.
+ Timer.run(() {
+ s.add("event");
+ s.close();
+ });
+ return s.stream;
+}
diff --git a/tests/language/sync_star/yield_test.dart b/tests/language/sync_star/yield_test.dart
new file mode 100644
index 0000000..77e5594
--- /dev/null
+++ b/tests/language/sync_star/yield_test.dart
@@ -0,0 +1,106 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this is a copy of the language test of the same name,
+// we can remove this copy when we're running against those tests.
+import "package:expect/expect.dart";
+
+Iterable<int> foo1() sync* {
+ yield 1;
+}
+
+Iterable<int?> foo2(p) sync* {
+ bool t = false;
+ yield null;
+ while (true) {
+ a:
+ for (int i = 0; i < p; i++) {
+ if (!t) {
+ for (int j = 0; j < 3; j++) {
+ yield -1;
+ t = true;
+ break a;
+ }
+ }
+ yield i;
+ }
+ }
+}
+
+// p is copied to all Iterators from the Iterable returned by foo3.
+// Also each iterator will have its own i.
+Iterable<int> foo3(int p) sync* {
+ int i = 0;
+ i++;
+ p++;
+ yield p + i;
+}
+
+void testCapturingInSyncStar() {
+ int localL0 = 0;
+
+ nested1(int paramL1) sync* {
+ int localL1 = 0;
+ localL0 += 10;
+ paramL1 += 100;
+
+ nested2(int paramL2) sync* {
+ int localL2 = 0;
+ localL0 += 1000;
+ paramL1 += 10000;
+ localL1 += 100000;
+ paramL2 += 1000000;
+ localL2 += 10000000;
+
+ yield localL0 + paramL1 + localL1 + paramL2 + localL2;
+ }
+
+ yield nested2(0);
+ }
+
+ Iterable t1 = nested1(0);
+
+ Iterator it11 = t1.iterator;
+ Iterator it12 = t1.iterator;
+ it11.moveNext();
+ it12.moveNext();
+
+ Iterable t2 = it11.current;
+ Iterable t3 = it12.current;
+ Iterator it21 = t2.iterator;
+ Iterator it22 = t2.iterator;
+ Iterator it31 = t3.iterator;
+ Iterator it32 = t3.iterator;
+
+ it21.moveNext();
+ it22.moveNext();
+ it31.moveNext();
+ it32.moveNext();
+
+ Expect.equals(11111120, it21.current);
+ Expect.equals(11222120, it22.current);
+ Expect.equals(11113120, it31.current);
+ Expect.equals(11224120, it32.current);
+}
+
+main() {
+ Expect.listEquals([1], foo1().toList());
+ Expect.listEquals(
+ [null, -1, 0, 1, 2, 3, 0, 1, 2, 3], foo2(4).take(10).toList());
+ Iterable t = foo3(0);
+ Iterator it1 = t.iterator;
+ Iterator it2 = t.iterator; //# copyParameters: ok
+ it1.moveNext();
+ it2.moveNext(); //# copyParameters: continued
+ Expect.equals(2, it1.current);
+ // TODO(sigurdm): Check up on the spec here.
+ Expect.equals(2, it2.current); // //# copyParameters: continued
+ Expect.isFalse(it1.moveNext());
+ // Test that two `moveNext()` calls are fine.
+ Expect.isFalse(it1.moveNext());
+ Expect.isFalse(it2.moveNext()); //# copyParameters: continued
+ Expect.isFalse(it2.moveNext()); //# copyParameters: continued
+
+ testCapturingInSyncStar(); //# capturing: ok
+}
diff --git a/tests/language/sync_star/yieldstar_test.dart b/tests/language/sync_star/yieldstar_test.dart
new file mode 100644
index 0000000..82e7166
--- /dev/null
+++ b/tests/language/sync_star/yieldstar_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// TODO(jmesserly): this is a copy of the language test of the same name,
+// we can remove this copy when we're running against those tests.
+import "package:expect/expect.dart";
+
+bar() sync* {
+ int i = 1;
+ int j = 1;
+ while (true) {
+ yield i;
+ j = i + j;
+ i = j - i;
+ }
+}
+
+foo() sync* {
+ yield* [1, 2, 3];
+ yield null;
+ // TODO(jmesserly): added cast here to work around:
+ // https://codereview.chromium.org/1213503002/
+ yield* bar() as Iterable;
+}
+
+main() async {
+ Expect.listEquals([1, 2, 3, null, 1, 1, 2, 3, 5], foo().take(9).toList());
+}
diff --git a/tests/language/syntax/deep_nesting_expression_test.dart b/tests/language/syntax/deep_nesting_expression_test.dart
new file mode 100644
index 0000000..5ab1db5
--- /dev/null
+++ b/tests/language/syntax/deep_nesting_expression_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Deeply nested expression must not crash compiler due to stack overflow.
+
+main() {
+ var x =
+[
+[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] //# 01: ok, compile-time error
+];
+ print('okay');
+}
diff --git a/tests/language/syntax/deep_nesting_statement_test.dart b/tests/language/syntax/deep_nesting_statement_test.dart
new file mode 100644
index 0000000..bb00024
--- /dev/null
+++ b/tests/language/syntax/deep_nesting_statement_test.dart
@@ -0,0 +1,10013 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Deeply nested statements must not crash compiler due to stack overflow.
+
+var x = 0;
+
+main() {
+ if (x == 0) {
+ if (x == 0) { //# 01: ok, compile-time error
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ if (x == 0) { //# 01: continued
+ }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} //# 01: continued
+ }
+ print("survived!");
+}
diff --git a/tests/language/syntax/nested_comments_test.dart b/tests/language/syntax/nested_comments_test.dart
new file mode 100644
index 0000000..48d07ba
--- /dev/null
+++ b/tests/language/syntax/nested_comments_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing nested comments
+
+import "package:expect/expect.dart";
+
+// /* nested comment */
+/*// nested comment */
+/*/* nested comment */*/
+/* entire function
+void main() {
+ /* nested comment */
+ Expect.isTrue(false); // nested
+}
+*/
+
+/**
+ test documentation
+ /* nested comment */
+*/
+main() {
+ Expect.isTrue(true);
+}
diff --git a/tests/language/syntax/statement_test.dart b/tests/language/syntax/statement_test.dart
new file mode 100644
index 0000000..f1b8a46
--- /dev/null
+++ b/tests/language/syntax/statement_test.dart
@@ -0,0 +1,223 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Tests all statement types. Not an exhaustive test of all statement semantics.
+class StatementTest {
+ StatementTest() {}
+
+ static testMain() {
+ var test = new StatementTest();
+ test.testIfStatement();
+ test.testForLoop();
+ test.testWhileLoops();
+ test.testSwitch();
+ test.testExceptions();
+ test.testBreak();
+ test.testContinue();
+ test.testFunction();
+ test.testReturn();
+ }
+
+ testIfStatement() {
+ // Basic if statements.
+ if (true) {
+ Expect.equals(true, true);
+ } else {
+ Expect.equals(false, true);
+ }
+
+ if (false) {
+ Expect.equals(false, true);
+ } else {
+ Expect.equals(true, true);
+ }
+ }
+
+ testForLoop() {
+ int count = 0, count2;
+
+ // Basic for loop.
+ for (int i = 0; i < 10; ++i) {
+ ++count;
+ }
+ Expect.equals(10, count);
+
+ // For loop with no 'var'.
+ count2 = 0;
+ for (count = 0; count < 5; ++count) {
+ ++count2;
+ }
+ Expect.equals(5, count);
+ Expect.equals(5, count2);
+
+ // For loop with no initializer.
+ count = count2 = 0;
+ for (; count < 10; ++count) {
+ ++count2;
+ }
+ Expect.equals(10, count);
+ Expect.equals(10, count2);
+
+ // For loop with no increment.
+ for (count = 0; count < 5;) {
+ ++count;
+ }
+ Expect.equals(5, count);
+
+ // For loop with no test.
+ for (count = 0;; ++count) {
+ if (count == 10) {
+ break;
+ }
+ }
+ Expect.equals(10, count);
+
+ // For loop with no nothing.
+ count = 0;
+ for (;;) {
+ if (count == 5) {
+ break;
+ }
+ ++count;
+ }
+ Expect.equals(5, count);
+ }
+
+ testWhileLoops() {
+ // Basic while loop.
+ int count = 0;
+ while (count < 10) {
+ ++count;
+ }
+ Expect.equals(10, count);
+
+ // Basic do loop.
+ count = 0;
+ do {
+ ++count;
+ } while (count < 5);
+ Expect.equals(5, count);
+ }
+
+ testSwitch() {
+ // Int switch.
+ bool? hit0, hit1, hitDefault;
+ for (int x = 0; x < 3; ++x) {
+ switch (x) {
+ case 0:
+ hit0 = true;
+ break;
+ case 1:
+ hit1 = true;
+ break;
+ default:
+ hitDefault = true;
+ break;
+ }
+ }
+ Expect.equals(true, hit0);
+ Expect.equals(true, hit1);
+ Expect.equals(true, hitDefault);
+
+ // String switch.
+ var strings = ['a', 'b', 'c'];
+ bool? hitA, hitB;
+ hitDefault = false;
+ for (int x = 0; x < 3; ++x) {
+ switch (strings[x]) {
+ case 'a':
+ hitA = true;
+ break;
+ case 'b':
+ hitB = true;
+ break;
+ default:
+ hitDefault = true;
+ break;
+ }
+ }
+ Expect.equals(true, hitA);
+ Expect.equals(true, hitB);
+ Expect.equals(true, hitDefault);
+ }
+
+ testExceptions() {
+ // TODO(jgw): Better tests once all the exception semantics are worked out.
+ bool hitCatch, hitFinally;
+ try {
+ throw "foo";
+ } catch (e) {
+ Expect.equals(true, e == "foo");
+ hitCatch = true;
+ } finally {
+ hitFinally = true;
+ }
+
+ Expect.equals(true, hitCatch);
+ Expect.equals(true, hitFinally);
+ }
+
+ testBreak() {
+ var ints = [
+ [32, 87, 3, 589],
+ [12, 1076, 2000, 8],
+ [622, 127, 77, 955]
+ ];
+ int i, j = 0;
+ bool foundIt = false;
+
+ search:
+ for (i = 0; i < ints.length; i++) {
+ for (j = 0; j < ints[i].length; j++) {
+ if (ints[i][j] == 12) {
+ foundIt = true;
+ break search;
+ }
+ }
+ }
+ Expect.equals(true, foundIt);
+ }
+
+ testContinue() {
+ String searchMe = "Look for a substring in me";
+ String substring = "sub";
+ bool foundIt = false;
+ int max = searchMe.length - substring.length;
+
+ test:
+ for (int i = 0; i <= max; i++) {
+ int n = substring.length;
+ int j = i;
+ int k = 0;
+ while (n-- != 0) {
+ if (searchMe[j++] != substring[k++]) {
+ continue test;
+ }
+ }
+ foundIt = true;
+ break test;
+ }
+ }
+
+ testFunction() {
+ int foo() {
+ return 42;
+ }
+
+ Expect.equals(42, foo());
+ }
+
+ void testReturn() {
+ if (true) {
+ return;
+ }
+ Expect.equals(true, false);
+ }
+}
+
+main() {
+ StatementTest.testMain();
+}
diff --git a/tests/language/syntax/syntax_test.dart b/tests/language/syntax/syntax_test.dart
new file mode 100644
index 0000000..c0f977a
--- /dev/null
+++ b/tests/language/syntax/syntax_test.dart
@@ -0,0 +1,255 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class SyntaxTest {
+ // "this" cannot be used as a field name.
+ SyntaxTest this; //# 01: syntax error
+
+ // Syntax error.
+ foo {} //# 02: syntax error
+
+ // Syntax error.
+ static foo {} //# 03: syntax error
+
+ // Syntax error.
+ operator +=() {} //# 04: syntax error
+
+ // Syntax error.
+ operator -=() {} //# 05: syntax error
+
+ // Syntax error.
+ operator *=() {} //# 06: syntax error
+
+ // Syntax error.
+ operator /=() {} //# 07: syntax error
+
+ // Syntax error.
+ operator ~/=() {} //# 08: syntax error
+
+ // Syntax error.
+ operator %=() {} //# 09: syntax error
+
+ // Syntax error.
+ operator <<=() {} //# 10: syntax error
+
+ // Syntax error.
+ operator >>=() {} //# 11: syntax error
+
+ // Syntax error.
+ operator >>>=() {} //# 12: syntax error
+
+ // Syntax error.
+ operator &=() {} //# 13: syntax error
+
+ // Syntax error.
+ operator ^=() {} //# 14: syntax error
+
+ // Syntax error.
+ operator |=() {} //# 15: syntax error
+
+ // Syntax error.
+ operator ?() {} //# 16: syntax error
+
+ // Syntax error.
+ operator ||() {} //# 17: syntax error
+
+ // Syntax error.
+ operator &&() {} //# 18: syntax error
+
+ // Syntax error.
+ operator !=() {} //# 19: syntax error
+
+ // Syntax error.
+ operator ===() {} //# 20: syntax error
+
+ // Syntax error.
+ operator !==() {} //# 21: syntax error
+
+ // Syntax error.
+ operator is() {} //# 22: syntax error
+
+ // Syntax error.
+ operator !() {} //# 23: syntax error
+
+ // Syntax error.
+ operator ++() {} //# 24: syntax error
+
+ // Syntax error.
+ operator --() {} //# 25: syntax error
+
+ // Syntax error.
+ bool operator ===(A other) { return true; } //# 26: syntax error
+
+ int sample = -1;
+}
+
+fisk {} //# 27: syntax error
+
+class DOMWindow {}
+
+class Window extends DOMWindow
+native "*Window" //# 28: syntax error
+{}
+
+class Console
+native "=(typeof console == 'undefined' ? {} : console)" //# 29: syntax error
+{}
+
+class NativeClass
+native "FooBar" //# 30: syntax error
+{}
+
+abstract class Fisk {}
+
+class BoolImplementation implements Fisk
+native "Boolean" //# 31: syntax error
+{}
+
+class _JSON
+native 'JSON' //# 32: syntax error
+{}
+
+class ListFactory<E> implements List<E>
+native "Array" //# 33: syntax error
+{
+ noSuchMethod(_) => null; // Allow unimplemented methods
+}
+
+abstract class I implements UNKNOWN; //# 34: syntax error
+
+class XWindow extends DOMWindow
+hest "*Window" //# 35: syntax error
+{}
+
+class XConsole
+hest "=(typeof console == 'undefined' ? {} : console)" //# 36: syntax error
+{}
+
+class XNativeClass
+hest "FooBar" //# 37: syntax error
+{}
+
+class XBoolImplementation implements Fisk
+hest "Boolean" //# 38: syntax error
+{}
+
+class _JSONX
+hest 'JSON' //# 39: syntax error
+{}
+
+class XListFactory<E> implements List<E>
+hest "Array" //# 40: syntax error
+{
+ noSuchMethod(_) => null; // Allow unimplemented methods
+}
+
+class YWindow extends DOMWindow
+for "*Window" //# 41: syntax error
+{}
+
+class YConsole
+for "=(typeof console == 'undefined' ? {} : console)" //# 42: syntax error
+{}
+
+class YNativeClass
+for "FooBar" //# 43: syntax error
+{}
+
+class YBoolImplementation implements Fisk
+for "Boolean" //# 44: syntax error
+{}
+
+class _JSONY
+for 'JSON' //# 45: syntax error
+{}
+
+class YListFactory<E> implements List<E>
+for "Array" //# 46: syntax error
+{
+ noSuchMethod(_) => null; // Allow unimplemented methods
+}
+
+class A {
+ const A()
+ {} //# 47: syntax error
+ ;
+}
+
+abstract class G<T> {}
+
+typedef <T>(); //# 48: syntax error
+
+class B
+extends void //# 49: syntax error
+{}
+
+main() {
+ try {
+ new SyntaxTest();
+ new SyntaxTest().foo(); //# 02: continued
+ SyntaxTest.foo(); //# 03: continued
+ fisk(); //# 27: continued
+
+ new Window();
+ new Console();
+ new NativeClass();
+ new BoolImplementation();
+ new _JSON();
+ new ListFactory();
+ new ListFactory<Object>();
+ var x = null;
+ x is I; //# 34: continued
+
+ new XConsole();
+ new XNativeClass();
+ new XBoolImplementation();
+ new _JSONX();
+ new XListFactory();
+ new XListFactory<Object>();
+
+ new YConsole();
+ new YNativeClass();
+ new YBoolImplementation();
+ new _JSONY();
+ new YListFactory();
+ new YListFactory<Object>();
+
+ futureOf(x) {}
+ if (!(fisk futureOf(false))) {} //# 50: syntax error
+ if (!(await futureOf(false))) {} //# 51: compile-time error
+
+ void f{} //# 52: syntax error
+ G<int double> g; //# 53: syntax error
+ f(void) {}; //# 54: syntax error
+
+ optionalArg([x]) {}
+ optionalArg(
+ void (var i) {} //# 55: syntax error
+ );
+
+ function __PROTO__$(...args) { return 12; } //# 56: syntax error
+ G<> t; //# 57: syntax error
+ G<null> t; //# 58: syntax error
+ A<void> a = null; //# 59: compile-time error
+ void v; //# 60: ok
+ void v = null; //# 61: ok
+ print(null is void); //# 62: syntax error
+ new A();
+ new B();
+
+ new Bad();
+
+ 1 + 2 = 1; //# 63: syntax error
+ new SyntaxTest() = 1; //# 64: syntax error
+ futureOf(null) = 1; //# 65: syntax error
+
+ } catch (ex) {
+ // Swallowing exceptions. Any error should be a compile-time error
+ // which kills the current isolate.
+ }
+}
+
+class Bad {
+ factory Bad<Bad(String type) { return null; } //# 63: syntax error
+}
diff --git a/tests/language/syntax/unbalanced_brace_test.dart b/tests/language/syntax/unbalanced_brace_test.dart
new file mode 100644
index 0000000..5e889ccc
--- /dev/null
+++ b/tests/language/syntax/unbalanced_brace_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test syntax errors related to unterminated braces.
+
+class A {
+ m() {
+ /* //# 01: syntax error
+ }
+ // */
+
+/* //# 02: syntax error
+}
+// */
+
+class B {}
+
+main() {
+ new A();
+ new B();
+}
diff --git a/tests/language/this/as_covariant_call_checks_test.dart b/tests/language/this/as_covariant_call_checks_test.dart
new file mode 100644
index 0000000..635b9ae
--- /dev/null
+++ b/tests/language/this/as_covariant_call_checks_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--no-background-compilation --optimization-counter-threshold=10
+
+import "package:expect/expect.dart";
+
+class A<T> {
+ late T field;
+
+ @pragma('vm:never-inline')
+ set property(T v) {}
+
+ @pragma('vm:never-inline')
+ void method(T x) {}
+
+ @pragma('vm:never-inline')
+ void testMethod(bool violateType) {
+ A<dynamic> x = this;
+ x.method(violateType ? 10 : "10");
+ }
+
+ @pragma('vm:never-inline')
+ void testSetter(bool violateType) {
+ A<dynamic> x = this;
+ x.property = violateType ? 10 : "10";
+ }
+
+ @pragma('vm:never-inline')
+ void testField(bool violateType) {
+ A<dynamic> x = this;
+ x.field = violateType ? 10 : "10";
+ }
+}
+
+@pragma('vm:never-inline')
+void loop(A<String> obj, bool violateType) {
+ for (var i = 0; i < 100; i++) {
+ obj.testMethod(violateType);
+ obj.testSetter(violateType);
+ obj.testField(violateType);
+ }
+}
+
+void main() {
+ A<num>().field = 10;
+ final obj = A<String>();
+ loop(obj, false);
+ loop(obj, false);
+ Expect.throwsTypeError(() => obj.testMethod(true));
+ Expect.throwsTypeError(() => obj.testSetter(true));
+ Expect.throwsTypeError(() => obj.testField(true));
+}
diff --git a/tests/language/this/as_dynamic_call_checks_test.dart b/tests/language/this/as_dynamic_call_checks_test.dart
new file mode 100644
index 0000000..829a327
--- /dev/null
+++ b/tests/language/this/as_dynamic_call_checks_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// VMOptions=--no-background-compilation --optimization-counter-threshold=10
+
+import "package:expect/expect.dart";
+
+class A<T> {
+ late T field;
+
+ @pragma('vm:never-inline')
+ set property(T v) {}
+
+ @pragma('vm:never-inline')
+ void method(T x) {}
+
+ @pragma('vm:never-inline')
+ void testMethod({bool violateType: false}) {
+ dynamic x = this;
+ x.method(violateType ? 10 : "10");
+ }
+
+ @pragma('vm:never-inline')
+ void testSetter({bool violateType: false}) {
+ dynamic x = this;
+ x.property = violateType ? 10 : "10";
+ }
+
+ @pragma('vm:never-inline')
+ void testField({bool violateType: false}) {
+ dynamic x = this;
+ x.field = violateType ? 10 : "10";
+ }
+}
+
+@pragma('vm:never-inline')
+void loop(A<String> obj, {bool violateType: false}) {
+ for (var i = 0; i < 100; i++) {
+ obj.testMethod(violateType: violateType);
+ obj.testSetter(violateType: violateType);
+ obj.testField(violateType: violateType);
+ }
+}
+
+void main() {
+ final obj = A<String>();
+ loop(obj, violateType: false);
+ loop(obj, violateType: false);
+ Expect.throwsTypeError(() => obj.testMethod(violateType: true));
+ Expect.throwsTypeError(() => obj.testSetter(violateType: true));
+ Expect.throwsTypeError(() => obj.testField(violateType: true));
+}
diff --git a/tests/language/this/call_this_test.dart b/tests/language/this/call_this_test.dart
new file mode 100644
index 0000000..55e7ccd
--- /dev/null
+++ b/tests/language/this/call_this_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that dart2js treats [:this():] as a closure send.
+
+import "package:expect/expect.dart";
+
+class A {
+ call() => 42;
+ test1() => this();
+ test2() => (this)();
+}
+
+main() {
+ Expect.equals(42, (new A()).test1());
+ Expect.equals(42, (new A()).test2());
+}
diff --git a/tests/language/this/conditional_operator_runtime_test.dart b/tests/language/this/conditional_operator_runtime_test.dart
new file mode 100644
index 0000000..eb56244
--- /dev/null
+++ b/tests/language/this/conditional_operator_runtime_test.dart
@@ -0,0 +1,31 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the ?. operator cannot be used for forwarding "this"
+// constructors.
+
+class B {
+ B();
+ B.namedConstructor();
+ var field = 1;
+ method() => 1;
+
+ B.forward()
+
+ ;
+
+ test() {
+ this?.field = 1;
+ this?.field += 1;
+ this?.field;
+ this?.method();
+ }
+}
+
+main() {
+ new B.forward().test();
+}
diff --git a/tests/language/this/conditional_operator_test.dart b/tests/language/this/conditional_operator_test.dart
new file mode 100644
index 0000000..85060a5
--- /dev/null
+++ b/tests/language/this/conditional_operator_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Verify that the ?. operator cannot be used for forwarding "this"
+// constructors.
+
+class B {
+ B();
+ B.namedConstructor();
+ var field = 1;
+ method() => 1;
+
+ B.forward()
+ : this?.namedConstructor()
+ //^^^^
+ // [analyzer] COMPILE_TIME_ERROR.INVALID_REFERENCE_TO_THIS
+ // [cfe] Expected an assignment after the field name.
+ //^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_ASSIGNMENT_IN_INITIALIZER
+ //^^^^^^^^^^^^^^^^^^^^^^^^
+ // [analyzer] COMPILE_TIME_ERROR.INITIALIZER_FOR_NON_EXISTENT_FIELD
+ // [error line 15, column 11, length 0]
+ // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
+ // [cfe] Expected '.' before this.
+ // ^^
+ // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+ // [cfe] Expected an identifier, but got ''.
+ ;
+
+ test() {
+ this?.field = 1;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ this?.field += 1;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ this?.field;
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ this?.method();
+ // ^^
+ // [analyzer] STATIC_WARNING.INVALID_NULL_AWARE_OPERATOR
+ }
+}
+
+main() {
+ new B.forward().test();
+}
diff --git a/tests/language/this/implicit_runtime_test.dart b/tests/language/this/implicit_runtime_test.dart
new file mode 100644
index 0000000..34022fd
--- /dev/null
+++ b/tests/language/this/implicit_runtime_test.dart
@@ -0,0 +1,46 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+abstract class Interface {
+ final x;
+ Interface(this.x);
+}
+
+abstract class Abstract implements Interface {
+ String toString() => x.toString();
+}
+
+// This class does not implement "x" either, but it is not marked
+// abstract.
+
+
+// This class does not implement "x", but is itself abstract, so that's OK.
+abstract class SubAbstract2 extends Abstract {
+ get x; // Abstract.
+}
+
+// This class does not implement "x" either, but it is not marked
+// abstract.
+
+
+class Concrete extends Abstract {
+ get x => 7;
+}
+
+class SubConcrete extends Concrete {
+ final x;
+ SubConcrete(this.x);
+}
+
+void main() {
+
+ Expect.equals('7', new Concrete().toString());
+ Expect.equals('42', new SubConcrete(42).toString());
+ Expect.equals('7', new SubConcrete(new Concrete()).toString());
+}
diff --git a/tests/language/this/implicit_this_test.dart b/tests/language/this/implicit_this_test.dart
new file mode 100644
index 0000000..3500c9a
--- /dev/null
+++ b/tests/language/this/implicit_this_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+abstract class Interface {
+ final x;
+ Interface(this.x);
+}
+
+abstract class Abstract implements Interface {
+ String toString() => x.toString();
+}
+
+// This class does not implement "x" either, but it is not marked
+// abstract.
+class SubAbstract1 extends Abstract {}
+// ^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER
+// [cfe] The non-abstract class 'SubAbstract1' is missing implementations for these members:
+
+// This class does not implement "x", but is itself abstract, so that's OK.
+abstract class SubAbstract2 extends Abstract {
+ get x; // Abstract.
+}
+
+// This class does not implement "x" either, but it is not marked
+// abstract.
+class SubSubAbstract2 extends SubAbstract2 {}
+// ^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER
+// [cfe] The non-abstract class 'SubSubAbstract2' is missing implementations for these members:
+
+class Concrete extends Abstract {
+ get x => 7;
+}
+
+class SubConcrete extends Concrete {
+ final x;
+ SubConcrete(this.x);
+}
+
+void main() {
+ new Abstract();
+ // ^^^^^^^^
+ // [analyzer] STATIC_WARNING.INSTANTIATE_ABSTRACT_CLASS
+ // [cfe] The class 'Abstract' is abstract and can't be instantiated.
+ Expect.equals('7', new Concrete().toString());
+ Expect.equals('42', new SubConcrete(42).toString());
+ Expect.equals('7', new SubConcrete(new Concrete()).toString());
+}
diff --git a/tests/language/this/in_initializer_test.dart b/tests/language/this/in_initializer_test.dart
new file mode 100644
index 0000000..554c15c
--- /dev/null
+++ b/tests/language/this/in_initializer_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ static String? s = "something";
+ var a = "anything";
+ var x;
+
+ foo() => null;
+ bar(var y) => y;
+ static sfoo() => null;
+ static sbar(var y) => y;
+
+ A.next();
+
+ A(); //# 00: ok
+ A() : this.next(); //# 01: ok
+
+ A() : x = s; //# 02: ok
+ A() : x = sfoo(); //# 03: ok
+ A() : x = sbar(null); //# 04: ok
+ A() : x = a; //# 05: compile-time error
+ A() : x = foo(); //# 06: compile-time error
+ A() : x = bar(null); //# 07: compile-time error
+ A() : x = bar(this); //# 08: compile-time error
+ A() : x = this; //# 09: compile-time error
+ A() : x = this.a; //# 10: compile-time error
+ A() : x = this.foo(); //# 11: compile-time error
+ A() : x = this.bar(null); //# 12: compile-time error
+ A() : x = this.bar(this); //# 13: compile-time error
+ A() : x = sbar(this); //# 14: compile-time error
+ A() : x = sbar(this.a); //# 15: compile-time error
+ A() : x = sbar(this.foo()); //# 16: compile-time error
+ A() : x = sbar(this.bar(null)); //# 17: compile-time error
+ A() : x = sbar(this.bar(this)); //# 18: compile-time error
+
+ A() : this.x = (() => null); //# 19: ok
+ A() : this.x = (() => s)(); //# 20: ok
+ A() : this.x = ((c) => c); //# 21: ok
+ A() : this.x = ((c) => s)(null); //# 22: ok
+ A() : this.x = ((c) => c)(this); //# 23: compile-time error
+ A() : this.x = (() => this); //# 24: compile-time error
+ A() : this.x = (() => this.a)(); //# 25: compile-time error
+ A() : this.x = ((c) => this.foo()); //# 26: compile-time error
+ A() : this.x = ((c) => a)(null); //# 27: compile-time error
+ A() : this.x = ((c) => foo())(s); //# 28: compile-time error
+ A() : this.x = sbar((() { return null; })); //# 29: ok
+ A() : this.x = sbar((() { return s; })()); //# 30: ok
+ A() : this.x = sbar(((c) { return c; })); //# 31: ok
+ A() : this.x = sbar(((c) { return s; })(null)); //# 32: ok
+ A() : this.x = sbar(((c) { return c; })(this)); //# 33: compile-time error
+ A() : this.x = sbar((() { return this; })); //# 34: compile-time error
+ A() : this.x = sbar((() { return this.a; })()); //# 35: compile-time error
+ A() : this.x = sbar(((c) { return this.foo(); })); //# 36: compile-time error
+ A() : this.x = sbar(((c) { return a; })(null)); //# 37: compile-time error
+ A() : this.x = sbar(((c) { return foo(); })(s)); //# 38: compile-time error
+
+ A() : this.x = (s = null); //# 39: ok
+ A() : this.x = (a = null); //# 40: compile-time error
+ A() : this.x = (this.a = null); //# 41: compile-time error
+}
+
+main() {}
diff --git a/tests/language/this/runtime_test.dart b/tests/language/this/runtime_test.dart
new file mode 100644
index 0000000..c81a1b2
--- /dev/null
+++ b/tests/language/this/runtime_test.dart
@@ -0,0 +1,26 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ var x;
+ f() {}
+
+ testMe() {
+
+
+
+
+
+
+
+
+ }
+}
+
+main() {
+ new Foo().testMe();
+}
diff --git a/tests/language/this/this_test.dart b/tests/language/this/this_test.dart
new file mode 100644
index 0000000..8d29f8a
--- /dev/null
+++ b/tests/language/this/this_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo {
+ var x;
+ f() {}
+
+ testMe() {
+ x.this;
+ //^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ x.this();
+ //^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ x.this.x;
+ //^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ x.this().x;
+ //^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ f().this;
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ f().this();
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ f().this.f();
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ f().this().f();
+ // ^^^^
+ // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+ // [cfe] Expected identifier, but got 'this'.
+ }
+}
+
+main() {
+ new Foo().testMe();
+}
diff --git a/tests/language/top_level/collision1_test.dart b/tests/language/top_level/collision1_test.dart
new file mode 100644
index 0000000..f8d97c4b
--- /dev/null
+++ b/tests/language/top_level/collision1_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+int x = 100;
+
+get x => 200; // //# 00: compile-time error
+set x(var i) { print(i); } // //# 01: compile-time error
+
+int x(a, b) { print(a + b); } // //# 02: compile-time error
+
+void main() {
+ // No need to reference x.
+}
diff --git a/tests/language/top_level/collision2_test.dart b/tests/language/top_level/collision2_test.dart
new file mode 100644
index 0000000..0d9734e
--- /dev/null
+++ b/tests/language/top_level/collision2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+get x => 200;
+
+// Ok: can have a setter named x when getter x is defined.
+set x(var i) {
+ print(i);
+}
+
+// Error: there is already a getter for x
+int x; // //# 00: compile-time error
+
+// Error: there is already a getter named x.
+int x(a, b) { print(a + b); } // //# 01: compile-time error
+
+void main() {
+ // No need to reference x.
+}
diff --git a/tests/language/top_level/file1.dart b/tests/language/top_level/file1.dart
new file mode 100644
index 0000000..e0f5d98
--- /dev/null
+++ b/tests/language/top_level/file1.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of TopLevelMultipleFilesTest.dart;
+
+main() {
+ Expect.equals(topLevelVar, 42);
+ Expect.equals(topLevelMethod(), 87);
+}
diff --git a/tests/language/top_level/file2.dart b/tests/language/top_level/file2.dart
new file mode 100644
index 0000000..19ca8ca
--- /dev/null
+++ b/tests/language/top_level/file2.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of TopLevelMultipleFilesTest.dart;
+
+const topLevelVar = 42;
+
+topLevelMethod() => 87;
diff --git a/tests/language/top_level/file3.dart b/tests/language/top_level/file3.dart
new file mode 100644
index 0000000..a42c558
--- /dev/null
+++ b/tests/language/top_level/file3.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ Expect.equals(42, prefix.topLevelVar);
+}
diff --git a/tests/language/top_level/func_test.dart b/tests/language/top_level/func_test.dart
new file mode 100644
index 0000000..db9d859
--- /dev/null
+++ b/tests/language/top_level/func_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing top-level variables.
+
+import "package:expect/expect.dart";
+
+class TopLevelFuncTest {
+ static testMain() {
+ var z = [1, 10, 100, 1000];
+ Expect.equals(Sum(z), 1111);
+
+ var w = Window;
+ Expect.equals(w, "window");
+
+ Expect.equals(null, rgb);
+ Color = "ff0000";
+ Expect.equals(rgb, "#ff0000");
+ CheckColor("#ff0000");
+
+ Expect.equals("5", digits[5]);
+
+ var e1 = Enumerator;
+ var e2 = Enumerator;
+ Expect.equals(0, e1());
+ Expect.equals(1, e1());
+ Expect.equals(2, e1());
+ Expect.equals(0, e2());
+ }
+}
+
+void CheckColor(String expected) {
+ Expect.equals(expected, rgb);
+}
+
+int Sum(List<int> v) {
+ int s = 0;
+ for (int i = 0; i < v.length; i++) {
+ s += v[i];
+ }
+ return s;
+}
+
+get Window {
+ return "win" "dow";
+}
+
+String? rgb;
+
+void set Color(col) {
+ rgb = "#$col";
+}
+
+List<String> get digits {
+ return ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
+}
+
+Function get Enumerator {
+ int k = 0;
+ return () => k++;
+}
+
+main() {
+ TopLevelFuncTest.testMain();
+}
diff --git a/tests/language/top_level/getter_arrow_syntax_test.dart b/tests/language/top_level/getter_arrow_syntax_test.dart
new file mode 100644
index 0000000..77309dd
--- /dev/null
+++ b/tests/language/top_level/getter_arrow_syntax_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+get getter => 42;
+
+List<int>? get lgetter => null;
+
+bool get two_wrongs {
+ return !true;
+}
+
+main() {
+ Expect.equals(42, getter);
+ Expect.equals(null, lgetter);
+ Expect.equals(false, two_wrongs);
+}
diff --git a/tests/language/top_level/getter_no_setter1_test.dart b/tests/language/top_level/getter_no_setter1_test.dart
new file mode 100644
index 0000000..a8b0fa2
--- /dev/null
+++ b/tests/language/top_level/getter_no_setter1_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+bool getter_visited = false;
+
+int get getter {
+ getter_visited = true;
+ return -1;
+}
+
+class Class {
+ method() {
+ getter++; /*@compile-error=unspecified*/
+ }
+}
+
+main() {
+ new Class().method();
+}
diff --git a/tests/language/top_level/getter_no_setter2_test.dart b/tests/language/top_level/getter_no_setter2_test.dart
new file mode 100644
index 0000000..4545839
--- /dev/null
+++ b/tests/language/top_level/getter_no_setter2_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+bool getter_visited = false;
+
+final int getter = () {
+ getter_visited = true;
+ return -1;
+}();
+
+class Class {
+ method() {
+ getter++; /*@compile-error=unspecified*/
+ }
+}
+
+main() {
+ new Class().method();
+}
diff --git a/tests/language/top_level/in_initializer_test.dart b/tests/language/top_level/in_initializer_test.dart
new file mode 100644
index 0000000..b639ca4
--- /dev/null
+++ b/tests/language/top_level/in_initializer_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that constructor initializers can access top level elements.
+
+const topLevelField = 1;
+topLevelMethod() => 1;
+get topLevelGetter {
+ return 1;
+}
+
+class Foo {
+ Foo.one() : x = topLevelField;
+ Foo.second() : x = topLevelMethod;
+ Foo.third() : x = topLevelGetter;
+ var x;
+}
+
+main() {
+ Expect.equals(topLevelField, new Foo.one().x);
+ Expect.equals(topLevelMethod(), new Foo.second().x());
+ Expect.equals(topLevelGetter, new Foo.third().x);
+}
diff --git a/tests/language/top_level/method_test.dart b/tests/language/top_level/method_test.dart
new file mode 100644
index 0000000..ea3ce0f
--- /dev/null
+++ b/tests/language/top_level/method_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+untypedTopLevel() {
+ return 1;
+}
+
+class TopLevelMethodTest {
+ static void testMain() {
+ Expect.equals(1, untypedTopLevel());
+ }
+}
+
+main() {
+ TopLevelMethodTest.testMain();
+}
diff --git a/tests/language/top_level/multiple_files_test.dart b/tests/language/top_level/multiple_files_test.dart
new file mode 100644
index 0000000..53f578e
--- /dev/null
+++ b/tests/language/top_level/multiple_files_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library TopLevelMultipleFilesTest.dart;
+
+import "package:expect/expect.dart";
+part 'file1.dart';
+part 'file2.dart';
diff --git a/tests/language/top_level/non_prefixed_library_test.dart b/tests/language/top_level/non_prefixed_library_test.dart
new file mode 100644
index 0000000..937170c
--- /dev/null
+++ b/tests/language/top_level/non_prefixed_library_test.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library TopLevelMultipleFilesTest.dart;
+
+import "package:expect/expect.dart";
+import 'prefixed_library.dart';
+part 'file1.dart';
diff --git a/tests/language/top_level/prefixed_declaration_test.dart b/tests/language/top_level/prefixed_declaration_test.dart
new file mode 100644
index 0000000..0243091
--- /dev/null
+++ b/tests/language/top_level/prefixed_declaration_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test for top level declarations involving an imported type.
+
+library main;
+
+import "package:expect/expect.dart";
+import "../library11.dart" as lib11;
+
+lib11.Library11? variable = null;
+
+lib11.Library11? function() => null;
+
+lib11.Library11? get getter => null;
+
+main() {
+ Expect.isTrue(variable == null);
+ Expect.isTrue(function() == null);
+ Expect.isTrue(getter == null);
+}
diff --git a/tests/language/top_level/prefixed_library.dart b/tests/language/top_level/prefixed_library.dart
new file mode 100644
index 0000000..6e48391
--- /dev/null
+++ b/tests/language/top_level/prefixed_library.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library TopLevelMultipleFilesTest.dart;
+
+const topLevelVar = 42;
+
+topLevelMethod() => 87;
diff --git a/tests/language/top_level/unresolved_method_test.dart b/tests/language/top_level/unresolved_method_test.dart
new file mode 100644
index 0000000..1aa0503
--- /dev/null
+++ b/tests/language/top_level/unresolved_method_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that an unresolved method call at the top level creates a compile-
+// time error.
+
+var a = b(); /*@compile-error=unspecified*/
+
+main() {
+ print(a);
+}
diff --git a/tests/language/top_level/unresolved_var_test.dart b/tests/language/top_level/unresolved_var_test.dart
new file mode 100644
index 0000000..c2e5f72
--- /dev/null
+++ b/tests/language/top_level/unresolved_var_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that an unresolved identifier at the top level causes a compile-time
+// error.
+
+var a = b; /*@compile-error=unspecified*/
+
+main() {
+ print(a);
+}
diff --git a/tests/language/top_level/var_test.dart b/tests/language/top_level/var_test.dart
new file mode 100644
index 0000000..e7d9216
--- /dev/null
+++ b/tests/language/top_level/var_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Dart test program testing top-level variables.
+
+import "package:expect/expect.dart";
+
+var a, b;
+
+class TopLevelVarTest {
+ static testMain() {
+ Expect.equals(null, a);
+ Expect.equals(null, b);
+ a = b = 100;
+ b++;
+ Expect.equals(100, a);
+ Expect.equals(101, b);
+
+ Expect.equals(111, x);
+ Expect.equals(112, y);
+ }
+}
+
+// Ensure that initializers work for both const and non-const variables.
+const int x = 2 * 55 + 1;
+int y = x + 1;
+
+main() {
+ TopLevelVarTest.testMain();
+}
diff --git a/tests/language/type/alias_equality_test.dart b/tests/language/type/alias_equality_test.dart
new file mode 100644
index 0000000..7ee087a
--- /dev/null
+++ b/tests/language/type/alias_equality_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that type aliases perform equality tests according to the
+// underlying function type, not as if they were a distinct type
+// for each type alias declaration.
+
+import 'package:expect/expect.dart';
+
+typedef F1 = void Function(int);
+typedef F2 = void Function(int);
+typedef void F3(int x);
+
+typedef G1 = X Function<X>(X);
+typedef G2 = X Function<X>(X);
+typedef G3 = Y Function<Y>(Y);
+
+main() {
+ Expect.equals(F1, F2); //# 01: ok
+ Expect.equals(F1, F3); //# 02: ok
+ Expect.equals(G1, G2); //# 03: ok
+ Expect.equals(G1, G3); //# 04: ok
+}
diff --git a/tests/language/type/check_const_function_typedef2_test.dart b/tests/language/type/check_const_function_typedef2_test.dart
new file mode 100644
index 0000000..c367411
--- /dev/null
+++ b/tests/language/type/check_const_function_typedef2_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that typechecks on const objects with typedefs work.
+
+import "package:expect/expect.dart";
+
+typedef String Int2String(int x);
+
+class A {
+ final Int2String f;
+ const A(this.f);
+}
+
+int foo(String x) => 499;
+
+const a = const A(foo); /*@compile-error=unspecified*/
+
+main() {
+ a.f(499);
+}
diff --git a/tests/language/type/check_const_function_typedef_test.dart b/tests/language/type/check_const_function_typedef_test.dart
new file mode 100644
index 0000000..484c61a
--- /dev/null
+++ b/tests/language/type/check_const_function_typedef_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Tests that typechecks on const objects with typedefs work.
+
+import "package:expect/expect.dart";
+
+typedef String Int2String(int x);
+
+class A {
+ final Int2String f;
+ const A(this.f);
+}
+
+String foo(int x) => "str";
+
+const a = const A(foo);
+
+main() {
+ Expect.equals("str", a.f(499));
+}
diff --git a/tests/language/type/check_test.dart b/tests/language/type/check_test.dart
new file mode 100644
index 0000000..20539a1
--- /dev/null
+++ b/tests/language/type/check_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to remove the a B type check
+// after an A type check, because it thought any subtype of A had to be B.
+
+import "package:expect/expect.dart";
+
+class A {}
+
+class B extends A {}
+
+main() {
+ var a = [new A(), new B()];
+ var b = a[0];
+ b = b as A;
+ Expect.throwsTypeError(() => b as B);
+}
diff --git a/tests/language/type/checks_in_factory_method_runtime_test.dart b/tests/language/type/checks_in_factory_method_runtime_test.dart
new file mode 100644
index 0000000..58f0c89
--- /dev/null
+++ b/tests/language/type/checks_in_factory_method_runtime_test.dart
@@ -0,0 +1,43 @@
+// TODO(multitest): This was automatically migrated from a multitest and may
+// contain strange or dead code.
+
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Tests the type checking when passing code into closure from inside a factory method
+
+import "package:expect/expect.dart";
+
+abstract class Foo<T> {
+ factory Foo.from() = Bar<T>.from;
+}
+
+class Bar<T> implements Foo<T> {
+ Bar() {}
+
+ factory Bar.from() {
+ var func = (T arg) {
+ T foo = arg;
+ bool isString = foo is String;
+ print(arg);
+ print(" String=$isString");
+ };
+
+
+ return new Bar<T>();
+ }
+}
+
+main() {
+ Foo<String> value1;
+ value1 = new Foo<String>.from();
+
+ bool gotError = false;
+
+ try {
+ Foo<int> value2 = new Foo<int>.from();
+ } on TypeError catch (e) {
+ gotError = true;
+ }
+ Expect.equals(false, gotError);
+}
diff --git a/tests/language/type/checks_in_factory_method_test.dart b/tests/language/type/checks_in_factory_method_test.dart
new file mode 100644
index 0000000..cae8f04
--- /dev/null
+++ b/tests/language/type/checks_in_factory_method_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Tests the type checking when passing code into closure from inside a factory method
+
+import "package:expect/expect.dart";
+
+abstract class Foo<T> {
+ factory Foo.from() = Bar<T>.from;
+}
+
+class Bar<T> implements Foo<T> {
+ Bar() {}
+
+ factory Bar.from() {
+ var func = (T arg) {
+ T foo = arg;
+ bool isString = foo is String;
+ print(arg);
+ print(" String=$isString");
+ };
+
+ func("Hello World!");
+ // ^^^^^^^^^^^^^^
+ // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+ // [cfe] The argument type 'String' can't be assigned to the parameter type 'T'.
+ return new Bar<T>();
+ }
+}
+
+main() {
+ Foo<String> value1;
+ value1 = new Foo<String>.from();
+
+ bool gotError = false;
+
+ try {
+ Foo<int> value2 = new Foo<int>.from();
+ } on TypeError catch (e) {
+ gotError = true;
+ }
+ Expect.equals(false, gotError);
+}
diff --git a/tests/language/type/constants_test.dart b/tests/language/type/constants_test.dart
new file mode 100644
index 0000000..560e485
--- /dev/null
+++ b/tests/language/type/constants_test.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test that the value of constant type literals are allowed as
+// constant map keys and case expressions, and the value of non-constant type
+// literals are not.
+
+import "dart:collection" deferred as prefix;
+
+main(args) {
+ testSwitch(args);
+ testMaps(args);
+}
+
+const Type numType = num;
+
+Type argumentType<T>() => T;
+
+void testSwitch<T extends MyType>(args) {
+ var types = [MyType, T, argumentType<MyType>(), argumentType<T>()];
+ for (int i = 0; i < types.length; i++) {
+ switch (types[i]) {
+ // Must be type literal or not override `==`.
+ case const MyType(): //# 01: compile-time error
+
+ // Must not be type variable.
+ case T: //# 02: compile-time error
+
+ // Must not be deferred type.
+ case prefix.HashSet: //# 03: compile-time error
+
+ // Constant type literals are valid.
+ case String:
+ throw "unreachable: String #$i";
+ case int:
+ throw "unreachable: int #$i";
+ case numType:
+ throw "unreachable: num #$i";
+ case MyType:
+ break;
+ default:
+ throw "unreachable: default #$i";
+ }
+ }
+}
+
+void testMaps<T extends MyType>(args) {
+ const map = {
+ // Must be type literal or not override `==`.
+ MyType(): 0, //# 04: compile-time error
+
+ // Must not be type variable.
+ T: 0, //# 05: compile-time error
+
+ // Must not be deferred.
+ prefix.HashSet: 0, //# 06: compile-time error
+
+ // Constant type literals are valid.
+ MyType: 0,
+ int: 1,
+ String: 2,
+ numType: 3,
+ };
+ if (map[MyType] != 0) throw "Map Error: ${MyType} as literal";
+ if (map[T] != 0) throw "Map Error: ${T} as type argument";
+ if (map[argumentType<MyType>()] != 0) {
+ throw "Map Error: ${argumentType<MyType>()} as type argument of literal";
+ }
+ if (map[argumentType<T>()] != 0) {
+ throw "Map Error: ${argumentType<T>()} as type argument of type variable";
+ }
+ if (map[num] != 3) throw "Map Error: ${num} -> ${map[num]}";
+}
+
+// An implementation of `Type` which overrides `==`,
+// but is not the value of a constant type literal.
+class MyType implements Type {
+ const MyType();
+ int get hashCode => 0;
+ bool operator ==(Object other) => identical(this, other);
+}
diff --git a/tests/language/type/conversion_ssa_test.dart b/tests/language/type/conversion_ssa_test.dart
new file mode 100644
index 0000000..975b03b
--- /dev/null
+++ b/tests/language/type/conversion_ssa_test.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js, that used to generate bad code in
+// checked mode. The pattern that lead to an error was:
+//
+// t1 = GeneratedAtUseSite instruction
+// t2 = check(t1)
+// t3 = check(t2)
+// t4 = use(t3)
+// t5 = use(t3)
+// t6 = use(t2)
+//
+// The SSA variable allocator used to allocate the same variable for
+// t5 and t2, because of a bogus optimization with check instructions.
+
+expect(a, b) {
+ if (a != b) throw 'Failed';
+}
+
+var array = <dynamic>[
+ new SelectorGroup([
+ new Selector([new SimpleSelectorSequence(new ClassSelector())]),
+ new Selector([new SimpleSelectorSequence(new ClassSelector())]),
+ new Selector([new SimpleSelectorSequence(new ClassSelector())])
+ ]),
+ new Object()
+];
+
+class RuleSet {
+ final SelectorGroup _selectorGroup;
+ RuleSet(this._selectorGroup);
+ SelectorGroup get selectorGroup => _selectorGroup;
+}
+
+class SelectorGroup {
+ List<Selector> _selectors;
+ SelectorGroup(this._selectors);
+ List<Selector> get selectors => _selectors;
+}
+
+class Selector {
+ final List<SimpleSelectorSequence> _simpleSelectorSequences;
+ Selector(this._simpleSelectorSequences);
+ List<SimpleSelectorSequence> get simpleSelectorSequences =>
+ _simpleSelectorSequences;
+}
+
+class SimpleSelectorSequence {
+ final SimpleSelector _selector;
+ SimpleSelectorSequence(this._selector);
+ get simpleSelector => _selector;
+}
+
+class SimpleSelector {}
+
+class ClassSelector extends SimpleSelector {}
+
+void testSelectorGroups() {
+ // Fetch the rule set from an array to trick the type inferrer.
+ var ruleset = new RuleSet(array[0]);
+ expect(ruleset.selectorGroup.selectors.length, 3);
+
+ var groupSelector0 = ruleset.selectorGroup.selectors[0];
+ var selector0 = groupSelector0.simpleSelectorSequences[0];
+ var simpleSelector0 = selector0.simpleSelector;
+
+ var groupSelector1 = ruleset.selectorGroup.selectors[1];
+ var selector1 = groupSelector1.simpleSelectorSequences[0];
+ var simpleSelector1 = selector1.simpleSelector;
+ expect(simpleSelector1 is ClassSelector, true);
+ var groupSelector2 = ruleset.selectorGroup.selectors[2];
+}
+
+main() {
+ testSelectorGroups();
+ // Trick the type inferrer.
+ new SimpleSelectorSequence(new SimpleSelector());
+ new SelectorGroup([]);
+ new Selector([]);
+}
diff --git a/tests/language/type/error_test.dart b/tests/language/type/error_test.dart
new file mode 100644
index 0000000..4797b37
--- /dev/null
+++ b/tests/language/type/error_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that various type errors produced by explicit casts don't invoke
+// user-defined code during error reporting.
+
+class NoToString {
+ toString() {
+ Expect.fail("should not be called");
+ return "";
+ }
+}
+
+/// Defeat optimizations of type checks.
+dynamic wrap(e) {
+ if (new DateTime.now().year == 1980) return null;
+ return e;
+}
+
+bool assertionsEnabled = false;
+
+void main() {
+ assert(assertionsEnabled = true);
+
+ dynamic noToString = NoToString();
+
+ Expect.throws<TypeError>(() {
+ wrap(noToString) as int; // Explicit cast should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+
+ if (assertionsEnabled) {
+ Expect.throws<AssertionError>(() {
+ assert(wrap(false), noToString); // Assertion should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+ }
+}
diff --git a/tests/language/type/guard_conversion_test.dart b/tests/language/type/guard_conversion_test.dart
new file mode 100644
index 0000000..34427d4
--- /dev/null
+++ b/tests/language/type/guard_conversion_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+foo() => 'bar';
+
+main() {
+ var a = foo();
+ var b = 'c';
+ do {
+ b = a[2];
+ } while (b != 'r');
+
+ if (a is Comparable) {
+ // Re-assign "a" to disable the promotion to Comparable which would
+ // otherwise prohibit calling "+" on a.
+ a = a as dynamic;
+
+ a += a;
+ }
+ Expect.equals('barbar', a);
+}
diff --git a/tests/language/type/hoisting_test.dart b/tests/language/type/hoisting_test.dart
new file mode 100644
index 0000000..77ea730
--- /dev/null
+++ b/tests/language/type/hoisting_test.dart
@@ -0,0 +1,63 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import "package:expect/expect.dart";
+
+class A<T> {
+ A(this.x, T z);
+ A.make();
+ void f(T x) {}
+ static String g(String x) {
+ return x;
+ }
+
+ late T x;
+}
+
+class B extends A<int> {
+ B(int x, int z) : super(x, z);
+ B.make() : super.make();
+ void f(int x) {}
+ static int g(int x) {
+ return x;
+ }
+}
+
+class C {
+ C(this.x, int z);
+ void f(int x) {}
+ static int g(int x) {
+ return x;
+ }
+
+ int x = 0;
+}
+
+typedef void ToVoid<T>(T x);
+typedef T Id<T>(T x);
+
+void main() {
+ {
+ A<String> a = new A<String>("hello", "world");
+ Expect.isTrue(new A<String>.make() is! A<int>);
+ Expect.isTrue(new A.make() is A);
+ Expect.isTrue(a is! A<int>);
+ Expect.isTrue(a is A<String>);
+ Expect.isTrue(a.f is ToVoid<String>);
+ Expect.isTrue(A.g is Id<String>);
+ }
+ {
+ B b = new B(0, 1);
+ Expect.isTrue(new B.make() is B);
+ Expect.isTrue(new B.make() is A<int>);
+ Expect.isTrue(b is B);
+ Expect.isTrue(b.f is ToVoid<int>);
+ Expect.isTrue(B.g is Id<int>);
+ }
+ {
+ C c = new C(0, 1);
+ Expect.isTrue(c is C);
+ Expect.isTrue(c.f is ToVoid<int>);
+ Expect.isTrue(C.g is Id<int>);
+ }
+}
diff --git a/tests/language/type/implicit_error_test.dart b/tests/language/type/implicit_error_test.dart
new file mode 100644
index 0000000..1c42842
--- /dev/null
+++ b/tests/language/type/implicit_error_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that various type errors produced by implicit casts don't invoke
+// user-defined code during error reporting.
+
+class NoToString {
+ toString() {
+ Expect.fail("should not be called");
+ return "";
+ }
+}
+
+/// Defeat optimizations of type checks.
+dynamic wrap(e) {
+ if (new DateTime.now().year == 1980) return null;
+ return e;
+}
+
+bool assertionsEnabled = false;
+
+void main() {
+ assert(assertionsEnabled = true);
+
+ dynamic noToString = NoToString();
+
+ Expect.throws<TypeError>(() {
+ int x = wrap(noToString); // Implicit cast should throw
+ return x;
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+
+ if (assertionsEnabled) {
+ Expect.throws<TypeError>(() {
+ assert(wrap(noToString)); // Implicit cast should throw
+ }, (e) {
+ e.toString(); // Should not throw.
+ return true;
+ });
+ }
+}
diff --git a/tests/language/type/intersection_test.dart b/tests/language/type/intersection_test.dart
new file mode 100644
index 0000000..dc548b4
--- /dev/null
+++ b/tests/language/type/intersection_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to consider that the
+// intersection of [Comparable] and [num] is conflicting.
+
+import "package:expect/expect.dart";
+
+class A {
+ foo(a, Comparable b) => a == b;
+ bar(a, Comparable b) => b == a;
+}
+
+main() {
+ Expect.isFalse(new A().foo(1, 'foo'));
+ Expect.isTrue(new A().foo(1, 1));
+ Expect.isFalse(new A().bar(1, 'foo'));
+ Expect.isTrue(new A().bar(1, 1));
+}
diff --git a/tests/language_2/super/in_async3_test.dart b/tests/language_2/super/in_async3_test.dart
index 425d209..9798010 100644
--- a/tests/language_2/super/in_async3_test.dart
+++ b/tests/language_2/super/in_async3_test.dart
@@ -7,7 +7,7 @@
import 'dart:async';
class A {
- Future/*<T>*/ foo/*<T>*/(/*=T*/ x) async => x;
+ Future<T> foo<T>(T x) async => x;
}
class B extends A {
diff --git a/tests/language_2/super/in_async4_test.dart b/tests/language_2/super/in_async4_test.dart
index bbe7724..399c8d8 100644
--- a/tests/language_2/super/in_async4_test.dart
+++ b/tests/language_2/super/in_async4_test.dart
@@ -7,7 +7,7 @@
import 'dart:async';
class A {
- Future/*<T>*/ foo/*<T>*/({/*=T*/ x}) async => x;
+ Future<T> foo<T>({T x}) async => x;
}
class B extends A {
diff --git a/tests/language_2/super/in_finally_test.dart b/tests/language_2/super/in_finally_test.dart
index f0c0c10..41f74756 100644
--- a/tests/language_2/super/in_finally_test.dart
+++ b/tests/language_2/super/in_finally_test.dart
@@ -5,7 +5,7 @@
import "package:expect/expect.dart";
class A {
- /*<T>*/ foo/*<T>*/({/*=T*/ x}) => x;
+ T foo<T>({T x}) => x;
}
class B extends A {
diff --git a/tools/VERSION b/tools/VERSION
index c51350b02..60fa9bb 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
MAJOR 2
MINOR 9
PATCH 0
-PRERELEASE 17
+PRERELEASE 18
PRERELEASE_PATCH 0
ABI_VERSION 37
OLDEST_SUPPORTED_ABI_VERSION 37
diff --git a/tools/bots/dart_sdk.py b/tools/bots/dart_sdk.py
index 94fe2ea..f152233 100755
--- a/tools/bots/dart_sdk.py
+++ b/tools/bots/dart_sdk.py
@@ -74,22 +74,6 @@
DartArchiveUploadSDKs(BUILD_OS, arch, sdk_zip)
-def CopyAotBinaries(arch, sdk_path):
- product_sdk_path = BuildRootPath(
- 'dart-sdk', arch=arch, build_mode='product')
- # We don't support precompilation on ia32.
- if arch != 'ia32':
- with bot.BuildStep('Patching in PRODUCT built AOT binaries'):
- CopyBetween(product_sdk_path, sdk_path, 'bin', 'utils',
- GuessExtension('gen_snapshot'))
- CopyBetween(product_sdk_path, sdk_path, 'bin',
- GuessExtension('dartaotruntime'))
- shutil.copy2(
- os.path.join(product_sdk_path, 'lib', '_internal',
- 'vm_platform_strong.dill'),
- os.path.join(sdk_path, 'lib', '_internal',
- 'vm_platform_strong_product.dill'))
-
def DartArchiveUploadSDKs(system, arch, sdk_zip):
namer = bot_utils.GCSNamer(CHANNEL, bot_utils.ReleaseType.RAW)
@@ -261,15 +245,8 @@
elif CHANNEL != bot_utils.Channel.TRY:
for arch in BuildArchitectures():
sdk_path = BuildRootPath('dart-sdk', arch=arch)
- # Patch in all the PRODUCT built AOT binaries.
- CopyAotBinaries(arch, sdk_path)
with bot.BuildStep('Create and upload sdk zip for ' + arch):
CreateAndUploadSDKZip(arch, sdk_path)
DartArchiveUnstrippedBinaries()
if BUILD_OS == 'linux':
CreateUploadVersionFile()
- else: # CHANNEL == bot_utils.Channel.TRY
- # Patch in all the PRODUCT built AOT binaries.
- for arch in BuildArchitectures():
- sdk_path = BuildRootPath('dart-sdk', arch=arch)
- CopyAotBinaries(arch, sdk_path)
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 315b0c2..828c326 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -42,9 +42,9 @@
"tests/co19/co19-dartdevc.status",
"tests/co19/co19-kernel.status",
"tests/co19/co19-runtime.status",
- "tests/compiler/",
"tests/corelib_2/",
"tests/dart2js_2/",
+ "tests/dartdevc_2/",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -83,9 +83,9 @@
"tests/co19/co19-dartdevc.status",
"tests/co19/co19-kernel.status",
"tests/co19/co19-runtime.status",
- "tests/compiler/",
"tests/corelib/",
"tests/dart2js/",
+ "tests/dartdevc/",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -131,9 +131,9 @@
"tests/co19_2/co19_2-dartdevc.status",
"tests/co19_2/co19_2-kernel.status",
"tests/co19_2/co19_2-runtime.status",
- "tests/compiler/",
"tests/corelib_2/",
"tests/dart2js_2/",
+ "tests/dartdevc_2/",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -175,9 +175,9 @@
"tests/co19/co19-dartdevc.status",
"tests/co19/co19-kernel.status",
"tests/co19/co19-runtime.status",
- "tests/compiler/",
"tests/corelib/",
"tests/dart2js/",
+ "tests/dartdevc/",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -219,11 +219,12 @@
"tests/co19_2/co19_2-dartdevc.status",
"tests/co19_2/co19_2-kernel.status",
"tests/co19_2/co19_2-runtime.status",
- "tests/compiler/",
"tests/corelib/",
"tests/corelib_2/",
"tests/dart2js/",
"tests/dart2js_2/",
+ "tests/dartdevc/",
+ "tests/dartdevc_2/",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -328,11 +329,12 @@
"tests/co19_2/co19_2-dartdevc.status",
"tests/co19_2/co19_2-kernel.status",
"tests/co19_2/co19_2-runtime.status",
- "tests/compiler/",
"tests/corelib/",
"tests/corelib_2/",
"tests/dart2js/",
"tests/dart2js_2/",
+ "tests/dartdevc",
+ "tests/dartdevc_2",
"tests/kernel/",
"tests/language/",
"tests/language_2/",
@@ -1924,7 +1926,7 @@
"language_2",
"corelib_2",
"lib_2",
- "dartdevc_native"
+ "dartdevc_2"
]
},
{
@@ -2008,7 +2010,7 @@
"language_2",
"corelib_2",
"lib_2",
- "dartdevc_native"
+ "dartdevc_2"
]
}
]
@@ -2054,7 +2056,7 @@
"language",
"corelib",
"lib",
- "dartdevc_native"
+ "dartdevc"
],
"shards": 5,
"fileset": "web_platform_nnbd"
@@ -2075,7 +2077,7 @@
"language",
"corelib",
"lib",
- "dartdevc_native"
+ "dartdevc"
]
},
{
@@ -2110,7 +2112,7 @@
"language_2",
"corelib_2",
"lib_2",
- "dartdevc_native"
+ "dartdevc_2"
]
},
{
@@ -2652,26 +2654,6 @@
]
},
{
- "name": "build gen_kernel.dart.snapshot",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64,arm,arm64",
- "--mode=release",
- "copy_gen_kernel_snapshot"
- ]
- },
- {
- "name": "build gen_snapshot and dartaotruntime",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64,arm,arm64",
- "--mode=product",
- "copy_gen_snapshot",
- "copy_dartaotruntime",
- "copy_vm_dill_files"
- ]
- },
- {
"name": "upload sdk",
"script": "tools/bots/dart_sdk.py"
},
@@ -2717,26 +2699,6 @@
]
},
{
- "name": "build gen_kernel.dart.snapshot",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64",
- "--mode=release",
- "copy_gen_kernel_snapshot"
- ]
- },
- {
- "name": "build gen_snapshot and dartaotruntime",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64",
- "--mode=product",
- "copy_gen_snapshot",
- "copy_dartaotruntime",
- "copy_vm_dill_files"
- ]
- },
- {
"name": "upload sdk",
"script": "tools/bots/dart_sdk.py"
},
@@ -2768,26 +2730,6 @@
]
},
{
- "name": "build gen_kernel.dart.snapshot",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64",
- "--mode=release",
- "copy_gen_kernel_snapshot"
- ]
- },
- {
- "name": "build gen_snapshot and dartaotruntime",
- "script": "tools/build.py",
- "arguments": [
- "--arch=x64",
- "--mode=product",
- "copy_gen_snapshot",
- "copy_dartaotruntime",
- "copy_vm_dill_files"
- ]
- },
- {
"name": "upload sdk",
"script": "tools/bots/dart_sdk.py"
},
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index 14523e0..9e36db7 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -157,6 +157,7 @@
third_party/pkg \
third_party/pkg_tested \
.packages \
+ .dart_tool/package_config.json \
pkg \
runtime/bin \
runtime/lib \
@@ -295,6 +296,7 @@
third_party/pkg \
third_party/pkg_tested \
.packages \
+ .dart_tool/package_config.json \
pkg \
runtime/bin \
runtime/lib \
diff --git a/tools/build.py b/tools/build.py
index 0a49af9..6321be1 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -59,7 +59,7 @@
result.add_option(
"--os",
help='Target OSs (comma-separated).',
- metavar='[all,host,android]',
+ metavar='[all,host,android,fuchsia]',
default='host')
result.add_option(
"--sanitizer",
@@ -88,7 +88,7 @@
if options.mode == 'all':
options.mode = 'debug,release,product'
if options.os == 'all':
- options.os = 'host,android'
+ options.os = 'host,android,fuchsia'
if options.sanitizer == 'all':
options.sanitizer = 'none,asan,lsan,msan,tsan,ubsan'
options.mode = options.mode.split(',')
@@ -110,13 +110,12 @@
return False
options.os = [ProcessOsOption(os_name) for os_name in options.os]
for os_name in options.os:
- if not os_name in ['android', 'freebsd', 'linux', 'macos', 'win32']:
+ if not os_name in [
+ 'android', 'freebsd', 'linux', 'macos', 'win32', 'fuchsia'
+ ]:
print("Unknown os %s" % os_name)
return False
- if os_name != HOST_OS:
- if os_name != 'android':
- print("Unsupported target os %s" % os_name)
- return False
+ if os_name == 'android':
if not HOST_OS in ['linux', 'macos']:
print("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
@@ -135,6 +134,19 @@
"For android builds you must specify a target, such as 'runtime'."
)
return False
+ elif os_name == 'fuchsia':
+ if HOST_OS != 'linux':
+ print("Cross-compilation to %s is not supported on host os %s."
+ % (os_name, HOST_OS))
+ return False
+ if arch != 'x64':
+ print(
+ "Cross-compilation to %s is not supported for architecture %s."
+ % (os_name, arch))
+ return False
+ elif os_name != HOST_OS:
+ print("Unsupported target os %s" % os_name)
+ return False
return True
diff --git a/tools/gn.py b/tools/gn.py
index c9335f4..9607231 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -127,7 +127,7 @@
def UseSysroot(args, gn_args):
# Don't try to use a Linux sysroot if we aren't on Linux.
- if gn_args['target_os'] != 'linux':
+ if gn_args['target_os'] != 'linux' and HOST_OS != 'linux':
return False
# Don't use the sysroot if we're given another sysroot.
if TargetSysroot(args):
@@ -221,15 +221,18 @@
gn_args['is_msan'] = sanitizer == 'msan'
gn_args['is_tsan'] = sanitizer == 'tsan'
gn_args['is_ubsan'] = sanitizer == 'ubsan'
- gn_args['include_dart2native'] = True
gn_args['is_qemu'] = args.use_qemu
if not args.platform_sdk and not gn_args['target_cpu'].startswith('arm'):
gn_args['dart_platform_sdk'] = args.platform_sdk
- gn_args['dart_stripped_binary'] = 'exe.stripped/dart'
- gn_args[
- 'dart_precompiled_runtime_stripped_binary'] = 'exe.stripped/dart_precompiled_runtime'
- gn_args['gen_snapshot_stripped_binary'] = 'exe.stripped/gen_snapshot'
+
+ # We don't support stripping on Windows
+ if host_os != 'win':
+ gn_args['dart_stripped_binary'] = 'exe.stripped/dart'
+ gn_args['dart_precompiled_runtime_stripped_binary'] = (
+ 'exe.stripped/dart_precompiled_runtime_product')
+ gn_args['gen_snapshot_stripped_binary'] = (
+ 'exe.stripped/gen_snapshot_product')
# Setup the user-defined sysroot.
if UseSysroot(args, gn_args):
@@ -278,7 +281,7 @@
if args.mode == 'all':
args.mode = 'debug,release,product'
if args.os == 'all':
- args.os = 'host,android'
+ args.os = 'host,android,fuchsia'
if args.sanitizer == 'all':
args.sanitizer = 'none,asan,lsan,msan,tsan,ubsan'
args.mode = args.mode.split(',')
@@ -299,13 +302,12 @@
return False
oses = [ProcessOsOption(os_name) for os_name in args.os]
for os_name in oses:
- if not os_name in ['android', 'freebsd', 'linux', 'macos', 'win32']:
+ if not os_name in [
+ 'android', 'freebsd', 'linux', 'macos', 'win32', 'fuchsia'
+ ]:
print("Unknown os %s" % os_name)
return False
- if os_name != HOST_OS:
- if os_name != 'android':
- print("Unsupported target os %s" % os_name)
- return False
+ if os_name == 'android':
if not HOST_OS in ['linux', 'macos']:
print("Cross-compilation to %s is not supported on host os %s."
% (os_name, HOST_OS))
@@ -317,6 +319,19 @@
"Cross-compilation to %s is not supported for architecture %s."
% (os_name, arch))
return False
+ elif os_name == 'fuchsia':
+ if HOST_OS != 'linux':
+ print("Cross-compilation to %s is not supported on host os %s."
+ % (os_name, HOST_OS))
+ return False
+ if arch != 'x64':
+ print(
+ "Cross-compilation to %s is not supported for architecture %s."
+ % (os_name, arch))
+ return False
+ elif os_name != HOST_OS:
+ print("Unsupported target os %s" % os_name)
+ return False
if HOST_OS != 'win' and args.use_crashpad:
print("Crashpad is only supported on Windows")
return False
@@ -363,7 +378,7 @@
'--os',
type=str,
help='Target OSs (comma-separated).',
- metavar='[all,host,android]',
+ metavar='[all,host,android,fuchsia]',
default='host')
common_group.add_argument(
'--sanitizer',
diff --git a/tools/linux_dist_support/debian/rules b/tools/linux_dist_support/debian/rules
index c6893d7..da3ff23 100755
--- a/tools/linux_dist_support/debian/rules
+++ b/tools/linux_dist_support/debian/rules
@@ -36,22 +36,6 @@
endif
endif
-# Only run AOT builds for supported archs.
-ifneq (,$(findstring $(DEB_HOST_ARCH_CPU),$(AOT_SUPPORTED_ARCHS)))
-AOT_BUILD_CMD := \
-python tools/build.py -v -m release -a $(ARCH) $(TOOLCHAIN) \
- copy_gen_kernel_snapshot; \
-python tools/build.py -v -m product -a $(ARCH) $(TOOLCHAIN) \
- copy_gen_snapshot copy_dartaotruntime; \
-mkdir -p out/$(BUILD_TYPE)/dart-sdk/bin/utils; \
-cp out/$(BUILD_TYPE_PRODUCT)/dart-sdk/bin/utils/gen_snapshot \
- out/$(BUILD_TYPE)/dart-sdk/bin/utils/gen_snapshot; \
-cp out/$(BUILD_TYPE_PRODUCT)/dart-sdk/bin/dartaotruntime \
- out/$(BUILD_TYPE)/dart-sdk/bin/dartaotruntime
-else
-AOT_BUILD_CMD := # empty
-endif
-
# Verbose?
ifeq (1,$(DH_VERBOSE))
BUILD_ARGS += V=1
@@ -74,7 +58,6 @@
override_dh_auto_build:
cd dart; \
python tools/build.py -v -m release -a $(ARCH) $(TOOLCHAIN) create_sdk; \
- $(AOT_BUILD_CMD); \
cd ..
# Building the Dart SDK will already strip all binaries.
diff --git a/tools/utils.py b/tools/utils.py
index 3971ef1..1b543e3c 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -311,7 +311,7 @@
def GetBuildConf(mode, arch, conf_os=None, sanitizer=None):
- if conf_os == 'android':
+ if conf_os is not None and conf_os != GuessOS() and conf_os != "host":
return '%s%s%s' % (GetBuildMode(mode), conf_os.title(), arch.upper())
else:
# Ask for a cross build if the host and target architectures don't match.
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 71fc422..9591612 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -204,7 +204,7 @@
# named `${name}_js` must exist.
# * args: additional args to pass to dartdevc
- prebuilt_dart_action(target_name) {
+ dart_action(target_name) {
script = "../../pkg/dev_compiler/bin/dartdevc.dart"
module = invoker.package
out_dir = rebase_path("$js_gen_dir")