@tikoci/rosetta 0.6.8 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/mcp.ts CHANGED
@@ -186,14 +186,11 @@ const {
186
186
  getSkill,
187
187
  listSkills,
188
188
  lookupProperty,
189
- searchCallouts,
190
189
  searchChangelogs,
191
190
  searchDevices,
192
191
  searchDeviceTests,
193
192
  getTestResultMeta,
194
- searchPages,
195
- searchProperties,
196
- searchVideos,
193
+ searchAll,
197
194
  searchDude,
198
195
  getDudePage,
199
196
  } = await import("./query.ts");
@@ -208,7 +205,7 @@ const server = new McpServer({
208
205
  name: "rosetta",
209
206
  version: RESOLVED_VERSION,
210
207
  }, {
211
- instructions: "RouterOS documentation search. Start with routeros_search for any RouterOS question — it searches across pages, callouts, and properties with BM25 ranking. Drill into specific pages with routeros_get_page (by ID or title). For device hardware specs use routeros_device_lookup; for version-specific command changes use routeros_command_diff. Only v7 data exists (7.9+) — v6 is out of scope and answers will be unreliable.",
208
+ instructions: "RouterOS documentation search. Start with routeros_search for any RouterOS question — it runs a classifier (detects command paths, versions, devices, topics) + BM25 FTS, and returns pages plus a `related` block (command_node, properties, devices, callouts, videos, changelogs, skills) + next-step hints. One call usually answers the question. Drill into specific pages with routeros_get_page; for hardware specs use routeros_device_lookup; for version-specific command changes use routeros_command_diff. Only v7 data exists (7.9+) — v6 is out of scope.",
212
209
  });
213
210
 
214
211
  server.registerResource(
@@ -519,33 +516,43 @@ server.registerResource(
519
516
  server.registerTool(
520
517
  "routeros_search",
521
518
  {
522
- description: `Search RouterOS documentation using natural language.
519
+ description: `Unified RouterOS search start here for any question.
523
520
 
524
- This is the **primary discovery tool**. Start here, then drill down with other tools.
521
+ One call runs an input classifier (command-path, version, device, topic, property)
522
+ and FTS in parallel, returning pages plus classifier-informed side queries in a
523
+ single response. Consolidates what used to require 3–5 separate tool calls.
524
+
525
+ Response shape:
526
+ - classified: { version, topics, command_path, device, property } — what the
527
+ classifier detected from your input
528
+ - pages: top FTS matches (title, path, URL, excerpt, best_section)
529
+ - related: callouts, properties, changelogs, videos, commands, devices, skills —
530
+ each capped at 2–3 entries, empty sections omitted
531
+ - next_steps: concrete follow-up tool calls informed by the classification
525
532
 
526
533
  Capabilities:
527
- - Full-text search with BM25 ranking and Porter stemming
528
- ("configuring" matches "configuration", "configured", etc.)
534
+ - BM25 ranking with Porter stemming ("configuring" matches "configuration")
529
535
  - Proximity matching for compound terms ("firewall filter", "bridge vlan")
530
- - Results include page title, breadcrumb path, help.mikrotik.com URL, and excerpt
531
- - If AND returns nothing, the engine automatically retries with OR
536
+ - Automatic AND OR fallback on empty page results
537
+ - Version/device/topic detection steers related lookups
532
538
 
533
- Workflow what to do next:
534
- → routeros_get_page: retrieve full content for a result (use page ID from results)
535
- routeros_search_properties: find specific properties mentioned in results
536
- routeros_search_callouts: find warnings/notes about topics in results
537
- routeros_command_tree: browse the command hierarchy for a feature
538
- routeros_search_videos: search MikroTik YouTube video transcripts for tutorials and demos
539
+ Drill-down tools (still standalone for specific needs):
540
+ → routeros_get_page: full page content (or section) for any result
541
+ routeros_lookup_property: exact property lookup, optionally filtered by command path
542
+ routeros_command_tree: browse command hierarchy
543
+ routeros_search_changelogs: version range + category + breaking-only filters
544
+ routeros_device_lookup: detailed device specs and test results
545
+ → routeros_command_diff / routeros_command_version_check: version-specific command tracking
539
546
 
540
547
  Tips:
541
548
  - Use specific technical terms: "DHCP relay agent" not "how to set up DHCP"
542
- - For retired Dude GUI or wiki topics, prefer routeros_dude_search; routeros_search covers current RouterOS v7 docs
543
- - Documentation: 317 pages from March 2026 Confluence export (~515K words)
544
- - Docs reflect the then-current long-term release (~7.22), not version-pinned
545
- - Command data: RouterOS 7.9–7.23beta2. No v6 data available.
546
- - v6 had different syntax and subsystems — answers for v6 are unreliable.`,
549
+ - Pass a command path directly ("/ip/firewall/filter") and related.commands +
550
+ related.command_node surface children and linked docs without a second call
551
+ - For retired Dude GUI topics, use routeros_dude_search instead
552
+ - Documentation: 317 pages from March 2026 Confluence export, ~7.22 long-term
553
+ - Command data: RouterOS 7.9–7.23beta2. No v6 data.`,
547
554
  inputSchema: {
548
- query: z.string().describe("Natural language search query"),
555
+ query: z.string().describe("Natural language search query, command path, or identifier"),
549
556
  limit: z
550
557
  .number()
551
558
  .int()
@@ -553,11 +560,11 @@ Tips:
553
560
  .max(50)
554
561
  .optional()
555
562
  .default(8)
556
- .describe("Max results (default 8)"),
563
+ .describe("Max page results (default 8). Related sections are always capped at 2–3."),
557
564
  },
558
565
  },
559
566
  async ({ query, limit }) => {
560
- const result = searchPages(query, limit);
567
+ const result = searchAll(query, limit);
561
568
  return {
562
569
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
563
570
  };
@@ -579,23 +586,25 @@ Callouts contain crucial caveats and edge-case details — always review them.
579
586
 
580
587
  **Large page handling:** max_length defaults to 16000. When page content exceeds it,
581
588
  pages with sections return a **table of contents** instead of truncated text.
582
- The TOC lists each section's heading, hierarchy level, character count, and
583
- deep-link URL. Re-call with the section parameter to retrieve specific sections.
589
+ The TOC response surfaces high-signal content up front so you rarely need a
590
+ second call: top **properties** (name + type + description), **related_videos**
591
+ (FTS match on page title), callout_summary (count by type), and the section list
592
+ (heading, level, char_count, deep-link URL). Re-call with the section parameter
593
+ for full section text.
584
594
 
585
595
  **Section parameter:** Pass a section heading or anchor_id (from the TOC)
586
596
  to get that section's content. If a section is still too large, its sub-section
587
597
  TOC is returned instead — request a more specific sub-section.
588
598
 
589
599
  Recommended workflow for large pages:
590
- 1. First call → get TOC if page is large (automatic with default max_length)
591
- 2. Review section headings to find the relevant section
592
- 3. Call again with section="Section Name" to get that section's content
600
+ 1. First call → get TOC (+ properties, related_videos, callout_summary)
601
+ 2. Answer directly if the surfaced signal is enough
602
+ 3. Otherwise call again with section="Section Name" for specific content
593
603
 
594
604
  Workflow — what to do with this content:
595
- → routeros_search_properties: look up specific properties mentioned in text
596
605
  → routeros_lookup_property: get exact details for a named property
597
- routeros_search_callouts: find related warnings across other pages
598
- routeros_command_tree: browse the command path for features on this page`,
606
+ routeros_command_tree: browse the command path for features on this page
607
+ routeros_search: related warnings, video segments, and device specs now surface via search's related block`,
599
608
  inputSchema: {
600
609
  page: z
601
610
  .string()
@@ -637,8 +646,8 @@ Returns type, default value, description, and documentation page.
637
646
  Optionally filter by command path to disambiguate (e.g., "disabled" appears everywhere).
638
647
 
639
648
  This requires the **exact property name**. If you don't know the name:
640
- routeros_search_properties: full-text search across property descriptions
641
- routeros_search: find the documentation page, then read it with routeros_get_page
649
+ routeros_search: find the documentation page, then routeros_get_page to read properties in context
650
+ routeros_command_tree: browse args at the command path to discover property names
642
651
 
643
652
  Examples:
644
653
  - name: "add-default-route" → DHCP client property
@@ -660,7 +669,7 @@ Examples:
660
669
  content: [
661
670
  {
662
671
  type: "text",
663
- text: `No property found: "${name}"${command_path ? ` under ${command_path}` : ""}\n\nTry instead:\n- routeros_search_properties with a keyword from the property description\n- routeros_search to find the documentation page, then routeros_get_page to read it\n- routeros_command_tree at the command path to see available args`,
672
+ text: `No property found: "${name}"${command_path ? ` under ${command_path}` : ""}\n\nTry instead:\n- routeros_search to find the documentation page, then routeros_get_page to read properties in context\n- routeros_command_tree at the command path to see available args`,
664
673
  },
665
674
  ],
666
675
  };
@@ -671,51 +680,6 @@ Examples:
671
680
  },
672
681
  );
673
682
 
674
- // ---- routeros_search_properties ----
675
-
676
- server.registerTool(
677
- "routeros_search_properties",
678
- {
679
- description: `Search RouterOS properties by name or description text.
680
-
681
- Full-text search across 4,860 property names and descriptions from 145 pages.
682
- Use when you don't know the exact property name but know what it does.
683
- If AND returns nothing, the engine automatically retries with OR.
684
-
685
- If this returns empty:
686
- → routeros_search: find the documentation page containing the feature
687
- → routeros_get_page: read the page — properties are embedded in page text
688
- → routeros_command_tree: browse args at a command path for property names
689
-
690
- Examples:
691
- - "gateway reachability check" → finds check-gateway properties
692
- - "snooping" → finds dhcp-snooping, igmp-snooping properties
693
- - "trusted" → finds bridge port trusted property`,
694
- inputSchema: {
695
- query: z.string().describe("Search query for property descriptions"),
696
- limit: z
697
- .number()
698
- .int()
699
- .min(1)
700
- .max(50)
701
- .optional()
702
- .default(10)
703
- .describe("Max results (default 10)"),
704
- },
705
- },
706
- async ({ query, limit }) => {
707
- const results = searchProperties(query, limit);
708
- if (results.length === 0) {
709
- return {
710
- content: [{ type: "text", text: `No properties matched: "${query}"\n\nTry instead:\n- routeros_search to find the documentation page containing this feature\n- routeros_get_page to read properties directly from page text\n- routeros_command_tree to browse args at the command path\n- Shorter/different keywords (property descriptions are brief)` }],
711
- };
712
- }
713
- return {
714
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
715
- };
716
- },
717
- );
718
-
719
683
  // ---- routeros_command_tree ----
720
684
 
721
685
  server.registerTool(
@@ -735,7 +699,6 @@ Workflow — combine with other tools:
735
699
  → routeros_get_page: read the linked documentation page for a command
736
700
  → routeros_lookup_property: look up arg names as properties for details
737
701
  → routeros_command_version_check: check when a command was added
738
- → routeros_search_properties: search for properties under this path
739
702
 
740
703
  Examples:
741
704
  - path: "/ip" → address, arp, dhcp-client, dhcp-server, firewall, route, etc.
@@ -814,54 +777,6 @@ Knowledge boundaries:
814
777
  },
815
778
  );
816
779
 
817
- // ---- routeros_search_callouts ----
818
-
819
- server.registerTool(
820
- "routeros_search_callouts",
821
- {
822
- description: `Search note, warning, tip, and info callout blocks across all RouterOS documentation.
823
-
824
- 1,034 callouts containing important caveats, edge cases, and non-obvious behavior.
825
- Useful for finding warnings about hardware offloading, compatibility notes,
826
- or unexpected feature interactions that aren't obvious from main page text.
827
-
828
- Query tips:
829
- - Use SHORT keyword queries (1-2 terms). Callouts are brief — multi-word NL phrases often miss.
830
- - "bridge" finds more than "bridge VLAN spanning tree conflict"
831
- - Pass type only (no query) to browse callouts of that type
832
- - If AND finds nothing, the engine automatically retries with OR
833
-
834
- Optionally filter by callout type: "note" (426), "info" (357), "warning" (213), or "tip" (38).
835
-
836
- Examples:
837
- - query: "hardware offload" → warnings about bridge HW offloading limitations
838
- - query: "VLAN", type: "warning" → only VLAN-related warnings
839
- - query: "bridge", type: "warning" → bridge-related warnings
840
- - type: "warning", limit: 20 → browse 20 warnings (no search term needed)`,
841
- inputSchema: {
842
- query: z.string().optional().default("").describe("Search keywords for callout content (keep short — 1-2 terms work best)"),
843
- type: z
844
- .enum(["note", "warning", "info", "tip"])
845
- .optional()
846
- .describe("Filter by callout type"),
847
- limit: z
848
- .number()
849
- .int()
850
- .min(1)
851
- .max(50)
852
- .optional()
853
- .default(10)
854
- .describe("Max results (default 10)"),
855
- },
856
- },
857
- async ({ query, type, limit }) => {
858
- const results = searchCallouts(query, type, limit);
859
- return {
860
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
861
- };
862
- },
863
- );
864
-
865
780
  // ---- routeros_search_changelogs ----
866
781
 
867
782
  /** Group flat changelog results by version for compact output. */
@@ -899,8 +814,7 @@ Entries marked !) are breaking changes that may require config adjustments after
899
814
  1. Search changelogs with from_version=A, to_version=B, and the subsystem as query
900
815
  2. Look for !) breaking changes that explain the behavior change
901
816
  3. → routeros_get_page for the subsystem's documentation
902
- 4. → routeros_search_callouts for version-specific warnings
903
- 5. → routeros_command_version_check to see if commands were added/removed
817
+ 4. → routeros_command_version_check to see if commands were added/removed
904
818
 
905
819
  Supports: FTS keyword search, version range filtering, category filtering, breaking-only mode.
906
820
  Categories are subsystem names: bgp, bridge, dhcpv4-server, wifi, ipsec, console, container, etc.
@@ -960,7 +874,7 @@ Coverage depends on which versions were extracted — typically matches ros_vers
960
874
  from_version || to_version ? "Try widening the version range" : null,
961
875
  category ? `Try without category filter, or check spelling (categories are lowercase: bgp, bridge, wifi, etc.)` : null,
962
876
  breaking_only ? "Try without breaking_only — the change may not be marked as breaking" : null,
963
- "Use routeros_search or routeros_search_callouts for documentation-based answers",
877
+ "Use routeros_search for documentation-based answers — callouts and videos surface in its related block",
964
878
  ].filter(Boolean);
965
879
  return {
966
880
  content: [
@@ -979,56 +893,6 @@ Coverage depends on which versions were extracted — typically matches ros_vers
979
893
  },
980
894
  );
981
895
 
982
- // ---- routeros_search_videos ----
983
-
984
- server.registerTool(
985
- "routeros_search_videos",
986
- {
987
- description: `Search MikroTik YouTube video transcripts for RouterOS topics.
988
-
989
- Searches chapter-level transcript segments from official MikroTik YouTube videos.
990
- Returns matching segments with video title, URL, chapter name, and an excerpt.
991
- Auto-caption quality varies — short config snippets may not appear verbatim.
992
-
993
- MUM conference talks are excluded (those are long, off-topic lectures).
994
- Results include the video URL and start timestamp for direct chapter linking.
995
-
996
- Useful for: finding tutorial walkthroughs, feature announcements, demo configs,
997
- and explanations that complement the text documentation.
998
-
999
- → routeros_search: search official text documentation (more precise for property names)
1000
- → routeros_get_page: read full documentation page for a topic
1001
- → routeros_search_callouts: find Warnings/Notes embedded in documentation`,
1002
- inputSchema: {
1003
- query: z.string().describe("Topic to search for in video transcripts (e.g., 'VLAN trunking', 'BGP route reflection')"),
1004
- limit: z
1005
- .number()
1006
- .int()
1007
- .min(1)
1008
- .max(20)
1009
- .default(5)
1010
- .optional()
1011
- .describe("Max results (1–20, default 5)"),
1012
- },
1013
- },
1014
- async ({ query, limit }) => {
1015
- const results = searchVideos(query, limit ?? 5);
1016
- if (results.length === 0) {
1017
- return {
1018
- content: [
1019
- {
1020
- type: "text",
1021
- text: `No video transcript results for: "${query}"\n\nTry:\n- Broader or simpler search terms\n- routeros_search for official documentation\n- routeros_search_callouts for Notes and Warnings in docs`,
1022
- },
1023
- ],
1024
- };
1025
- }
1026
- return {
1027
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
1028
- };
1029
- },
1030
- );
1031
-
1032
896
  // ---- routeros_dude_search ----
1033
897
 
1034
898
  server.registerTool(
@@ -1137,8 +1001,8 @@ Useful for answering "is /container supported in 7.12?" or "when was /ip/firewal
1137
1001
 
1138
1002
  Command data covers versions 7.9–7.23beta2. No v6 data.
1139
1003
  For versions below 7.9, no command tree data exists — the command may still exist there.
1140
- Cross-reference with routeros_get_page or routeros_search_callouts for version mentions
1141
- in documentation text. → routeros_search_changelogs to see what changed between versions.
1004
+ Cross-reference with routeros_get_page for version mentions in documentation text (callouts
1005
+ surface in routeros_search's related block). → routeros_search_changelogs to see what changed between versions.
1142
1006
 
1143
1007
  Examples:
1144
1008
  - command_path: "/container" → shows versions where container support exists
package/src/query.test.ts CHANGED
@@ -37,6 +37,9 @@ const {
37
37
  listSkills,
38
38
  getSkill,
39
39
  getSkillReference,
40
+ lookupGlossary,
41
+ listGlossary,
42
+ KNOWN_TOPICS,
40
43
  } = await import("./query.ts");
41
44
  const { parseChangelog } = await import("./extract-changelogs.ts");
42
45
  const { parseVtt, segmentTranscript } = await import("./extract-videos.ts");
@@ -48,6 +51,31 @@ const { parseVtt, segmentTranscript } = await import("./extract-videos.ts");
48
51
  beforeAll(() => {
49
52
  initDb();
50
53
 
54
+ // Keep this test deterministic even if another test file initialized db.ts first
55
+ // against a non-empty DB (e.g., workflow-generated ros-help.db).
56
+ db.run("PRAGMA foreign_keys=OFF;");
57
+ db.run("DELETE FROM skill_references");
58
+ db.run("DELETE FROM skills");
59
+ db.run("DELETE FROM dude_images");
60
+ db.run("DELETE FROM dude_pages");
61
+ db.run("DELETE FROM video_segments");
62
+ db.run("DELETE FROM videos");
63
+ db.run("DELETE FROM changelogs");
64
+ db.run("DELETE FROM device_test_results");
65
+ db.run("DELETE FROM devices");
66
+ db.run("DELETE FROM schema_node_presence");
67
+ db.run("DELETE FROM schema_nodes");
68
+ db.run("DELETE FROM command_versions");
69
+ db.run("DELETE FROM commands");
70
+ db.run("DELETE FROM ros_versions");
71
+ db.run("DELETE FROM sections");
72
+ db.run("DELETE FROM callouts");
73
+ db.run("DELETE FROM properties");
74
+ db.run("DELETE FROM pages");
75
+ // Reset autoincrement counters so fixture IDs are deterministic
76
+ db.run("DELETE FROM sqlite_sequence");
77
+ db.run("PRAGMA foreign_keys=ON;");
78
+
51
79
  db.run(`INSERT INTO pages
52
80
  (id, slug, title, path, depth, parent_id, url, text, code, code_lang,
53
81
  author, last_updated, word_count, code_lines, html_file)
@@ -1935,3 +1963,104 @@ describe("getDudePage", () => {
1935
1963
  expect(getDudePage("NonExistent")).toBeNull();
1936
1964
  });
1937
1965
  });
1966
+
1967
+ // ---------------------------------------------------------------------------
1968
+ // KNOWN_TOPICS
1969
+ // ---------------------------------------------------------------------------
1970
+
1971
+ describe("KNOWN_TOPICS", () => {
1972
+ test("contains core RouterOS subsystems", () => {
1973
+ expect(KNOWN_TOPICS.has("firewall")).toBe(true);
1974
+ expect(KNOWN_TOPICS.has("bridge")).toBe(true);
1975
+ expect(KNOWN_TOPICS.has("bgp")).toBe(true);
1976
+ expect(KNOWN_TOPICS.has("ospf")).toBe(true);
1977
+ expect(KNOWN_TOPICS.has("container")).toBe(true);
1978
+ expect(KNOWN_TOPICS.has("wifi")).toBe(true);
1979
+ expect(KNOWN_TOPICS.has("ipsec")).toBe(true);
1980
+ expect(KNOWN_TOPICS.has("dns")).toBe(true);
1981
+ });
1982
+
1983
+ test("contains changelog-derived categories", () => {
1984
+ expect(KNOWN_TOPICS.has("winbox")).toBe(true);
1985
+ expect(KNOWN_TOPICS.has("hotspot")).toBe(true);
1986
+ expect(KNOWN_TOPICS.has("lte")).toBe(true);
1987
+ expect(KNOWN_TOPICS.has("wireguard")).toBe(true);
1988
+ expect(KNOWN_TOPICS.has("zerotier")).toBe(true);
1989
+ });
1990
+
1991
+ test("contains top-level command paths", () => {
1992
+ expect(KNOWN_TOPICS.has("ip")).toBe(true);
1993
+ expect(KNOWN_TOPICS.has("system")).toBe(true);
1994
+ expect(KNOWN_TOPICS.has("interface")).toBe(true);
1995
+ expect(KNOWN_TOPICS.has("app")).toBe(true);
1996
+ });
1997
+
1998
+ test("does not contain stop words", () => {
1999
+ expect(KNOWN_TOPICS.has("the")).toBe(false);
2000
+ expect(KNOWN_TOPICS.has("how")).toBe(false);
2001
+ expect(KNOWN_TOPICS.has("configure")).toBe(false);
2002
+ });
2003
+
2004
+ test("has reasonable size (80-200 entries)", () => {
2005
+ expect(KNOWN_TOPICS.size).toBeGreaterThanOrEqual(80);
2006
+ expect(KNOWN_TOPICS.size).toBeLessThanOrEqual(200);
2007
+ });
2008
+ });
2009
+
2010
+ // ---------------------------------------------------------------------------
2011
+ // Glossary
2012
+ // ---------------------------------------------------------------------------
2013
+
2014
+ describe("lookupGlossary", () => {
2015
+ test("finds exact term match", () => {
2016
+ const result = lookupGlossary("chr");
2017
+ expect(result).not.toBeNull();
2018
+ expect(result!.term).toBe("chr");
2019
+ expect(result!.definition).toContain("Cloud Hosted Router");
2020
+ expect(result!.category).toBe("product");
2021
+ });
2022
+
2023
+ test("case-insensitive lookup", () => {
2024
+ const result = lookupGlossary("CHR");
2025
+ expect(result).not.toBeNull();
2026
+ expect(result!.term).toBe("chr");
2027
+ });
2028
+
2029
+ test("finds term by alias", () => {
2030
+ const result = lookupGlossary("openvpn");
2031
+ expect(result).not.toBeNull();
2032
+ expect(result!.term).toBe("ovpn");
2033
+ });
2034
+
2035
+ test("returns null for unknown term", () => {
2036
+ expect(lookupGlossary("nonexistentterm")).toBeNull();
2037
+ });
2038
+
2039
+ test("returns null for empty input", () => {
2040
+ expect(lookupGlossary("")).toBeNull();
2041
+ });
2042
+
2043
+ test("search_hint field is populated", () => {
2044
+ const result = lookupGlossary("capsman");
2045
+ expect(result).not.toBeNull();
2046
+ expect(result!.search_hint).toBeTruthy();
2047
+ expect(result!.search_hint).toContain("CAPsMAN");
2048
+ });
2049
+ });
2050
+
2051
+ describe("listGlossary", () => {
2052
+ test("returns all entries when no category", () => {
2053
+ const entries = listGlossary();
2054
+ expect(entries.length).toBeGreaterThanOrEqual(40);
2055
+ });
2056
+
2057
+ test("filters by category", () => {
2058
+ const products = listGlossary("product");
2059
+ expect(products.length).toBeGreaterThan(0);
2060
+ expect(products.every(e => e.category === "product")).toBe(true);
2061
+ });
2062
+
2063
+ test("returns empty for non-existent category", () => {
2064
+ expect(listGlossary("nonexistent")).toEqual([]);
2065
+ });
2066
+ });