diff options
Diffstat (limited to 'tools/aapt2/cmd/Dump.cpp')
-rw-r--r-- | tools/aapt2/cmd/Dump.cpp | 648 |
1 files changed, 410 insertions, 238 deletions
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 6bb762aafb3b..a23a6a46cf0f 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -14,18 +14,22 @@ * limitations under the License. */ +#include "Dump.h" + #include <cinttypes> #include <vector> #include "android-base/stringprintf.h" +#include "androidfw/ConfigDescription.h" #include "androidfw/StringPiece.h" #include "Debug.h" #include "Diagnostics.h" -#include "Flags.h" #include "LoadedApk.h" +#include "Util.h" #include "format/Container.h" #include "format/binary/BinaryResourceParser.h" +#include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "io/FileStream.h" #include "io/ZipArchive.h" @@ -39,13 +43,6 @@ using ::android::base::StringPrintf; namespace aapt { -struct DumpOptions { - DebugPrintTableOptions print_options; - - // The path to a file within an APK to dump. - Maybe<std::string> file_to_dump_path; -}; - static const char* ResourceFileTypeToString(const ResourceFile::Type& type) { switch (type) { case ResourceFile::Type::kPng: @@ -77,210 +74,6 @@ static void DumpCompiledFile(const ResourceFile& file, const Source& source, off printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len)); } -static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto, - text::Printer* printer) { - std::unique_ptr<xml::XmlResource> doc; - if (proto) { - std::unique_ptr<io::InputStream> in = file->OpenInputStream(); - if (in == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to open file"); - return false; - } - - io::ZeroCopyInputAdaptor adaptor(in.get()); - pb::XmlNode pb_node; - if (!pb_node.ParseFromZeroCopyStream(&adaptor)) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML"); - return false; - } - - std::string err; - doc = DeserializeXmlResourceFromPb(pb_node, &err); - if (doc == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML"); - return false; - } - printer->Println("Proto XML"); - } else { - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (data == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to open file"); - return false; - } - - std::string err; - doc = xml::Inflate(data->data(), data->size(), &err); - if (doc == nullptr) { - context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML"); - return false; - } - printer->Println("Binary XML"); - } - - Debug::DumpXml(*doc, printer); - return true; -} - -static bool TryDumpFile(IAaptContext* context, const std::string& file_path, - const DumpOptions& options) { - // Use a smaller buffer so that there is less latency for dumping to stdout. - constexpr size_t kStdOutBufferSize = 1024u; - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - std::string err; - std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err); - if (zip) { - ResourceTable table; - bool proto = false; - if (io::IFile* file = zip->FindFile("resources.pb")) { - proto = true; - - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (data == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb"); - return false; - } - - pb::ResourceTable pb_table; - if (!pb_table.ParseFromArray(data->data(), data->size())) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb"); - return false; - } - - if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - return false; - } - } else if (io::IFile* file = zip->FindFile("resources.arsc")) { - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (!data) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc"); - return false; - } - - BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path), - data->data(), data->size()); - if (!parser.Parse()) { - return false; - } - } - - if (!options.file_to_dump_path) { - if (proto) { - printer.Println("Proto APK"); - } else { - printer.Println("Binary APK"); - } - Debug::PrintTable(table, options.print_options, &printer); - return true; - } - - io::IFile* file = zip->FindFile(options.file_to_dump_path.value()); - if (file == nullptr) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "file '" << options.file_to_dump_path.value() - << "' not found in APK"); - return false; - } - return DumpXmlFile(context, file, proto, &printer); - } - - err.clear(); - - io::FileInputStream input(file_path); - if (input.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to open file: " << input.GetError()); - return false; - } - - // Try as a compiled file. - ContainerReader reader(&input); - if (reader.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to read container: " << reader.GetError()); - return false; - } - - printer.Println("AAPT2 Container (APC)"); - ContainerReaderEntry* entry; - while ((entry = reader.Next()) != nullptr) { - if (entry->Type() == ContainerEntryType::kResTable) { - printer.Println("kResTable"); - - pb::ResourceTable pb_table; - if (!entry->GetResTable(&pb_table)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse proto table: " << entry->GetError()); - continue; - } - - ResourceTable table; - err.clear(); - if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - continue; - } - - printer.Indent(); - Debug::PrintTable(table, options.print_options, &printer); - printer.Undent(); - } else if (entry->Type() == ContainerEntryType::kResFile) { - printer.Println("kResFile"); - pb::internal::CompiledFile pb_compiled_file; - off64_t offset; - size_t length; - if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { - context->GetDiagnostics()->Error( - DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError()); - continue; - } - - ResourceFile file; - std::string error; - if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { - context->GetDiagnostics()->Warn(DiagMessage(file_path) - << "failed to parse compiled file: " << error); - continue; - } - - printer.Indent(); - DumpCompiledFile(file, Source(file_path), offset, length, &printer); - printer.Undent(); - } - } - return true; -} - -static bool DumpPackageName(IAaptContext* context, const std::string& file_path) { - auto loaded_apk = LoadedApk::LoadApkFromPath(file_path, context->GetDiagnostics()); - if (!loaded_apk) { - return false; - } - - constexpr size_t kStdOutBufferSize = 1024u; - io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); - Printer printer(&fout); - - xml::Element* manifest_el = loaded_apk->GetManifest()->root.get(); - if (!manifest_el) { - context->GetDiagnostics()->Error(DiagMessage() << "No AndroidManifest."); - return false; - } - - xml::Attribute* attr = manifest_el->FindAttribute({}, "package"); - if (!attr) { - context->GetDiagnostics()->Error(DiagMessage() << "No package name."); - return false; - } - printer.Println(StringPrintf("%s", attr->value.c_str())); - - return true; -} - namespace { class DumpContext : public IAaptContext { @@ -332,44 +125,423 @@ class DumpContext : public IAaptContext { } // namespace -// Entry point for dump command. -int Dump(const std::vector<StringPiece>& args) { - bool verbose = false; - bool no_values = false; - DumpOptions options; - Flags flags = Flags() - .OptionalSwitch("--no-values", - "Suppresses output of values when displaying resource tables.", - &no_values) - .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.", - &options.file_to_dump_path) - .OptionalSwitch("-v", "increase verbosity of output", &verbose); - if (!flags.Parse("aapt2 dump", args, &std::cerr)) { +int DumpAPCCommand::Action(const std::vector<std::string>& args) { + DumpContext context; + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump container specified"); + return 1; + } + + bool error = false; + for (auto container : args) { + io::FileInputStream input(container); + if (input.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to open file: " << input.GetError()); + error = true; + continue; + } + + // Try as a compiled file. + ContainerReader reader(&input); + if (reader.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to read container: " << reader.GetError()); + error = true; + continue; + } + + printer_->Println("AAPT2 Container (APC)"); + ContainerReaderEntry* entry; + std::string error; + while ((entry = reader.Next()) != nullptr) { + if (entry->Type() == ContainerEntryType::kResTable) { + printer_->Println("kResTable"); + + pb::ResourceTable pb_table; + if (!entry->GetResTable(&pb_table)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse proto table: " << entry->GetError()); + error = true; + continue; + } + + ResourceTable table; + error.clear(); + if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse table: " << error); + error = true; + continue; + } + + printer_->Indent(); + Debug::PrintTable(table, print_options, printer_); + printer_->Undent(); + } else if (entry->Type() == ContainerEntryType::kResFile) { + printer_->Println("kResFile"); + pb::internal::CompiledFile pb_compiled_file; + off64_t offset; + size_t length; + if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse compiled proto file: " + << entry->GetError()); + error = true; + continue; + } + + ResourceFile file; + if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { + context.GetDiagnostics()->Warn(DiagMessage(container) + << "failed to parse compiled file: " << error); + error = true; + continue; + } + + printer_->Indent(); + DumpCompiledFile(file, Source(container), offset, length, printer_); + printer_->Undent(); + } + } + } + + return (error) ? 1 : 0; +} + +int DumpBadgerCommand::Action(const std::vector<std::string>& args) { + printer_->Print(StringPrintf("%s", kBadgerData)); + printer_->Print("Did you mean \"aapt2 dump badging\"?\n"); + return 1; +} + +int DumpConfigsCommand::Dump(LoadedApk* apk) { + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); + return 1; + } + + // Comparison function used to order configurations + auto compare = [](android::ConfigDescription c1, android::ConfigDescription c2) -> bool { + return c1.compare(c2) < 0; + }; + + // Insert the configurations into a set in order to keep every configuarion seen + std::set<android::ConfigDescription, decltype(compare)> configs(compare); + for (auto& package : table->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + for (auto& value : entry->values) { + configs.insert(value->config); + } + } + } + } + + // Print the configurations in order + for (auto& config : configs) { + GetPrinter()->Print(StringPrintf("%s\n", config.to_string().data())); + } + return 0; +} + +int DumpPackageNameCommand::Dump(LoadedApk* apk) { + Maybe<std::string> package_name = GetPackageName(apk); + if (!package_name) { + return 1; + } + + GetPrinter()->Println(package_name.value()); + return 0; +} + +int DumpStringsCommand::Dump(LoadedApk* apk) { + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); + return 1; + } + + // Load the run-time xml string pool using the flattened data + BigBuffer buffer(4096); + StringPool::FlattenUtf8(&buffer, table->string_pool, GetDiagnostics()); + auto data = buffer.to_string(); + android::ResStringPool pool(data.data(), data.size(), false); + Debug::DumpResStringPool(&pool, GetPrinter()); + return 0; +} + +int DumpStyleParentCommand::Dump(LoadedApk* apk) { + Maybe<std::string> package_name = GetPackageName(apk); + if (!package_name) { + return 1; + } + + const auto target_style = ResourceName(package_name.value(), ResourceType::kStyle, style_); + const auto table = apk->GetResourceTable(); + + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); + return 1; + } + + Maybe<ResourceTable::SearchResult> target = table->FindResource(target_style); + if (!target) { + GetDiagnostics()->Error( + DiagMessage() << "Target style \"" << target_style.entry << "\" does not exist"); return 1; } + Debug::PrintStyleGraph(table, target_style); + return 0; +} + +int DumpTableCommand::Dump(LoadedApk* apk) { + if (apk->GetApkFormat() == ApkFormat::kProto) { + GetPrinter()->Println("Proto APK"); + } else { + GetPrinter()->Println("Binary APK"); + } + + ResourceTable* table = apk->GetResourceTable(); + if (!table) { + GetDiagnostics()->Error(DiagMessage() << "Failed to retrieve resource table"); + return 1; + } + + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + Debug::PrintTable(*table, print_options, GetPrinter()); + return 0; +} + +int DumpXmlStringsCommand::Dump(LoadedApk* apk) { DumpContext context; - context.SetVerbose(verbose); - - auto parsedArgs = flags.GetArgs(); - if (parsedArgs.size() > 1 && parsedArgs[0] == "packagename") { - parsedArgs.erase(parsedArgs.begin()); - for (const std::string& arg : parsedArgs) { - if (!DumpPackageName(&context, arg)) { - return 1; + bool error = false; + for (auto xml_file : files_) { + android::ResXMLTree tree; + + if (apk->GetApkFormat() == ApkFormat::kProto) { + auto xml = apk->LoadXml(xml_file, GetDiagnostics()); + if (!xml) { + error = true; + continue; + } + + // Flatten the xml document to get a binary representation of the proto xml file + BigBuffer buffer(4096); + XmlFlattenerOptions options = {}; + options.keep_raw_values = true; + XmlFlattener flattener(&buffer, options); + if (!flattener.Consume(&context, xml.get())) { + error = true; + continue; + } + + // Load the run-time xml tree using the flattened data + std::string data = buffer.to_string(); + tree.setTo(data.data(), data.size(), /** copyData */ true); + + } else if (apk->GetApkFormat() == ApkFormat::kBinary) { + io::IFile* file = apk->GetFileCollection()->FindFile(xml_file); + if (!file) { + GetDiagnostics()->Error(DiagMessage(xml_file) + << "File '" << xml_file << "' not found in APK"); + error = true; + continue; + } + + std::unique_ptr<io::IData> data = file->OpenAsData(); + if (!data) { + GetDiagnostics()->Error(DiagMessage() << "Failed to open " << xml_file); + error = true; + continue; } + + // Load the run-time xml tree from the file data + tree.setTo(data->data(), data->size(), /** copyData */ true); + } else { + GetDiagnostics()->Error(DiagMessage(apk->GetSource()) << "Unknown APK format"); + error = true; + continue; } - return 0; + + Debug::DumpResStringPool(&tree.getStrings(), GetPrinter()); } + return (error) ? 1 : 0; +} - options.print_options.show_sources = true; - options.print_options.show_values = !no_values; - for (const std::string& arg : parsedArgs) { - if (!TryDumpFile(&context, arg, options)) { +int DumpXmlTreeCommand::Dump(LoadedApk* apk) { + for (auto file : files_) { + auto xml = apk->LoadXml(file, GetDiagnostics()); + if (!xml) { return 1; } + Debug::DumpXml(*xml, GetPrinter()); } return 0; } +const char DumpBadgerCommand::kBadgerData[2925] = { + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 95, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 63, 86, 35, 40, 46, 46, + 95, 95, 95, 95, 97, 97, 44, 32, 46, 124, 42, 33, 83, 62, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 58, 46, 58, 59, 61, 59, 61, 81, 81, 81, 81, 66, 96, 61, 61, 58, 46, + 46, 46, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 106, 81, 81, + 81, 81, 102, 59, 61, 59, 59, 61, 61, 61, 58, 46, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 61, 59, 59, 59, 58, 109, 81, 81, 81, 81, 61, 59, 59, 59, 59, 59, 58, 59, 59, + 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 60, 81, 81, 81, 81, 87, 58, + 59, 59, 59, 59, 59, 59, 61, 119, 44, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 47, 61, 59, 59, + 58, 100, 81, 81, 81, 81, 35, 58, 59, 59, 59, 59, 59, 58, 121, 81, 91, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 46, 109, 58, 59, 59, 61, 81, 81, 81, 81, 81, 109, 58, 59, 59, 59, + 59, 61, 109, 81, 81, 76, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 41, 87, 59, 61, 59, 41, 81, 81, + 81, 81, 81, 81, 59, 61, 59, 59, 58, 109, 81, 81, 87, 39, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 60, 81, 91, 59, 59, 61, 81, 81, 81, 81, 81, 87, 43, 59, 58, 59, 60, 81, 81, + 81, 76, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 52, 91, 58, 45, 59, 87, 81, 81, 81, 81, + 70, 58, 58, 58, 59, 106, 81, 81, 81, 91, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 93, 40, + 32, 46, 59, 100, 81, 81, 81, 81, 40, 58, 46, 46, 58, 100, 81, 81, 68, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, 46, 32, 46, + 46, 46, 32, 46, 32, 46, 45, 91, 59, 61, 58, 109, 81, 81, 81, 87, 46, 58, 61, + 59, 60, 81, 81, 80, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, 46, + 61, 59, 61, 61, 61, 59, 61, 61, 59, 59, 59, 58, 58, 46, 46, 41, 58, 59, 58, + 81, 81, 81, 81, 69, 58, 59, 59, 60, 81, 81, 68, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 58, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 61, 61, 46, 61, 59, 93, 81, 81, 81, 81, 107, 58, 59, 58, 109, 87, 68, + 96, 32, 32, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 46, 60, 61, 61, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 58, 58, 115, 109, 68, 41, 36, + 81, 109, 46, 61, 61, 81, 69, 96, 46, 58, 58, 46, 58, 46, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 46, 32, 95, 81, 67, + 61, 61, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 58, 68, 39, 61, 105, 61, 63, 81, 119, 58, 106, 80, 32, 58, 61, 59, 59, + 61, 59, 61, 59, 61, 46, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 36, 81, 109, 105, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 46, 58, 37, 73, 108, 108, 62, 52, 81, + 109, 34, 32, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 59, 61, 61, 46, 46, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 46, 45, 57, 101, 43, 43, 61, + 61, 59, 59, 59, 59, 59, 59, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 97, + 46, 61, 108, 62, 126, 58, 106, 80, 96, 46, 61, 61, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 61, 61, 97, 103, 97, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 45, 46, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, + 58, 59, 59, 59, 59, 61, 119, 81, 97, 124, 105, 124, 124, 39, 126, 95, 119, 58, 61, + 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 61, 119, 81, 81, + 99, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 58, 106, 81, 81, 81, 109, 119, + 119, 119, 109, 109, 81, 81, 122, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 58, 115, 81, 87, 81, 102, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58, + 59, 61, 81, 81, 81, 81, 81, 81, 87, 87, 81, 81, 81, 81, 81, 58, 59, 59, 59, + 59, 59, 59, 59, 59, 58, 45, 45, 45, 59, 59, 59, 41, 87, 66, 33, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 45, 32, 46, 32, 32, 32, 32, 32, 46, + 32, 126, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 58, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 58, 59, 59, 59, 58, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 58, 59, 59, 58, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 40, 58, 59, 59, 59, 46, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 60, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 59, 61, 59, 59, 61, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 58, 59, 59, 93, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 40, 59, + 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 106, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 76, 58, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 58, 58, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 87, 58, 59, 59, 59, 59, + 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 58, 59, 61, 41, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 87, 59, 61, 58, 59, 59, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 58, 61, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 107, 58, 59, 59, 59, 59, 58, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 58, 59, 59, 58, 51, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 102, 94, + 59, 59, 59, 59, 59, 61, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 58, 61, 59, 59, 59, 43, 63, 36, 81, + 81, 81, 87, 64, 86, 102, 58, 59, 59, 59, 59, 59, 59, 59, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, + 59, 59, 59, 59, 59, 59, 59, 43, 33, 58, 126, 126, 58, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 58, 45, 58, 61, 59, 58, 58, 58, 61, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 46, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, + 58, 95, 32, 45, 61, 59, 61, 59, 59, 59, 59, 59, 59, 59, 45, 58, 59, 59, 59, + 59, 61, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 58, 61, 59, 59, 59, 59, 59, 61, 59, 61, 46, 46, 32, 45, 45, 45, 59, 58, + 45, 45, 46, 58, 59, 59, 59, 59, 59, 59, 61, 46, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 46, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 61, 59, 46, 32, 32, 46, 32, 46, 32, 58, 61, 59, 59, 59, 59, 59, 59, 59, 59, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, + 59, 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, + 59, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 46, 61, 59, 59, 59, 59, 59, 59, 59, 32, 46, 32, + 32, 32, 32, 32, 32, 61, 46, 61, 59, 59, 59, 59, 59, 59, 58, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61, 59, 59, 59, + 59, 59, 59, 59, 59, 32, 46, 32, 32, 32, 32, 32, 32, 32, 46, 61, 58, 59, 59, + 59, 59, 59, 58, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 59, 59, 59, 46, 46, 32, 32, 32, 32, + 32, 32, 32, 61, 59, 59, 59, 59, 59, 59, 59, 45, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 45, 61, 59, 59, 59, 59, + 59, 58, 32, 46, 32, 32, 32, 32, 32, 32, 32, 58, 59, 59, 59, 59, 59, 58, 45, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 45, 45, 45, 45, 32, 46, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 45, 61, 59, 58, 45, 45, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 46, 32, 32, 46, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 10}; + } // namespace aapt |