summary refs log tree commit diff stats
path: root/tools
diff options
context:
space:
mode:
authorStar Rauchenberger <fefferburbia@gmail.com>2025-09-04 15:46:25 -0400
committerStar Rauchenberger <fefferburbia@gmail.com>2025-09-04 15:46:25 -0400
commita752ab325cf46d35a90606a354775799977dccb0 (patch)
tree66541b3ed6e820deb1d9e61cd9e10c874fb3a878 /tools
parent05d3219f4496104cdf8d96aaacbdd41f7e0dbed2 (diff)
downloadlingo2-archipelago-a752ab325cf46d35a90606a354775799977dccb0.tar.gz
lingo2-archipelago-a752ab325cf46d35a90606a354775799977dccb0.tar.bz2
lingo2-archipelago-a752ab325cf46d35a90606a354775799977dccb0.zip
[Data] Strip unnecessary AP IDs
This was causing issues in the client, specifically for The Ancient.
Diffstat (limited to 'tools')
-rw-r--r--tools/assign_ids/main.cpp77
-rw-r--r--tools/validator/human_processor.cpp66
-rw-r--r--tools/validator/structs.h6
-rw-r--r--tools/validator/validator.cpp79
4 files changed, 208 insertions, 20 deletions
diff --git a/tools/assign_ids/main.cpp b/tools/assign_ids/main.cpp index 6eb41e3..e3add66 100644 --- a/tools/assign_ids/main.cpp +++ b/tools/assign_ids/main.cpp
@@ -40,6 +40,7 @@ class AssignIds {
40 ReadIds(ids_path); 40 ReadIds(ids_path);
41 41
42 ProcessMaps(datadir_path); 42 ProcessMaps(datadir_path);
43 ProcessSpecialIds();
43 ProcessProgressivesFile(datadir_path / "progressives.txtpb"); 44 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
44 45
45 WriteIds(ids_path); 46 WriteIds(ids_path);
@@ -72,7 +73,7 @@ class AssignIds {
72 } 73 }
73 74
74 void WriteIds(std::filesystem::path path) { 75 void WriteIds(std::filesystem::path path) {
75 WriteIdsAsYaml(id_mappings_, path.string()); 76 WriteIdsAsYaml(output_, path.string());
76 } 77 }
77 78
78 void ProcessMaps(std::filesystem::path path) { 79 void ProcessMaps(std::filesystem::path path) {
@@ -109,14 +110,18 @@ class AssignIds {
109 return; 110 return;
110 } 111 }
111 112
113 auto& maps = *output_.mutable_maps();
114 auto& doors = *maps[current_map_name].mutable_doors();
115
112 if (!id_mappings_.maps().contains(current_map_name) || 116 if (!id_mappings_.maps().contains(current_map_name) ||
113 !id_mappings_.maps() 117 !id_mappings_.maps()
114 .at(current_map_name) 118 .at(current_map_name)
115 .doors() 119 .doors()
116 .contains(h_door.name())) { 120 .contains(h_door.name())) {
117 auto& maps = *id_mappings_.mutable_maps();
118 auto& doors = *maps[current_map_name].mutable_doors();
119 doors[h_door.name()] = next_id_++; 121 doors[h_door.name()] = next_id_++;
122 } else {
123 doors[h_door.name()] =
124 id_mappings_.maps().at(current_map_name).doors().at(h_door.name());
120 } 125 }
121 } 126 }
122 127
@@ -131,6 +136,10 @@ class AssignIds {
131 void ProcessRoom(const HumanRoom& h_room, 136 void ProcessRoom(const HumanRoom& h_room,
132 const std::string& current_map_name) { 137 const std::string& current_map_name) {
133 for (const HumanPanel& h_panel : h_room.panels()) { 138 for (const HumanPanel& h_panel : h_room.panels()) {
139 auto& maps = *output_.mutable_maps();
140 auto& rooms = *maps[current_map_name].mutable_rooms();
141 auto& panels = *rooms[h_room.name()].mutable_panels();
142
134 if (!id_mappings_.maps().contains(current_map_name) || 143 if (!id_mappings_.maps().contains(current_map_name) ||
135 !id_mappings_.maps() 144 !id_mappings_.maps()
136 .at(current_map_name) 145 .at(current_map_name)
@@ -142,23 +151,33 @@ class AssignIds {
142 .at(h_room.name()) 151 .at(h_room.name())
143 .panels() 152 .panels()
144 .contains(h_panel.name())) { 153 .contains(h_panel.name())) {
145 auto& maps = *id_mappings_.mutable_maps();
146 auto& rooms = *maps[current_map_name].mutable_rooms();
147 auto& panels = *rooms[h_room.name()].mutable_panels();
148 panels[h_panel.name()] = next_id_++; 154 panels[h_panel.name()] = next_id_++;
155 } else {
156 panels[h_panel.name()] = id_mappings_.maps()
157 .at(current_map_name)
158 .rooms()
159 .at(h_room.name())
160 .panels()
161 .at(h_panel.name());
149 } 162 }
150 } 163 }
151 164
152 for (const HumanLetter& h_letter : h_room.letters()) { 165 for (const HumanLetter& h_letter : h_room.letters()) {
153 std::string lettername = GetLetterName(h_letter.key(), h_letter.level2()); 166 std::string lettername = GetLetterName(h_letter.key(), h_letter.level2());
154 167
168 auto& letters = *output_.mutable_letters();
155 if (!id_mappings_.letters().contains(lettername)) { 169 if (!id_mappings_.letters().contains(lettername)) {
156 auto& letters = *id_mappings_.mutable_letters();
157 letters[lettername] = next_id_++; 170 letters[lettername] = next_id_++;
171 } else {
172 letters[lettername] = id_mappings_.letters().at(lettername);
158 } 173 }
159 } 174 }
160 175
161 for (const HumanMastery& h_mastery : h_room.masteries()) { 176 for (const HumanMastery& h_mastery : h_room.masteries()) {
177 auto& maps = *output_.mutable_maps();
178 auto& rooms = *maps[current_map_name].mutable_rooms();
179 auto& masteries = *rooms[h_room.name()].mutable_masteries();
180
162 if (!id_mappings_.maps().contains(current_map_name) || 181 if (!id_mappings_.maps().contains(current_map_name) ||
163 !id_mappings_.maps() 182 !id_mappings_.maps()
164 .at(current_map_name) 183 .at(current_map_name)
@@ -170,17 +189,24 @@ class AssignIds {
170 .at(h_room.name()) 189 .at(h_room.name())
171 .masteries() 190 .masteries()
172 .contains(h_mastery.name())) { 191 .contains(h_mastery.name())) {
173 auto& maps = *id_mappings_.mutable_maps();
174 auto& rooms = *maps[current_map_name].mutable_rooms();
175 auto& masteries = *rooms[h_room.name()].mutable_masteries();
176 masteries[h_mastery.name()] = next_id_++; 192 masteries[h_mastery.name()] = next_id_++;
193 } else {
194 masteries[h_mastery.name()] = id_mappings_.maps()
195 .at(current_map_name)
196 .rooms()
197 .at(h_room.name())
198 .masteries()
199 .at(h_mastery.name());
177 } 200 }
178 } 201 }
179 202
180 for (const HumanEnding& h_ending : h_room.endings()) { 203 for (const HumanEnding& h_ending : h_room.endings()) {
204 auto& endings = *output_.mutable_endings();
205
181 if (!id_mappings_.endings().contains(h_ending.name())) { 206 if (!id_mappings_.endings().contains(h_ending.name())) {
182 auto& endings = *id_mappings_.mutable_endings();
183 endings[h_ending.name()] = next_id_++; 207 endings[h_ending.name()] = next_id_++;
208 } else {
209 endings[h_ending.name()] = id_mappings_.endings().at(h_ending.name());
184 } 210 }
185 } 211 }
186 212
@@ -189,6 +215,10 @@ class AssignIds {
189 continue; 215 continue;
190 } 216 }
191 217
218 auto& maps = *output_.mutable_maps();
219 auto& rooms = *maps[current_map_name].mutable_rooms();
220 auto& keyholders = *rooms[h_room.name()].mutable_keyholders();
221
192 if (!id_mappings_.maps().contains(current_map_name) || 222 if (!id_mappings_.maps().contains(current_map_name) ||
193 !id_mappings_.maps() 223 !id_mappings_.maps()
194 .at(current_map_name) 224 .at(current_map_name)
@@ -200,25 +230,39 @@ class AssignIds {
200 .at(h_room.name()) 230 .at(h_room.name())
201 .keyholders() 231 .keyholders()
202 .contains(h_keyholder.name())) { 232 .contains(h_keyholder.name())) {
203 auto& maps = *id_mappings_.mutable_maps();
204 auto& rooms = *maps[current_map_name].mutable_rooms();
205 auto& keyholders = *rooms[h_room.name()].mutable_keyholders();
206 keyholders[h_keyholder.name()] = next_id_++; 233 keyholders[h_keyholder.name()] = next_id_++;
234 } else {
235 keyholders[h_keyholder.name()] = id_mappings_.maps()
236 .at(current_map_name)
237 .rooms()
238 .at(h_room.name())
239 .keyholders()
240 .at(h_keyholder.name());
207 } 241 }
208 } 242 }
209 } 243 }
210 244
245 void ProcessSpecialIds() {
246 auto& specials = *output_.mutable_special();
247
248 for (const auto& [special_name, ap_id] : id_mappings_.special()) {
249 specials[special_name] = ap_id;
250 }
251 }
252
211 void ProcessProgressivesFile(std::filesystem::path path) { 253 void ProcessProgressivesFile(std::filesystem::path path) {
212 if (!std::filesystem::exists(path)) { 254 if (!std::filesystem::exists(path)) {
213 return; 255 return;
214 } 256 }
215 257
216 auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string()); 258 auto h_progs = ReadMessageFromFile<HumanProgressives>(path.string());
217 auto& progs = *id_mappings_.mutable_progressives(); 259 auto& progs = *output_.mutable_progressives();
218 260
219 for (const HumanProgressive& h_prog : h_progs.progressives()) { 261 for (const HumanProgressive& h_prog : h_progs.progressives()) {
220 if (!progs.contains(h_prog.name())) { 262 if (!id_mappings_.progressives().contains(h_prog.name())) {
221 progs[h_prog.name()] = next_id_++; 263 progs[h_prog.name()] = next_id_++;
264 } else {
265 progs[h_prog.name()] = id_mappings_.progressives().at(h_prog.name());
222 } 266 }
223 } 267 }
224 } 268 }
@@ -237,6 +281,7 @@ class AssignIds {
237 uint64_t next_id_ = 1; 281 uint64_t next_id_ = 1;
238 282
239 IdMappings id_mappings_; 283 IdMappings id_mappings_;
284 IdMappings output_;
240}; 285};
241 286
242} // namespace 287} // namespace
diff --git a/tools/validator/human_processor.cpp b/tools/validator/human_processor.cpp index 49e7578..5720ba9 100644 --- a/tools/validator/human_processor.cpp +++ b/tools/validator/human_processor.cpp
@@ -13,6 +13,7 @@
13#include <string> 13#include <string>
14 14
15#include "structs.h" 15#include "structs.h"
16#include "util/ids_yaml_format.h"
16 17
17namespace com::fourisland::lingo2_archipelago { 18namespace com::fourisland::lingo2_archipelago {
18namespace { 19namespace {
@@ -42,7 +43,7 @@ class HumanProcessor {
42 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt); 43 ProcessConnectionsFile(datadir_path / "connections.txtpb", std::nullopt);
43 ProcessMaps(datadir_path); 44 ProcessMaps(datadir_path);
44 ProcessProgressivesFile(datadir_path / "progressives.txtpb"); 45 ProcessProgressivesFile(datadir_path / "progressives.txtpb");
45 ProcessIdsFile(datadir_path / "ids.txtpb"); 46 ProcessIdsFile(datadir_path / "ids.yaml");
46 } 47 }
47 48
48 private: 49 private:
@@ -510,7 +511,68 @@ class HumanProcessor {
510 } 511 }
511 512
512 void ProcessIdsFile(std::filesystem::path path) { 513 void ProcessIdsFile(std::filesystem::path path) {
513 // Ignore this for now. 514 auto ids = ReadIdsFromYaml(path.string());
515
516 DoorIdentifier di;
517 PanelIdentifier pi;
518 KeyholderIdentifier ki;
519
520 for (const auto& [map_name, map] : ids.maps()) {
521 di.set_map(map_name);
522 pi.set_map(map_name);
523 ki.set_map(map_name);
524
525 for (const auto& [door_name, ap_id] : map.doors()) {
526 di.set_name(door_name);
527
528 DoorInfo& door_info = info_.doors[di];
529 door_info.has_id = true;
530 }
531
532 for (const auto& [room_name, room] : map.rooms()) {
533 pi.set_room(room_name);
534 ki.set_room(room_name);
535
536 for (const auto& [panel_name, ap_id] : room.panels()) {
537 pi.set_name(panel_name);
538
539 PanelInfo& panel_info = info_.panels[pi];
540 panel_info.has_id = true;
541 }
542
543 for (const auto& [mastery_name, ap_id] : room.masteries()) {
544 // TODO: Mastery
545 }
546
547 for (const auto& [keyholder_name, ap_id] : room.keyholders()) {
548 ki.set_name(keyholder_name);
549
550 KeyholderInfo& keyholder_info = info_.keyholders[ki];
551 keyholder_info.has_id = true;
552 }
553 }
554 }
555
556 for (const auto& [tag, id] : ids.special()) {
557 // TODO: Specials
558 }
559
560 for (const auto& [letter_name, ap_id] : ids.letters()) {
561 LetterIdentifier li =
562 std::make_tuple(letter_name[0], letter_name[1] == '2');
563 LetterInfo& letter_info = info_.letters[li];
564 letter_info.has_id = true;
565 }
566
567 for (const auto& [ending_name, ap_id] : ids.endings()) {
568 EndingInfo& ending_info = info_.endings[ending_name];
569 ending_info.has_id = true;
570 }
571
572 for (const auto& [prog_name, ap_id] : ids.progressives()) {
573 ProgressiveInfo& prog_info = info_.progressives[prog_name];
574 prog_info.has_id = true;
575 }
514 } 576 }
515 577
516 std::string mapdir_; 578 std::string mapdir_;
diff --git a/tools/validator/structs.h b/tools/validator/structs.h index 717fccf..e24ed3d 100644 --- a/tools/validator/structs.h +++ b/tools/validator/structs.h
@@ -39,6 +39,7 @@ struct RoomInfo {
39 39
40struct DoorInfo { 40struct DoorInfo {
41 std::vector<HumanDoor> definitions; 41 std::vector<HumanDoor> definitions;
42 bool has_id = false;
42 43
43 std::vector<HumanConnection> connections_referenced_by; 44 std::vector<HumanConnection> connections_referenced_by;
44 std::vector<DoorIdentifier> doors_referenced_by; 45 std::vector<DoorIdentifier> doors_referenced_by;
@@ -72,6 +73,7 @@ struct ProxyInfo {
72 73
73struct PanelInfo { 74struct PanelInfo {
74 std::vector<HumanPanel> definitions; 75 std::vector<HumanPanel> definitions;
76 bool has_id = false;
75 77
76 std::string map_area_name; 78 std::string map_area_name;
77 79
@@ -83,6 +85,7 @@ struct PanelInfo {
83 85
84struct KeyholderInfo { 86struct KeyholderInfo {
85 std::vector<HumanKeyholder> definitions; 87 std::vector<HumanKeyholder> definitions;
88 bool has_id = false;
86 89
87 std::vector<DoorIdentifier> doors_referenced_by; 90 std::vector<DoorIdentifier> doors_referenced_by;
88}; 91};
@@ -91,10 +94,12 @@ using LetterIdentifier = std::tuple<char, bool>;
91 94
92struct LetterInfo { 95struct LetterInfo {
93 std::vector<RoomIdentifier> defined_in; 96 std::vector<RoomIdentifier> defined_in;
97 bool has_id = false;
94}; 98};
95 99
96struct EndingInfo { 100struct EndingInfo {
97 std::vector<RoomIdentifier> defined_in; 101 std::vector<RoomIdentifier> defined_in;
102 bool has_id = false;
98 103
99 std::vector<DoorIdentifier> doors_referenced_by; 104 std::vector<DoorIdentifier> doors_referenced_by;
100}; 105};
@@ -105,6 +110,7 @@ struct PanelNameInfo {
105 110
106struct ProgressiveInfo { 111struct ProgressiveInfo {
107 std::vector<HumanProgressive> definitions; 112 std::vector<HumanProgressive> definitions;
113 bool has_id = false;
108 114
109 std::vector<DoorIdentifier> malformed_doors; 115 std::vector<DoorIdentifier> malformed_doors;
110}; 116};
diff --git a/tools/validator/validator.cpp b/tools/validator/validator.cpp index fd004d7..ab1612e 100644 --- a/tools/validator/validator.cpp +++ b/tools/validator/validator.cpp
@@ -172,6 +172,10 @@ class Validator {
172 door_info.progressives_referenced_by) { 172 door_info.progressives_referenced_by) {
173 std::cout << " PROGRESSIVE " << prog_name << std::endl; 173 std::cout << " PROGRESSIVE " << prog_name << std::endl;
174 } 174 }
175
176 if (door_info.has_id) {
177 std::cout << " An AP ID is present." << std::endl;
178 }
175 } else if (door_info.definitions.size() > 1) { 179 } else if (door_info.definitions.size() > 1) {
176 std::cout << "Door " << door_identifier.ShortDebugString() 180 std::cout << "Door " << door_identifier.ShortDebugString()
177 << " was defined multiple times." << std::endl; 181 << " was defined multiple times." << std::endl;
@@ -215,6 +219,17 @@ class Validator {
215 << " is a location that depends on double_letters." 219 << " is a location that depends on double_letters."
216 << std::endl; 220 << std::endl;
217 } 221 }
222
223 bool needs_id = (h_door.type() != DoorType::EVENT);
224 if (door_info.has_id != needs_id) {
225 if (needs_id) {
226 std::cout << "Door " << door_identifier.ShortDebugString()
227 << " is missing an AP ID." << std::endl;
228 } else {
229 std::cout << "Door " << door_identifier.ShortDebugString()
230 << " should not have an AP ID." << std::endl;
231 }
232 }
218 } 233 }
219 } 234 }
220 235
@@ -280,6 +295,10 @@ class Validator {
280 std::cout << " CONNECTION " << connection.ShortDebugString() 295 std::cout << " CONNECTION " << connection.ShortDebugString()
281 << std::endl; 296 << std::endl;
282 } 297 }
298
299 if (panel_info.has_id) {
300 std::cout << " An AP ID is present." << std::endl;
301 }
283 } else if (panel_info.definitions.size() > 1) { 302 } else if (panel_info.definitions.size() > 1) {
284 std::cout << "Panel " << panel_identifier.ShortDebugString() 303 std::cout << "Panel " << panel_identifier.ShortDebugString()
285 << " was defined multiple times." << std::endl; 304 << " was defined multiple times." << std::endl;
@@ -308,6 +327,11 @@ class Validator {
308 << "\" was defined multiple times." << std::endl; 327 << "\" was defined multiple times." << std::endl;
309 } 328 }
310 } 329 }
330
331 if (!panel_info.has_id) {
332 std::cout << "Panel " << panel_identifier.ShortDebugString()
333 << " is missing an AP ID." << std::endl;
334 }
311 } 335 }
312 336
313 void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier, 337 void ValidateKeyholder(const KeyholderIdentifier& keyholder_identifier,
@@ -321,10 +345,28 @@ class Validator {
321 std::cout << " DOOR " << door_identifier.ShortDebugString() 345 std::cout << " DOOR " << door_identifier.ShortDebugString()
322 << std::endl; 346 << std::endl;
323 } 347 }
348
349 if (keyholder_info.has_id) {
350 std::cout << " An AP ID is present." << std::endl;
351 }
324 } else if (keyholder_info.definitions.size() > 1) { 352 } else if (keyholder_info.definitions.size() > 1) {
325 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString() 353 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
326 << " was defined multiple times." << std::endl; 354 << " was defined multiple times." << std::endl;
327 } 355 }
356
357 for (const HumanKeyholder& h_keyholder : keyholder_info.definitions) {
358 bool needs_id = (h_keyholder.has_key());
359
360 if (needs_id != keyholder_info.has_id) {
361 if (needs_id) {
362 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
363 << " is missing an AP ID." << std::endl;
364 } else {
365 std::cout << "Keyholder " << keyholder_identifier.ShortDebugString()
366 << " should not have an AP ID." << std::endl;
367 }
368 }
369 }
328 } 370 }
329 371
330 void ValidateLetter(const LetterIdentifier& letter_identifier, 372 void ValidateLetter(const LetterIdentifier& letter_identifier,
@@ -332,7 +374,14 @@ class Validator {
332 std::string letter_name = std::string(1, std::get<0>(letter_identifier)) + 374 std::string letter_name = std::string(1, std::get<0>(letter_identifier)) +
333 (std::get<1>(letter_identifier) ? "2" : "1"); 375 (std::get<1>(letter_identifier) ? "2" : "1");
334 376
335 if (letter_info.defined_in.size() > 1) { 377 if (letter_info.defined_in.empty()) {
378 std::cout << "Letter " << letter_name
379 << " has no definition, but was referenced:" << std::endl;
380
381 if (letter_info.has_id) {
382 std::cout << " An AP ID is present." << std::endl;
383 }
384 } else if (letter_info.defined_in.size() > 1) {
336 std::cout << "Letter " << letter_name 385 std::cout << "Letter " << letter_name
337 << " was defined in multiple places:" << std::endl; 386 << " was defined in multiple places:" << std::endl;
338 387
@@ -340,6 +389,11 @@ class Validator {
340 std::cout << " " << room_identifier.ShortDebugString() << std::endl; 389 std::cout << " " << room_identifier.ShortDebugString() << std::endl;
341 } 390 }
342 } 391 }
392
393 if (!letter_info.has_id) {
394 std::cout << "Letter " << letter_name << " is missing an AP ID."
395 << std::endl;
396 }
343 } 397 }
344 398
345 void ValidateEnding(const std::string& ending_name, 399 void ValidateEnding(const std::string& ending_name,
@@ -353,6 +407,10 @@ class Validator {
353 std::cout << " DOOR " << door_identifier.ShortDebugString() 407 std::cout << " DOOR " << door_identifier.ShortDebugString()
354 << std::endl; 408 << std::endl;
355 } 409 }
410
411 if (ending_info.has_id) {
412 std::cout << " An AP ID is present." << std::endl;
413 }
356 } else if (ending_info.defined_in.size() > 1) { 414 } else if (ending_info.defined_in.size() > 1) {
357 std::cout << "Ending " << ending_name 415 std::cout << "Ending " << ending_name
358 << " was defined in multiple places:" << std::endl; 416 << " was defined in multiple places:" << std::endl;
@@ -361,6 +419,11 @@ class Validator {
361 std::cout << " " << room_identifier.ShortDebugString() << std::endl; 419 std::cout << " " << room_identifier.ShortDebugString() << std::endl;
362 } 420 }
363 } 421 }
422
423 if (!ending_info.has_id) {
424 std::cout << "Ending " << ending_name << " is missing an AP ID."
425 << std::endl;
426 }
364 } 427 }
365 428
366 void ValidatePanelName(const std::string& panel_name, 429 void ValidatePanelName(const std::string& panel_name,
@@ -379,10 +442,22 @@ class Validator {
379 442
380 void ValidateProgressive(const std::string& prog_name, 443 void ValidateProgressive(const std::string& prog_name,
381 const ProgressiveInfo& prog_info) const { 444 const ProgressiveInfo& prog_info) const {
382 if (prog_info.definitions.size() > 1) { 445 if (prog_info.definitions.empty()) {
446 std::cout << "Progressive \"" << prog_name
447 << "\" has no definition, but was referenced:" << std::endl;
448
449 if (prog_info.has_id) {
450 std::cout << " An AP ID is present." << std::endl;
451 }
452 } else if (prog_info.definitions.size() > 1) {
383 std::cout << "Progressive \"" << prog_name 453 std::cout << "Progressive \"" << prog_name
384 << "\" has multiple definitions." << std::endl; 454 << "\" has multiple definitions." << std::endl;
385 } 455 }
456
457 if (!prog_info.has_id) {
458 std::cout << "Progressive \"" << prog_name << "\" is missing an AP ID."
459 << std::endl;
460 }
386 } 461 }
387 462
388 const CollectedInfo& info_; 463 const CollectedInfo& info_;