From e5e5d327a2c880360e9d858de66718c2a122b09f Mon Sep 17 00:00:00 2001 From: TotallyNot <44345987+TotallyNot@users.noreply.github.com> Date: Thu, 24 Apr 2025 23:39:08 +0200 Subject: [PATCH] chore(codegen): updated spec and improved builder ergonomics --- Cargo.lock | 2 +- torn-api-codegen/Cargo.toml | 2 +- torn-api-codegen/openapi.json | 5657 ++++++++++++++++++++++- torn-api-codegen/src/model/enum.rs | 65 +- torn-api-codegen/src/model/object.rs | 2 +- torn-api-codegen/src/model/parameter.rs | 14 + torn-api-codegen/src/model/path.rs | 46 +- torn-api/src/scopes.rs | 285 +- 8 files changed, 5959 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eceb0f2..7753c64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1228,7 +1228,7 @@ dependencies = [ [[package]] name = "torn-api-codegen" -version = "0.1.0" +version = "0.1.1" dependencies = [ "heck", "indexmap", diff --git a/torn-api-codegen/Cargo.toml b/torn-api-codegen/Cargo.toml index 63e7107..4d90373 100644 --- a/torn-api-codegen/Cargo.toml +++ b/torn-api-codegen/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "torn-api-codegen" authors = ["Pyrit [2111649]"] -version = "0.1.0" +version = "0.1.1" edition = "2024" description = "Contains the v2 torn API model descriptions and codegen for the bindings" license-file = { workspace = true } diff --git a/torn-api-codegen/openapi.json b/torn-api-codegen/openapi.json index 289075b..9336cd2 100644 --- a/torn-api-codegen/openapi.json +++ b/torn-api-codegen/openapi.json @@ -2,8 +2,8 @@ "openapi": "3.1.0", "info": { "title": "Torn API", - "description": "\n * The development of Torn's API v2 is still ongoing.\n * If selections remain unaltered, they will default to the API v1 version.\n * Unlike API v1, API v2 accepts both selections and IDs as path and query parameters.\n * If any discrepancies or errors are found, please submit a [bug report](https://www.torn.com/forums.php#/p=forums&f=19&b=0&a=0) on the Torn Forums.", - "version": "1.1.0" + "description": "\n * The development of Torn's API v2 is still ongoing.\n * If selections remain unaltered, they will default to the API v1 version.\n * Unlike API v1, API v2 accepts both selections and IDs as path and query parameters.\n * If any discrepancies or errors are found, please submit a [bug report](https://www.torn.com/forums.php#/p=forums&f=19&b=0&a=0) on the Torn Forums.\n * In case you're using bots to check for changes on openapi.json file, make sure to specificy a custom user-agent header - CloudFlare sometimes prevents requests from default user-agents.", + "version": "1.3.1" }, "servers": [ { @@ -200,7 +200,7 @@ "description": "Crime id", "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/TornCrimeId" } } ], @@ -224,6 +224,33 @@ "x-stability": "Stable" } }, + "/user/education": { + "get": { + "tags": [ + "User" + ], + "summary": "Get your education information", + "description": "The response contains a list of complete eduactions and of a current education (if any).", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserEducationResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/user/enlistedcars": { "get": { "tags": [ @@ -1180,12 +1207,24 @@ { "$ref": "#/components/schemas/UserCalendarResponse" }, + { + "$ref": "#/components/schemas/UserEducationResponse" + }, { "$ref": "#/components/schemas/UserBountiesResponse" }, { "$ref": "#/components/schemas/UserJobRanksResponse" }, + { + "$ref": "#/components/schemas/UserFactionBalanceResponse" + }, + { + "$ref": "#/components/schemas/RevivesResponse" + }, + { + "$ref": "#/components/schemas/RevivesFullResponse" + }, { "$ref": "#/components/schemas/UserItemMarketResponse" }, @@ -1757,7 +1796,7 @@ "x-stability": "Stable" } }, - "/faction/{id}/crime": { + "/faction/{crimeId}/crime": { "get": { "tags": [ "Faction" @@ -1766,12 +1805,12 @@ "description": "Requires minimal access key with faction API access permissions.
", "parameters": [ { - "name": "id", + "name": "crimeId", "in": "path", "description": "Crime id", "required": true, "schema": { - "$ref": "#/components/schemas/ItemId" + "$ref": "#/components/schemas/FactionCrimeId" } } ], @@ -1986,6 +2025,60 @@ "x-stability": "Stable" } }, + "/faction/positions": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get your faction's positions details", + "description": "Requires minimal access key with faction API access permissions.
", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionPositionsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/rackets": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a list of current rackets", + "description": "Requires public access key.
", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionRacketsReponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/faction/rankedwars": { "get": { "tags": [ @@ -1997,7 +2090,6 @@ { "name": "cat", "in": "query", - "description": "Stats category. Required unless requesting specific stats via 'stat' query parameter", "required": false, "schema": { "$ref": "#/components/schemas/FactionRankedWarsCategoryEnum" @@ -2071,7 +2163,7 @@ "x-stability": "Stable" } }, - "/faction/{id}/rankedwarreport": { + "/faction/{rankedWarId}/rankedwarreport": { "get": { "tags": [ "Faction" @@ -2080,7 +2172,7 @@ "description": "Requires public access key.
", "parameters": [ { - "name": "id", + "name": "rankedWarId", "in": "path", "description": "Ranked war id", "required": true, @@ -2224,6 +2316,231 @@ "x-stability": "Unstable" } }, + "/faction/territory": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a list of your faction's territories", + "description": "Requires public access key.
", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoriesReponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/{id}/territory": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a list of a faction's territories", + "description": "Requires public access key.
", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Faction id", + "required": true, + "schema": { + "$ref": "#/components/schemas/FactionId" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoriesReponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/territoryownership": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a list of your faction's territories", + "description": "Requires public access key.
", + "parameters": [ + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit500Default20" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoriesOwnershipResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/territorywars": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get territory wars list", + "description": "Requires public access key.
When category 'finished' is chosen, you can use 'from', 'to' & 'sort' query parameters.
When category 'ongoing' is chosen, all currently active territory wars are returned.
When no category is chosen, this selection will return territory war history of your own faction (if any).", + "parameters": [ + { + "name": "cat", + "in": "query", + "required": false, + "schema": { + "$ref": "#/components/schemas/FactionTerritoryWarsCategoryEnum" + } + }, + { + "$ref": "#/components/parameters/ApiFrom" + }, + { + "$ref": "#/components/parameters/ApiTo" + }, + { + "$ref": "#/components/parameters/ApiSortDesc" + }, + { + "$ref": "#/components/parameters/ApiLimit100" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoryWarsResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/{id}/territorywars": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get a faction's territory wars history", + "description": "Requires public access key.
", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "Faction id", + "required": true, + "schema": { + "$ref": "#/components/schemas/FactionId" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoryWarsHistoryResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/faction/{territoryWarId}/territorywarreport": { + "get": { + "tags": [ + "Faction" + ], + "summary": "Get territory war details", + "description": "Requires public access key.
", + "parameters": [ + { + "name": "territoryWarId", + "in": "path", + "description": "Territory war id", + "required": true, + "schema": { + "$ref": "#/components/schemas/TerritoryWarId" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FactionTerritoryWarReportResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/faction/upgrades": { "get": { "tags": [ @@ -2459,9 +2776,27 @@ { "$ref": "#/components/schemas/FactionNewsResponse" }, + { + "$ref": "#/components/schemas/RevivesResponse" + }, + { + "$ref": "#/components/schemas/FactionTerritoryWarsHistoryResponse" + }, { "$ref": "#/components/schemas/FactionAttacksResponse" }, + { + "$ref": "#/components/schemas/FactionBalanceResponse" + }, + { + "$ref": "#/components/schemas/FactionTerritoriesOwnershipResponse" + }, + { + "$ref": "#/components/schemas/FactionPositionsResponse" + }, + { + "$ref": "#/components/schemas/RevivesFullResponse" + }, { "$ref": "#/components/schemas/FactionAttacksFullResponse" }, @@ -2486,15 +2821,30 @@ { "$ref": "#/components/schemas/FactionRankedWarReportResponse" }, + { + "$ref": "#/components/schemas/FactionTerritoryWarReportResponse" + }, + { + "$ref": "#/components/schemas/FactionTerritoriesReponse" + }, { "$ref": "#/components/schemas/FactionUpgradesResponse" }, { "$ref": "#/components/schemas/FactionStatsResponse" }, + { + "$ref": "#/components/schemas/FactionTerritoryWarsResponse" + }, { "$ref": "#/components/schemas/FactionContributorsResponse" }, + { + "$ref": "#/components/schemas/FactionRacketsReponse" + }, + { + "$ref": "#/components/schemas/FactionRankedWarResponse" + }, { "$ref": "#/components/schemas/FactionLookupResponse" }, @@ -3459,7 +3809,7 @@ "description": "Code of the attack log. E.g. d51ad4fe6be884b309b142e2d1d4f807", "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/AttackCode" } }, { @@ -3581,6 +3931,33 @@ "x-stability": "Stable" } }, + "/torn/education": { + "get": { + "tags": [ + "Torn" + ], + "summary": "Get education information", + "description": "Requires public access key.
", + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TornEducationResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/torn/factionhof": { "get": { "tags": [ @@ -3940,7 +4317,7 @@ "description": "Crime id", "required": true, "schema": { - "type": "string" + "$ref": "#/components/schemas/TornCrimeId" } } ], @@ -3964,6 +4341,81 @@ "x-stability": "Stable" } }, + "/torn/territory": { + "get": { + "tags": [ + "Torn" + ], + "summary": "Get territory details", + "description": "Requires public access key.
", + "parameters": [ + { + "$ref": "#/components/parameters/ApiOffset" + }, + { + "$ref": "#/components/parameters/ApiLimit250Default20" + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TornTerritoriesResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, + "/torn/{territoryIds}/territory": { + "get": { + "tags": [ + "Torn" + ], + "summary": "Get territory details", + "description": "Requires public access key.
", + "parameters": [ + { + "name": "territoryIds", + "in": "path", + "description": "Territory id or a list of territory ids (comma separated)", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TornTerritoriesResponse" + } + } + } + } + }, + "security": [ + { + "api_key": [] + } + ], + "x-stability": "Unstable" + } + }, "/torn/lookup": { "get": { "tags": [ @@ -4056,22 +4508,13 @@ "$ref": "#/components/parameters/ApiLimit" }, { - "name": "to", - "in": "query", - "description": "Timestamp until when rows are returned", - "required": false, - "schema": { - "type": "integer" - } + "$ref": "#/components/parameters/ApiTo" }, { - "name": "from", - "in": "query", - "description": "Timestamp after when rows are returned", - "required": false, - "schema": { - "type": "integer" - } + "$ref": "#/components/parameters/ApiFrom" + }, + { + "$ref": "#/components/parameters/ApiSort" }, { "name": "cat", @@ -4082,19 +4525,6 @@ "type": "string" } }, - { - "name": "sort", - "in": "query", - "description": "Direction to sort rows in", - "required": false, - "schema": { - "type": "string", - "enum": [ - "DESC", - "ASC" - ] - } - }, { "$ref": "#/components/parameters/ApiOffsetNoDefault" } @@ -4124,9 +4554,15 @@ { "$ref": "#/components/schemas/TornLogTypesResponse" }, + { + "$ref": "#/components/schemas/TornItemsResponse" + }, { "$ref": "#/components/schemas/TornLogCategoriesResponse" }, + { + "$ref": "#/components/schemas/TornEducationResponse" + }, { "$ref": "#/components/schemas/TornBountiesResponse" }, @@ -4136,6 +4572,15 @@ { "$ref": "#/components/schemas/TornFactionTreeResponse" }, + { + "$ref": "#/components/schemas/AttackLogResponse" + }, + { + "$ref": "#/components/schemas/TornTerritoriesResponse" + }, + { + "$ref": "#/components/schemas/TornTerritoriesNoLinksReponse" + }, { "$ref": "#/components/schemas/TornItemModsResponse" }, @@ -4172,6 +4617,4118 @@ "E" ] }, + "FactionTerritoryEnum": { + "type": "string", + "enum": [ + "AAB", + "AAC", + "AAD", + "AAE", + "AAF", + "AAG", + "ABA", + "ABB", + "ABC", + "ABD", + "ABE", + "ABF", + "ACA", + "ACB", + "ACC", + "ACD", + "ACE", + "ACF", + "ACG", + "ADA", + "ADB", + "ADC", + "ADD", + "ADE", + "ADF", + "ADG", + "AEA", + "AEB", + "AEC", + "AED", + "AEE", + "AEF", + "AFA", + "AFB", + "AFC", + "AFD", + "AFE", + "AFF", + "AFG", + "AGA", + "AGB", + "AGC", + "AGD", + "AGE", + "AGF", + "AGG", + "AHA", + "AHB", + "AHC", + "AHD", + "AHE", + "AHF", + "AIA", + "AIB", + "AIC", + "AID", + "AIE", + "AIF", + "AJA", + "AJB", + "AJC", + "AJD", + "AJE", + "AJF", + "AKA", + "AKB", + "AKC", + "AKD", + "AKE", + "AKF", + "ALA", + "ALB", + "ALC", + "ALD", + "ALE", + "ALF", + "AMA", + "AMB", + "AMC", + "AMD", + "AME", + "AMF", + "ANB", + "ANC", + "AND", + "ANE", + "ANF", + "ANG", + "AOB", + "AOC", + "AOD", + "AOE", + "AOF", + "AOG", + "APB", + "APC", + "APD", + "APE", + "APF", + "APG", + "AQB", + "AQC", + "AQD", + "AQE", + "AQF", + "AQG", + "ARB", + "ARC", + "ARD", + "ARE", + "ARF", + "ASB", + "ASC", + "ASD", + "ASE", + "ASF", + "ASG", + "ATB", + "ATC", + "ATD", + "ATE", + "ATF", + "ATG", + "AUB", + "AUC", + "AUD", + "AUE", + "AUF", + "AUG", + "AVB", + "AVC", + "AVD", + "AVE", + "AVF", + "AVG", + "AWB", + "AWC", + "AWD", + "AWE", + "AWF", + "AWG", + "AXB", + "AXC", + "AXD", + "AXE", + "AXF", + "AXG", + "AYB", + "AYC", + "AYD", + "AYE", + "AYF", + "AYG", + "AZB", + "AZC", + "AZD", + "AZE", + "AZF", + "AZG", + "BAA", + "BAB", + "BAC", + "BAD", + "BAE", + "BAF", + "BAG", + "BBA", + "BBB", + "BBC", + "BBD", + "BBE", + "BBF", + "BBG", + "BCA", + "BCB", + "BCC", + "BCD", + "BCE", + "BCF", + "BCG", + "BDA", + "BDB", + "BDC", + "BDD", + "BDE", + "BDF", + "BDG", + "BEA", + "BEB", + "BEC", + "BED", + "BEE", + "BEF", + "BFA", + "BFB", + "BFC", + "BFD", + "BFE", + "BFF", + "BFG", + "BGA", + "BGB", + "BGC", + "BGD", + "BGE", + "BGF", + "BGG", + "BHA", + "BHB", + "BHC", + "BHD", + "BHE", + "BHF", + "BIA", + "BIB", + "BIC", + "BID", + "BIE", + "BIF", + "BJA", + "BJB", + "BJC", + "BJD", + "BJE", + "BJF", + "BKA", + "BKB", + "BKC", + "BKD", + "BKE", + "BKF", + "BLA", + "BLB", + "BLC", + "BLD", + "BLE", + "BLF", + "BMA", + "BMB", + "BMC", + "BMD", + "BME", + "BMF", + "BNB", + "BNC", + "BND", + "BNE", + "BNF", + "BNG", + "BOB", + "BOC", + "BOD", + "BOE", + "BOF", + "BPB", + "BPC", + "BPD", + "BPE", + "BPF", + "BPG", + "BQB", + "BQC", + "BQD", + "BQF", + "BQG", + "BRB", + "BRC", + "BRD", + "BRE", + "BRF", + "BRG", + "BSB", + "BSC", + "BSD", + "BSE", + "BSF", + "BTB", + "BTC", + "BTD", + "BTE", + "BTF", + "BTG", + "BUB", + "BUC", + "BUD", + "BUE", + "BUF", + "BUG", + "BVB", + "BVC", + "BVD", + "BVE", + "BVF", + "BVG", + "BWB", + "BWC", + "BWD", + "BWE", + "BWF", + "BWG", + "BXB", + "BXC", + "BXD", + "BXE", + "BXF", + "BXG", + "BYB", + "BYC", + "BYD", + "BYE", + "BYF", + "BYG", + "BZB", + "BZC", + "BZD", + "BZE", + "BZF", + "BZG", + "CAA", + "CAB", + "CAC", + "CAD", + "CAE", + "CAF", + "CAG", + "CBA", + "CBB", + "CBC", + "CBD", + "CBE", + "CBF", + "CBG", + "CCA", + "CCB", + "CCC", + "CCD", + "CCE", + "CCF", + "CCG", + "CDA", + "CDB", + "CDC", + "CDD", + "CDE", + "CDF", + "CDG", + "CEA", + "CEB", + "CEC", + "CED", + "CEE", + "CEF", + "CFA", + "CFB", + "CFC", + "CFD", + "CFE", + "CFG", + "CGA", + "CGB", + "CGC", + "CGD", + "CGE", + "CGF", + "CGG", + "CHA", + "CHB", + "CHC", + "CHD", + "CHE", + "CHF", + "CIA", + "CIB", + "CIC", + "CID", + "CIE", + "CIF", + "CJA", + "CJB", + "CJC", + "CJD", + "CJE", + "CJF", + "CKA", + "CKB", + "CKC", + "CKD", + "CKE", + "CKF", + "CLA", + "CLB", + "CLC", + "CLD", + "CLE", + "CLF", + "CMA", + "CMB", + "CMC", + "CMD", + "CME", + "CMF", + "CNB", + "CNC", + "CND", + "CNE", + "CNF", + "CNG", + "COB", + "COC", + "COD", + "COE", + "COF", + "COG", + "CPB", + "CPC", + "CPD", + "CPE", + "CPF", + "CPG", + "CQB", + "CQC", + "CQD", + "CQF", + "CQG", + "CRB", + "CRC", + "CRD", + "CRE", + "CRF", + "CRG", + "CSB", + "CSC", + "CSD", + "CSE", + "CSF", + "CSG", + "CTB", + "CTC", + "CTD", + "CTE", + "CTF", + "CTG", + "CUB", + "CUC", + "CUD", + "CUE", + "CUF", + "CUG", + "CVB", + "CVC", + "CVD", + "CVE", + "CVF", + "CVG", + "CWB", + "CWC", + "CWD", + "CWE", + "CWF", + "CWG", + "CXB", + "CXC", + "CXD", + "CXE", + "CXF", + "CXG", + "CYB", + "CYC", + "CYD", + "CYE", + "CYF", + "CZB", + "CZC", + "CZD", + "CZE", + "CZF", + "CZG", + "DAA", + "DAB", + "DAC", + "DAD", + "DAE", + "DAF", + "DAG", + "DBA", + "DBB", + "DBC", + "DBD", + "DBE", + "DBF", + "DBG", + "DCA", + "DCB", + "DCC", + "DCD", + "DCE", + "DCF", + "DCG", + "DDA", + "DDB", + "DDC", + "DDD", + "DDE", + "DDF", + "DDG", + "DEA", + "DEB", + "DEC", + "DED", + "DEE", + "DEF", + "DFA", + "DFB", + "DFC", + "DFD", + "DFE", + "DFF", + "DFG", + "DGA", + "DGB", + "DGC", + "DGD", + "DGE", + "DGF", + "DGG", + "DHA", + "DHB", + "DHC", + "DHD", + "DHE", + "DHF", + "DIA", + "DIB", + "DIC", + "DID", + "DIE", + "DIF", + "DJA", + "DJB", + "DJC", + "DJD", + "DJE", + "DKA", + "DKB", + "DKC", + "DKD", + "DKE", + "DKF", + "DLA", + "DLB", + "DLC", + "DLD", + "DLE", + "DLF", + "DMA", + "DMB", + "DMC", + "DMD", + "DME", + "DMF", + "DNB", + "DNC", + "DND", + "DNE", + "DNF", + "DNG", + "DOB", + "DOC", + "DOD", + "DOE", + "DOF", + "DOG", + "DPB", + "DPC", + "DPD", + "DPE", + "DPF", + "DPG", + "DQB", + "DQC", + "DQD", + "DQF", + "DQG", + "DRB", + "DRC", + "DRD", + "DRE", + "DRF", + "DRG", + "DSB", + "DSC", + "DSD", + "DSE", + "DSF", + "DSG", + "DTB", + "DTC", + "DTD", + "DTE", + "DTF", + "DTG", + "DUB", + "DUC", + "DUD", + "DUE", + "DUF", + "DUG", + "DVB", + "DVC", + "DVD", + "DVE", + "DVF", + "DVG", + "DWB", + "DWC", + "DWD", + "DWE", + "DWF", + "DWG", + "DXB", + "DXC", + "DXD", + "DXE", + "DXF", + "DXG", + "DYB", + "DYC", + "DYD", + "DYE", + "DYF", + "DYG", + "DZB", + "DZC", + "DZD", + "DZE", + "DZF", + "DZG", + "EAA", + "EAB", + "EAC", + "EAD", + "EAE", + "EAF", + "EAG", + "EBA", + "EBB", + "EBC", + "EBD", + "EBE", + "EBF", + "EBG", + "ECA", + "ECB", + "ECC", + "ECD", + "ECE", + "ECF", + "ECG", + "EDA", + "EDB", + "EDC", + "EDD", + "EDE", + "EDF", + "EDG", + "EEA", + "EEB", + "EEC", + "EED", + "EEE", + "EEF", + "EFA", + "EFB", + "EFC", + "EFD", + "EFE", + "EFF", + "EFG", + "EGA", + "EGB", + "EGC", + "EGD", + "EGE", + "EGF", + "EHA", + "EHB", + "EHC", + "EHD", + "EHE", + "EHF", + "EIA", + "EIB", + "EIC", + "EID", + "EIE", + "EIF", + "EJA", + "EJB", + "EJC", + "EJD", + "EJE", + "EKA", + "EKB", + "EKC", + "EKD", + "EKE", + "EKF", + "ELA", + "ELB", + "ELC", + "ELD", + "ELE", + "ELF", + "EMA", + "EMB", + "EMC", + "EMD", + "EME", + "EMF", + "ENB", + "ENC", + "END", + "ENE", + "ENF", + "ENG", + "EOB", + "EOC", + "EOD", + "EOE", + "EOF", + "EPB", + "EPC", + "EPD", + "EPE", + "EPF", + "EPG", + "EQB", + "EQC", + "EQD", + "EQF", + "EQG", + "ERB", + "ERC", + "ERD", + "ERE", + "ERF", + "ERG", + "ESB", + "ESC", + "ESD", + "ESE", + "ESF", + "ESG", + "ETB", + "ETC", + "ETD", + "ETE", + "ETF", + "ETG", + "EUB", + "EUC", + "EUD", + "EUE", + "EUF", + "EUG", + "EVB", + "EVC", + "EVD", + "EVE", + "EVF", + "EVG", + "EWB", + "EWC", + "EWD", + "EWE", + "EWF", + "EWG", + "EXB", + "EXC", + "EXD", + "EXE", + "EXF", + "EXG", + "EYB", + "EYC", + "EYD", + "EYE", + "EYF", + "EYG", + "EZB", + "EZC", + "EZD", + "EZE", + "EZF", + "EZG", + "FAA", + "FAB", + "FAC", + "FAD", + "FAE", + "FAF", + "FAG", + "FBA", + "FBB", + "FBC", + "FBD", + "FBF", + "FBG", + "FCA", + "FCB", + "FCC", + "FCD", + "FCE", + "FCF", + "FCG", + "FDA", + "FDB", + "FDC", + "FDD", + "FDE", + "FDF", + "FDG", + "FEA", + "FEB", + "FEC", + "FED", + "FEE", + "FEF", + "FFA", + "FFB", + "FFC", + "FFD", + "FFE", + "FFF", + "FFG", + "FGA", + "FGB", + "FGC", + "FGD", + "FGE", + "FGF", + "FGG", + "FHA", + "FHB", + "FHC", + "FHD", + "FHE", + "FHF", + "FIA", + "FIB", + "FIC", + "FID", + "FIE", + "FIF", + "FJA", + "FJB", + "FJC", + "FJD", + "FJE", + "FJF", + "FKA", + "FKB", + "FKC", + "FKD", + "FKE", + "FKF", + "FLA", + "FLB", + "FLC", + "FLD", + "FLE", + "FLF", + "FMA", + "FMC", + "FMD", + "FME", + "FMF", + "FNB", + "FNC", + "FND", + "FNE", + "FNF", + "FNG", + "FOB", + "FOC", + "FOD", + "FOE", + "FOF", + "FPB", + "FPC", + "FPD", + "FPE", + "FPF", + "FPG", + "FQB", + "FQC", + "FQD", + "FQF", + "FQG", + "FRB", + "FRC", + "FRD", + "FRE", + "FRF", + "FRG", + "FSB", + "FSC", + "FSD", + "FSE", + "FSF", + "FSG", + "FTB", + "FTC", + "FTD", + "FTE", + "FTF", + "FTG", + "FUB", + "FUC", + "FUD", + "FUE", + "FUF", + "FUG", + "FVB", + "FVC", + "FVD", + "FVE", + "FVF", + "FVG", + "FWB", + "FWC", + "FWD", + "FWE", + "FWF", + "FWG", + "FXB", + "FXC", + "FXD", + "FXE", + "FXF", + "FXG", + "FYB", + "FYC", + "FYD", + "FYE", + "FYF", + "FYG", + "FZB", + "FZC", + "FZD", + "FZE", + "FZF", + "FZG", + "GAA", + "GAB", + "GAC", + "GAD", + "GAE", + "GAF", + "GAG", + "GBA", + "GBB", + "GBC", + "GBD", + "GBE", + "GBF", + "GCA", + "GCB", + "GCC", + "GCD", + "GCE", + "GCF", + "GCG", + "GDA", + "GDB", + "GDC", + "GDD", + "GDE", + "GDF", + "GDG", + "GEA", + "GEB", + "GEC", + "GED", + "GEE", + "GEF", + "GFA", + "GFB", + "GFC", + "GFD", + "GFE", + "GFF", + "GFG", + "GGA", + "GGB", + "GGC", + "GGD", + "GGE", + "GGF", + "GHA", + "GHB", + "GHC", + "GHD", + "GHE", + "GHF", + "GIA", + "GIB", + "GIC", + "GID", + "GIE", + "GJA", + "GJB", + "GJC", + "GJD", + "GJE", + "GJF", + "GKA", + "GKB", + "GKC", + "GKD", + "GKE", + "GKF", + "GLA", + "GLB", + "GLC", + "GLD", + "GLE", + "GLF", + "GMA", + "GMC", + "GMD", + "GME", + "GMF", + "GNB", + "GNC", + "GND", + "GNE", + "GNF", + "GNG", + "GOB", + "GOC", + "GOD", + "GOE", + "GOF", + "GPB", + "GPC", + "GPD", + "GPE", + "GPF", + "GPG", + "GQC", + "GQD", + "GQF", + "GQG", + "GRB", + "GRC", + "GRD", + "GRE", + "GRF", + "GRG", + "GSB", + "GSC", + "GSD", + "GSE", + "GSF", + "GSG", + "GTB", + "GTC", + "GTD", + "GTE", + "GTF", + "GTG", + "GUB", + "GUC", + "GUD", + "GUF", + "GUG", + "GVB", + "GVC", + "GVD", + "GVE", + "GVF", + "GVG", + "GWB", + "GWC", + "GWD", + "GWE", + "GWF", + "GWG", + "GXB", + "GXC", + "GXD", + "GXE", + "GXF", + "GXG", + "GYB", + "GYC", + "GYD", + "GYE", + "GYF", + "GYG", + "GZB", + "GZC", + "GZD", + "GZE", + "GZF", + "GZG", + "HAA", + "HAB", + "HAC", + "HAD", + "HAE", + "HAF", + "HAG", + "HBA", + "HBB", + "HBC", + "HBD", + "HBE", + "HBF", + "HCA", + "HCB", + "HCC", + "HCD", + "HCE", + "HCF", + "HCG", + "HDA", + "HDB", + "HDC", + "HDD", + "HDE", + "HDF", + "HDG", + "HEA", + "HEB", + "HEC", + "HED", + "HEE", + "HEF", + "HFA", + "HFB", + "HFC", + "HFD", + "HFE", + "HFF", + "HGA", + "HGB", + "HGC", + "HGD", + "HGE", + "HGF", + "HHA", + "HHB", + "HHC", + "HHD", + "HHE", + "HHF", + "HIA", + "HIB", + "HIC", + "HID", + "HIE", + "HJA", + "HJB", + "HJC", + "HJD", + "HJE", + "HJF", + "HKA", + "HKB", + "HKC", + "HKD", + "HKE", + "HKF", + "HLA", + "HLB", + "HLC", + "HLD", + "HLE", + "HLF", + "HMA", + "HMC", + "HMD", + "HME", + "HMF", + "HNB", + "HNC", + "HND", + "HNE", + "HNF", + "HNG", + "HOB", + "HOC", + "HOD", + "HOE", + "HOF", + "HPB", + "HPC", + "HPD", + "HPE", + "HPF", + "HPG", + "HQB", + "HQC", + "HQD", + "HQF", + "HQG", + "HRB", + "HRC", + "HRD", + "HRE", + "HRF", + "HRG", + "HSB", + "HSC", + "HSD", + "HSE", + "HSF", + "HSG", + "HTB", + "HTC", + "HTD", + "HTE", + "HTF", + "HTG", + "HUB", + "HUC", + "HUD", + "HUE", + "HUF", + "HUG", + "HVB", + "HVC", + "HVD", + "HVE", + "HVF", + "HVG", + "HWB", + "HWC", + "HWD", + "HWE", + "HWF", + "HWG", + "HXB", + "HXC", + "HXD", + "HXE", + "HXF", + "HXG", + "HYB", + "HYC", + "HYD", + "HYE", + "HYF", + "HYG", + "HZB", + "HZC", + "HZD", + "HZE", + "HZF", + "HZG", + "IAA", + "IAB", + "IAC", + "IAD", + "IAE", + "IAF", + "IAG", + "IBA", + "IBB", + "IBC", + "IBD", + "IBE", + "IBF", + "ICA", + "ICB", + "ICC", + "ICD", + "ICE", + "ICF", + "ICG", + "IDA", + "IDB", + "IDC", + "IDD", + "IDE", + "IDF", + "IDG", + "IEA", + "IEB", + "IEC", + "IED", + "IEE", + "IEF", + "IFA", + "IFB", + "IFC", + "IFD", + "IFE", + "IFF", + "IFG", + "IGA", + "IGB", + "IGC", + "IGD", + "IGE", + "IGF", + "IGG", + "IHA", + "IHB", + "IHC", + "IHD", + "IHE", + "IHF", + "IIA", + "IIB", + "IIC", + "IID", + "IIE", + "IJA", + "IJB", + "IJC", + "IJD", + "IJE", + "IJF", + "IKA", + "IKB", + "IKC", + "IKD", + "IKE", + "IKF", + "ILA", + "ILB", + "ILC", + "ILD", + "ILE", + "ILF", + "IMA", + "IMB", + "IMC", + "IMD", + "IME", + "IMF", + "INB", + "INC", + "IND", + "INE", + "INF", + "ING", + "IOB", + "IOC", + "IOD", + "IOE", + "IOF", + "IPB", + "IPC", + "IPD", + "IPE", + "IPF", + "IPG", + "IQB", + "IQC", + "IQD", + "IQF", + "IQG", + "IRB", + "IRC", + "IRD", + "IRE", + "IRF", + "IRG", + "ISB", + "ISC", + "ISD", + "ISE", + "ISF", + "ISG", + "ITB", + "ITC", + "ITD", + "ITE", + "ITF", + "ITG", + "IUB", + "IUC", + "IUD", + "IUE", + "IUF", + "IUG", + "IVB", + "IVC", + "IVD", + "IVE", + "IVF", + "IVG", + "IWB", + "IWC", + "IWD", + "IWE", + "IWF", + "IWG", + "IXB", + "IXC", + "IXD", + "IXE", + "IXF", + "IXG", + "IYB", + "IYC", + "IYD", + "IYE", + "IYF", + "IYG", + "IZB", + "IZC", + "IZD", + "IZE", + "IZF", + "IZG", + "JAA", + "JAB", + "JAC", + "JAD", + "JAE", + "JAF", + "JAG", + "JBA", + "JBB", + "JBC", + "JBD", + "JBE", + "JBF", + "JCA", + "JCB", + "JCC", + "JCD", + "JCE", + "JCF", + "JCG", + "JDA", + "JDB", + "JDC", + "JDD", + "JDE", + "JDF", + "JDG", + "JEA", + "JEB", + "JEC", + "JED", + "JEE", + "JEF", + "JFA", + "JFB", + "JFC", + "JFD", + "JFE", + "JFF", + "JFG", + "JGA", + "JGB", + "JGC", + "JGD", + "JGE", + "JGF", + "JHA", + "JHB", + "JHC", + "JHD", + "JHE", + "JHF", + "JIA", + "JIB", + "JIC", + "JID", + "JIE", + "JIF", + "JJA", + "JJB", + "JJC", + "JJD", + "JJE", + "JJF", + "JKA", + "JKB", + "JKC", + "JKD", + "JKE", + "JKF", + "JLA", + "JLB", + "JLC", + "JLD", + "JLE", + "JLF", + "JMA", + "JMC", + "JMD", + "JME", + "JMF", + "JNB", + "JNC", + "JND", + "JNE", + "JNF", + "JNG", + "JOB", + "JOC", + "JOD", + "JOE", + "JOF", + "JPB", + "JPC", + "JPD", + "JPE", + "JPF", + "JPG", + "JQB", + "JQC", + "JQD", + "JQF", + "JQG", + "JRB", + "JRC", + "JRD", + "JRE", + "JRF", + "JRG", + "JSB", + "JSC", + "JSD", + "JSE", + "JSF", + "JSG", + "JTB", + "JTC", + "JTD", + "JTE", + "JTF", + "JTG", + "JUB", + "JUC", + "JUD", + "JUE", + "JUF", + "JUG", + "JVB", + "JVC", + "JVD", + "JVE", + "JVF", + "JVG", + "JWB", + "JWC", + "JWD", + "JWE", + "JWF", + "JWG", + "JXB", + "JXC", + "JXD", + "JXE", + "JXF", + "JXG", + "JYB", + "JYC", + "JYD", + "JYE", + "JYF", + "JYG", + "JZB", + "JZC", + "JZD", + "JZE", + "JZF", + "JZG", + "KAA", + "KAB", + "KAC", + "KAD", + "KAE", + "KAF", + "KAG", + "KBA", + "KBB", + "KBC", + "KBD", + "KBE", + "KBF", + "KBG", + "KCA", + "KCB", + "KCC", + "KCD", + "KCE", + "KCF", + "KCG", + "KDA", + "KDB", + "KDC", + "KDD", + "KDE", + "KEA", + "KEB", + "KEC", + "KED", + "KEE", + "KEF", + "KFA", + "KFB", + "KFC", + "KFD", + "KFE", + "KFF", + "KFG", + "KGA", + "KGB", + "KGC", + "KGD", + "KGE", + "KGF", + "KGG", + "KHA", + "KHB", + "KHC", + "KHD", + "KHE", + "KHF", + "KIA", + "KIB", + "KIC", + "KID", + "KIE", + "KIF", + "KJA", + "KJB", + "KJC", + "KJD", + "KJE", + "KJF", + "KKA", + "KKB", + "KKC", + "KKD", + "KKE", + "KKF", + "KLA", + "KLB", + "KLC", + "KLD", + "KLE", + "KLF", + "KMA", + "KMC", + "KMD", + "KME", + "KMF", + "KNB", + "KNC", + "KND", + "KNE", + "KNF", + "KNG", + "KOB", + "KOC", + "KOD", + "KOE", + "KOF", + "KPB", + "KPC", + "KPD", + "KPE", + "KPF", + "KPG", + "KQB", + "KQC", + "KQD", + "KQE", + "KQF", + "KQG", + "KRB", + "KRC", + "KRD", + "KRE", + "KRF", + "KRG", + "KSB", + "KSC", + "KSD", + "KSE", + "KSF", + "KSG", + "KTB", + "KTC", + "KTD", + "KTE", + "KTF", + "KTG", + "KUB", + "KUC", + "KUD", + "KUE", + "KUF", + "KUG", + "KVB", + "KVC", + "KVD", + "KVE", + "KVF", + "KVG", + "KWB", + "KWC", + "KWD", + "KWE", + "KWF", + "KWG", + "KXB", + "KXC", + "KXD", + "KXE", + "KXF", + "KXG", + "KYB", + "KYC", + "KYD", + "KYE", + "KYF", + "KYG", + "KZB", + "KZC", + "KZD", + "KZE", + "KZF", + "KZG", + "LAA", + "LAB", + "LAC", + "LAD", + "LAE", + "LAF", + "LAG", + "LBA", + "LBB", + "LBC", + "LBD", + "LBE", + "LBF", + "LBG", + "LCA", + "LCB", + "LCC", + "LCD", + "LCE", + "LCF", + "LCG", + "LDA", + "LDB", + "LDC", + "LDD", + "LDE", + "LDF", + "LEA", + "LEB", + "LEC", + "LED", + "LEE", + "LEF", + "LFA", + "LFB", + "LFC", + "LFD", + "LFE", + "LFF", + "LFG", + "LGA", + "LGB", + "LGC", + "LGD", + "LGE", + "LGF", + "LGG", + "LHA", + "LHB", + "LHC", + "LHD", + "LHE", + "LHF", + "LIA", + "LIB", + "LIC", + "LID", + "LIE", + "LIF", + "LJA", + "LJB", + "LJC", + "LJD", + "LJE", + "LJF", + "LKA", + "LKB", + "LKC", + "LKD", + "LKE", + "LKF", + "LLA", + "LLB", + "LLC", + "LLD", + "LLE", + "LLF", + "LMA", + "LMC", + "LMD", + "LME", + "LMF", + "LNB", + "LNC", + "LND", + "LNE", + "LNF", + "LNG", + "LOB", + "LOC", + "LOD", + "LOE", + "LOF", + "LPB", + "LPC", + "LPD", + "LPE", + "LPF", + "LPG", + "LQB", + "LQC", + "LQD", + "LQE", + "LQF", + "LQG", + "LRB", + "LRC", + "LRD", + "LRE", + "LRF", + "LRG", + "LSB", + "LSC", + "LSD", + "LSE", + "LSF", + "LSG", + "LTB", + "LTC", + "LTD", + "LTE", + "LTF", + "LTG", + "LUB", + "LUC", + "LUD", + "LUE", + "LUF", + "LUG", + "LVB", + "LVC", + "LVD", + "LVE", + "LVF", + "LVG", + "LWB", + "LWC", + "LWD", + "LWE", + "LWF", + "LWG", + "LXB", + "LXC", + "LXD", + "LXE", + "LXF", + "LXG", + "LYB", + "LYC", + "LYD", + "LYE", + "LYF", + "LYG", + "LZB", + "LZC", + "LZD", + "LZE", + "LZF", + "LZG", + "MAA", + "MAB", + "MAC", + "MAD", + "MAE", + "MAF", + "MAG", + "MBA", + "MBB", + "MBC", + "MBD", + "MBE", + "MBF", + "MBG", + "MCA", + "MCB", + "MCC", + "MCD", + "MCE", + "MCF", + "MCG", + "MDA", + "MDB", + "MDC", + "MDD", + "MDE", + "MDF", + "MDG", + "MEA", + "MEB", + "MEC", + "MED", + "MEE", + "MEF", + "MEG", + "MFA", + "MFB", + "MFC", + "MFD", + "MFE", + "MFF", + "MFG", + "MGA", + "MGB", + "MGC", + "MGD", + "MGE", + "MGF", + "MGG", + "MHA", + "MHB", + "MHC", + "MHD", + "MHE", + "MHF", + "MIA", + "MIB", + "MIC", + "MID", + "MIE", + "MIF", + "MJA", + "MJB", + "MJC", + "MJD", + "MJE", + "MKA", + "MKB", + "MKC", + "MKD", + "MKE", + "MKF", + "MLA", + "MLB", + "MLC", + "MLD", + "MLE", + "MLF", + "MMA", + "MMC", + "MMD", + "MME", + "MMF", + "MNB", + "MNC", + "MND", + "MNE", + "MNF", + "MNG", + "MOB", + "MOC", + "MOD", + "MOE", + "MOF", + "MPB", + "MPC", + "MPD", + "MPE", + "MPF", + "MPG", + "MQB", + "MQC", + "MQD", + "MQE", + "MQF", + "MQG", + "MRB", + "MRC", + "MRD", + "MRE", + "MRF", + "MRG", + "MSB", + "MSC", + "MSD", + "MSE", + "MSF", + "MSG", + "MTB", + "MTC", + "MTD", + "MTE", + "MTF", + "MTG", + "MUB", + "MUC", + "MUD", + "MUE", + "MUF", + "MUG", + "MVB", + "MVC", + "MVD", + "MVE", + "MVF", + "MVG", + "MWB", + "MWC", + "MWD", + "MWE", + "MWF", + "MWG", + "MXB", + "MXC", + "MXD", + "MXE", + "MXF", + "MXG", + "MYB", + "MYC", + "MYD", + "MYE", + "MYF", + "MYG", + "MZB", + "MZC", + "MZD", + "MZE", + "MZF", + "MZG", + "NAB", + "NAC", + "NAD", + "NAE", + "NAF", + "NAG", + "NBA", + "NBB", + "NBC", + "NBD", + "NBE", + "NBF", + "NBG", + "NCA", + "NCB", + "NCC", + "NCD", + "NCE", + "NCF", + "NCG", + "NDA", + "NDB", + "NDC", + "NDD", + "NDE", + "NDF", + "NDG", + "NEA", + "NEB", + "NEC", + "NED", + "NEE", + "NEF", + "NEG", + "NFA", + "NFB", + "NFC", + "NFD", + "NFE", + "NFF", + "NFG", + "NGA", + "NGB", + "NGC", + "NGD", + "NGE", + "NGF", + "NGG", + "NHA", + "NHB", + "NHC", + "NHD", + "NHE", + "NHF", + "NIA", + "NIB", + "NIC", + "NID", + "NIE", + "NIF", + "NJA", + "NJB", + "NJC", + "NJD", + "NJE", + "NJF", + "NKA", + "NKB", + "NKC", + "NKD", + "NKE", + "NKF", + "NLA", + "NLB", + "NLC", + "NLD", + "NLE", + "NLF", + "NMA", + "NMB", + "NMC", + "NMD", + "NME", + "NMF", + "NNB", + "NND", + "NNE", + "NNF", + "NNG", + "NOB", + "NOC", + "NOD", + "NOE", + "NOF", + "NOG", + "NPB", + "NPC", + "NPD", + "NPE", + "NPF", + "NQB", + "NQC", + "NQD", + "NQE", + "NQF", + "NQG", + "NRB", + "NRC", + "NRD", + "NRE", + "NRF", + "NRG", + "NSB", + "NSC", + "NSD", + "NSE", + "NSF", + "NSG", + "NTB", + "NTC", + "NTD", + "NTE", + "NTF", + "NTG", + "NUB", + "NUC", + "NUD", + "NUE", + "NUF", + "NUG", + "NVB", + "NVC", + "NVD", + "NVE", + "NVF", + "NVG", + "NWB", + "NWC", + "NWD", + "NWE", + "NWF", + "NWG", + "NXB", + "NXC", + "NXD", + "NXE", + "NXF", + "NXG", + "NYB", + "NYC", + "NYD", + "NYE", + "NYF", + "NYG", + "NZB", + "NZC", + "NZD", + "NZE", + "NZF", + "NZG", + "OAB", + "OAC", + "OAD", + "OAE", + "OAF", + "OAG", + "OBA", + "OBB", + "OBC", + "OBD", + "OBE", + "OBF", + "OCA", + "OCB", + "OCC", + "OCD", + "OCE", + "OCF", + "OCG", + "ODA", + "ODB", + "ODC", + "ODD", + "ODE", + "ODF", + "ODG", + "OEA", + "OEB", + "OEC", + "OED", + "OEE", + "OEF", + "OFA", + "OFB", + "OFC", + "OFD", + "OFE", + "OFF", + "OFG", + "OGA", + "OGB", + "OGC", + "OGD", + "OGE", + "OGF", + "OGG", + "OHA", + "OHB", + "OHC", + "OHD", + "OHE", + "OHF", + "OIA", + "OIB", + "OIC", + "OID", + "OIE", + "OIF", + "OJA", + "OJB", + "OJC", + "OJD", + "OJE", + "OJF", + "OKA", + "OKB", + "OKC", + "OKD", + "OKE", + "OKF", + "OLA", + "OLB", + "OLC", + "OLD", + "OLE", + "OLF", + "OMA", + "OMB", + "OMC", + "OMD", + "OME", + "OMF", + "ONB", + "OND", + "ONE", + "ONF", + "ONG", + "OOB", + "OOC", + "OOD", + "OOE", + "OOF", + "OOG", + "OPB", + "OPC", + "OPD", + "OPE", + "OPF", + "OQB", + "OQC", + "OQD", + "OQE", + "OQF", + "OQG", + "ORB", + "ORC", + "ORD", + "ORE", + "ORF", + "ORG", + "OSB", + "OSC", + "OSD", + "OSE", + "OSF", + "OTB", + "OTC", + "OTD", + "OTE", + "OTG", + "OUB", + "OUC", + "OUD", + "OUE", + "OUF", + "OUG", + "OVB", + "OVC", + "OVD", + "OVE", + "OVF", + "OVG", + "OWB", + "OWC", + "OWD", + "OWE", + "OWF", + "OWG", + "OXB", + "OXC", + "OXD", + "OXE", + "OXF", + "OXG", + "OYB", + "OYC", + "OYD", + "OYE", + "OYF", + "OYG", + "OZB", + "OZC", + "OZD", + "OZE", + "OZF", + "OZG", + "PAB", + "PAC", + "PAD", + "PAE", + "PAF", + "PAG", + "PBA", + "PBB", + "PBC", + "PBD", + "PBE", + "PBF", + "PCA", + "PCB", + "PCC", + "PCD", + "PCE", + "PCF", + "PCG", + "PDA", + "PDB", + "PDC", + "PDD", + "PDE", + "PDF", + "PDG", + "PEA", + "PEB", + "PEC", + "PED", + "PEE", + "PEF", + "PFA", + "PFB", + "PFC", + "PFD", + "PFE", + "PFF", + "PFG", + "PGA", + "PGB", + "PGC", + "PGD", + "PGE", + "PGF", + "PGG", + "PHA", + "PHB", + "PHC", + "PHD", + "PHE", + "PHF", + "PIA", + "PIB", + "PIC", + "PID", + "PIE", + "PIF", + "PJA", + "PJB", + "PJC", + "PJD", + "PJE", + "PJF", + "PKA", + "PKB", + "PKC", + "PKD", + "PKE", + "PKF", + "PLA", + "PLB", + "PLC", + "PLD", + "PLE", + "PLF", + "PMA", + "PMB", + "PMC", + "PMD", + "PME", + "PMF", + "PNB", + "PND", + "PNE", + "PNF", + "PNG", + "POB", + "POC", + "POD", + "POE", + "POF", + "POG", + "PPB", + "PPC", + "PPD", + "PPE", + "PPF", + "PQB", + "PQC", + "PQD", + "PQE", + "PQF", + "PQG", + "PRB", + "PRC", + "PRD", + "PRE", + "PRF", + "PRG", + "PSB", + "PSC", + "PSD", + "PSE", + "PSF", + "PTB", + "PTC", + "PTD", + "PTE", + "PTF", + "PTG", + "PUB", + "PUC", + "PUD", + "PUE", + "PUF", + "PUG", + "PVB", + "PVC", + "PVD", + "PVE", + "PVF", + "PVG", + "PWB", + "PWC", + "PWD", + "PWE", + "PWF", + "PWG", + "PXB", + "PXC", + "PXD", + "PXE", + "PXF", + "PXG", + "PYB", + "PYC", + "PYD", + "PYE", + "PYF", + "PYG", + "PZB", + "PZC", + "PZD", + "PZE", + "PZF", + "PZG", + "QAB", + "QAC", + "QAD", + "QAE", + "QAF", + "QAG", + "QBA", + "QBB", + "QBC", + "QBD", + "QBE", + "QBF", + "QCA", + "QCB", + "QCC", + "QCD", + "QCE", + "QCF", + "QCG", + "QDA", + "QDB", + "QDC", + "QDD", + "QDE", + "QDG", + "QEA", + "QEB", + "QEC", + "QED", + "QEE", + "QEF", + "QFA", + "QFB", + "QFC", + "QFD", + "QFE", + "QFF", + "QFG", + "QGA", + "QGB", + "QGC", + "QGD", + "QGE", + "QGF", + "QGG", + "QHA", + "QHB", + "QHC", + "QHD", + "QHE", + "QHF", + "QIA", + "QIB", + "QIC", + "QID", + "QIE", + "QIF", + "QJA", + "QJB", + "QJC", + "QJD", + "QJE", + "QJF", + "QKA", + "QKB", + "QKC", + "QKD", + "QKE", + "QKF", + "QLA", + "QLB", + "QLC", + "QLD", + "QLE", + "QLF", + "QMA", + "QMB", + "QMC", + "QMD", + "QME", + "QMF", + "QNB", + "QND", + "QNE", + "QNF", + "QNG", + "QOB", + "QOC", + "QOD", + "QOE", + "QOF", + "QOG", + "QPB", + "QPC", + "QPD", + "QPE", + "QPF", + "QQB", + "QQC", + "QQD", + "QQE", + "QQF", + "QQG", + "QRB", + "QRC", + "QRD", + "QRE", + "QRF", + "QRG", + "QSB", + "QSC", + "QSD", + "QSE", + "QSF", + "QSG", + "QTB", + "QTC", + "QTD", + "QTE", + "QTF", + "QTG", + "QUB", + "QUC", + "QUD", + "QUE", + "QUF", + "QUG", + "QVB", + "QVC", + "QVD", + "QVE", + "QVF", + "QWB", + "QWC", + "QWD", + "QWE", + "QWF", + "QWG", + "QXB", + "QXC", + "QXD", + "QXE", + "QXF", + "QXG", + "QYB", + "QYC", + "QYD", + "QYE", + "QYF", + "QYG", + "QZB", + "QZC", + "QZD", + "QZE", + "QZF", + "QZG", + "RAB", + "RAC", + "RAD", + "RAE", + "RAF", + "RAG", + "RBA", + "RBB", + "RBC", + "RBD", + "RBE", + "RBF", + "RCA", + "RCB", + "RCC", + "RCD", + "RCE", + "RCF", + "RCG", + "RDA", + "RDB", + "RDC", + "RDD", + "RDE", + "RDF", + "RDG", + "REA", + "REB", + "REC", + "RED", + "REE", + "REF", + "RFA", + "RFB", + "RFC", + "RFD", + "RFE", + "RFF", + "RFG", + "RGA", + "RGB", + "RGC", + "RGD", + "RGE", + "RGF", + "RGG", + "RHA", + "RHB", + "RHC", + "RHD", + "RHE", + "RHF", + "RIA", + "RIB", + "RIC", + "RID", + "RIE", + "RIF", + "RJA", + "RJB", + "RJC", + "RJD", + "RJE", + "RJF", + "RKA", + "RKB", + "RKC", + "RKD", + "RKE", + "RKF", + "RLA", + "RLB", + "RLC", + "RLD", + "RLE", + "RLF", + "RMA", + "RMB", + "RMC", + "RMD", + "RME", + "RMF", + "RNB", + "RND", + "RNE", + "RNF", + "RNG", + "ROB", + "ROC", + "ROD", + "ROE", + "ROF", + "ROG", + "RPB", + "RPC", + "RPD", + "RPE", + "RPF", + "RQB", + "RQC", + "RQD", + "RQE", + "RQF", + "RQG", + "RRC", + "RRD", + "RRE", + "RRF", + "RRG", + "RSB", + "RSC", + "RSD", + "RSE", + "RSF", + "RTB", + "RTC", + "RTD", + "RTE", + "RTF", + "RTG", + "RUB", + "RUC", + "RUD", + "RUE", + "RUF", + "RUG", + "RVB", + "RVC", + "RVD", + "RVE", + "RVF", + "RVG", + "RWB", + "RWC", + "RWD", + "RWE", + "RWF", + "RWG", + "RXB", + "RXC", + "RXD", + "RXE", + "RXF", + "RXG", + "RYB", + "RYC", + "RYD", + "RYE", + "RYF", + "RYG", + "RZB", + "RZC", + "RZD", + "RZE", + "RZF", + "RZG", + "SAB", + "SAC", + "SAD", + "SAE", + "SAF", + "SAG", + "SBA", + "SBB", + "SBC", + "SBD", + "SBE", + "SBF", + "SCA", + "SCB", + "SCC", + "SCD", + "SCE", + "SCF", + "SCG", + "SDA", + "SDB", + "SDC", + "SDD", + "SDE", + "SDF", + "SDG", + "SEA", + "SEB", + "SEC", + "SED", + "SEE", + "SEF", + "SFA", + "SFB", + "SFC", + "SFD", + "SFE", + "SFF", + "SFG", + "SGA", + "SGB", + "SGC", + "SGD", + "SGE", + "SGF", + "SGG", + "SHA", + "SHB", + "SHC", + "SHD", + "SHE", + "SHF", + "SIA", + "SIB", + "SIC", + "SID", + "SIE", + "SIF", + "SJA", + "SJB", + "SJC", + "SJD", + "SJE", + "SJF", + "SKA", + "SKB", + "SKC", + "SKD", + "SKE", + "SKF", + "SLA", + "SLB", + "SLC", + "SLD", + "SLE", + "SLF", + "SMA", + "SMB", + "SMC", + "SMD", + "SME", + "SMF", + "SNB", + "SND", + "SNE", + "SNF", + "SNG", + "SOB", + "SOC", + "SOD", + "SOE", + "SOF", + "SOG", + "SPB", + "SPC", + "SPD", + "SPE", + "SPF", + "SPG", + "SQB", + "SQC", + "SQD", + "SQE", + "SQF", + "SQG", + "SRB", + "SRC", + "SRD", + "SRE", + "SRF", + "SRG", + "SSB", + "SSC", + "SSD", + "SSE", + "SSF", + "SSG", + "STB", + "STC", + "STD", + "STE", + "STF", + "STG", + "SUB", + "SUC", + "SUD", + "SUE", + "SUF", + "SUG", + "SVB", + "SVC", + "SVD", + "SVE", + "SVF", + "SVG", + "SWB", + "SWC", + "SWD", + "SWE", + "SWF", + "SWG", + "SXB", + "SXC", + "SXD", + "SXE", + "SXF", + "SXG", + "SYB", + "SYC", + "SYD", + "SYE", + "SYF", + "SYG", + "SZB", + "SZC", + "SZD", + "SZE", + "SZF", + "SZG", + "TAB", + "TAC", + "TAD", + "TAE", + "TAF", + "TAG", + "TBA", + "TBB", + "TBC", + "TBD", + "TBE", + "TBF", + "TCA", + "TCB", + "TCC", + "TCD", + "TCE", + "TCF", + "TCG", + "TDA", + "TDB", + "TDC", + "TDD", + "TDE", + "TDF", + "TDG", + "TEA", + "TEB", + "TEC", + "TED", + "TEE", + "TEF", + "TFA", + "TFB", + "TFC", + "TFD", + "TFE", + "TFF", + "TFG", + "TGA", + "TGB", + "TGC", + "TGD", + "TGE", + "TGF", + "TGG", + "THA", + "THB", + "THC", + "THD", + "THE", + "THF", + "TIA", + "TIB", + "TIC", + "TID", + "TIE", + "TIF", + "TJA", + "TJB", + "TJC", + "TJD", + "TJE", + "TJF", + "TKA", + "TKB", + "TKC", + "TKD", + "TKE", + "TKF", + "TLA", + "TLB", + "TLC", + "TLD", + "TLE", + "TLF", + "TMA", + "TMB", + "TMC", + "TMD", + "TME", + "TMF", + "TNB", + "TNC", + "TND", + "TNE", + "TNF", + "TNG", + "TOB", + "TOC", + "TOD", + "TOE", + "TOF", + "TOG", + "TPB", + "TPC", + "TPD", + "TPE", + "TPF", + "TPG", + "TQB", + "TQC", + "TQD", + "TQE", + "TQF", + "TQG", + "TRB", + "TRC", + "TRD", + "TRE", + "TRF", + "TRG", + "TSB", + "TSC", + "TSD", + "TSE", + "TSF", + "TSG", + "TTB", + "TTC", + "TTD", + "TTE", + "TTF", + "TTG", + "TUB", + "TUD", + "TUE", + "TUF", + "TUG", + "TVB", + "TVC", + "TVD", + "TVE", + "TVF", + "TVG", + "TWB", + "TWC", + "TWD", + "TWE", + "TWF", + "TWG", + "TXB", + "TXC", + "TXD", + "TXE", + "TXF", + "TXG", + "TYB", + "TYC", + "TYD", + "TYE", + "TYF", + "TYG", + "TZB", + "TZC", + "TZD", + "TZE", + "TZF", + "TZG", + "UAB", + "UAC", + "UAD", + "UAE", + "UAF", + "UAG", + "UBA", + "UBB", + "UBC", + "UBD", + "UBE", + "UBF", + "UCA", + "UCB", + "UCC", + "UCD", + "UCE", + "UCF", + "UCG", + "UDA", + "UDB", + "UDC", + "UDD", + "UDE", + "UDF", + "UDG", + "UEA", + "UEB", + "UEC", + "UED", + "UEE", + "UEF", + "UFA", + "UFB", + "UFC", + "UFD", + "UFF", + "UFG", + "UGA", + "UGB", + "UGC", + "UGD", + "UGE", + "UGF", + "UGG", + "UHA", + "UHB", + "UHC", + "UHD", + "UHE", + "UHF", + "UIA", + "UIB", + "UIC", + "UID", + "UIE", + "UIF", + "UJA", + "UJB", + "UJC", + "UJD", + "UJE", + "UJF", + "UKA", + "UKB", + "UKC", + "UKD", + "UKE", + "UKF", + "ULA", + "ULB", + "ULC", + "ULD", + "ULE", + "ULF", + "UMA", + "UMB", + "UMC", + "UMD", + "UME", + "UMF", + "UNB", + "UNC", + "UND", + "UNE", + "UNF", + "UNG", + "UOB", + "UOC", + "UOD", + "UOE", + "UOF", + "UOG", + "UPB", + "UPC", + "UPD", + "UPE", + "UPF", + "UPG", + "UQB", + "UQC", + "UQD", + "UQE", + "UQF", + "UQG", + "URB", + "URC", + "URD", + "URE", + "URF", + "URG", + "USB", + "USC", + "USD", + "USE", + "USF", + "USG", + "UTB", + "UTC", + "UTD", + "UTE", + "UTF", + "UTG", + "UUB", + "UUC", + "UUD", + "UUE", + "UUF", + "UUG", + "UVB", + "UVC", + "UVD", + "UVE", + "UVF", + "UVG", + "UWB", + "UWC", + "UWD", + "UWE", + "UWF", + "UWG", + "UXB", + "UXC", + "UXD", + "UXE", + "UXF", + "UXG", + "UYB", + "UYC", + "UYD", + "UYE", + "UYF", + "UYG", + "UZB", + "UZC", + "UZD", + "UZE", + "UZF", + "UZG", + "VAB", + "VAC", + "VAD", + "VAE", + "VAF", + "VAG", + "VBA", + "VBB", + "VBC", + "VBD", + "VBE", + "VBF", + "VBG", + "VCA", + "VCB", + "VCC", + "VCD", + "VCE", + "VCF", + "VCG", + "VDA", + "VDB", + "VDC", + "VDD", + "VDE", + "VDF", + "VDG", + "VEA", + "VEB", + "VEC", + "VED", + "VEE", + "VEF", + "VFA", + "VFB", + "VFC", + "VFD", + "VFE", + "VFF", + "VFG", + "VGA", + "VGB", + "VGC", + "VGD", + "VGE", + "VGF", + "VGG", + "VHA", + "VHB", + "VHC", + "VHD", + "VHE", + "VHF", + "VIA", + "VIB", + "VIC", + "VID", + "VIE", + "VIF", + "VJA", + "VJB", + "VJC", + "VJD", + "VJE", + "VKA", + "VKB", + "VKC", + "VKD", + "VKE", + "VKF", + "VLA", + "VLB", + "VLC", + "VLD", + "VLE", + "VLF", + "VMA", + "VMB", + "VMC", + "VMD", + "VME", + "VMF", + "VNB", + "VNC", + "VND", + "VNE", + "VNF", + "VNG", + "VOB", + "VOC", + "VOD", + "VOE", + "VOF", + "VOG", + "VPB", + "VPC", + "VPD", + "VPE", + "VPF", + "VPG", + "VQB", + "VQC", + "VQD", + "VQE", + "VQF", + "VQG", + "VRB", + "VRC", + "VRD", + "VRE", + "VRF", + "VRG", + "VSB", + "VSC", + "VSD", + "VSE", + "VSF", + "VSG", + "VTB", + "VTC", + "VTD", + "VTE", + "VTF", + "VTG", + "VUB", + "VUC", + "VUD", + "VUE", + "VUF", + "VUG", + "VVB", + "VVC", + "VVD", + "VVE", + "VVF", + "VVG", + "VWB", + "VWC", + "VWD", + "VWE", + "VWF", + "VWG", + "VXC", + "VXD", + "VXE", + "VXF", + "VXG", + "VYB", + "VYC", + "VYD", + "VYE", + "VYF", + "VYG", + "VZB", + "VZC", + "VZD", + "VZE", + "VZF", + "VZG", + "WAB", + "WAC", + "WAD", + "WAE", + "WAF", + "WAG", + "WBA", + "WBB", + "WBC", + "WBD", + "WBE", + "WBF", + "WBG", + "WCA", + "WCB", + "WCC", + "WCD", + "WCE", + "WCF", + "WCG", + "WDA", + "WDC", + "WDD", + "WDE", + "WDF", + "WDG", + "WEA", + "WEB", + "WEC", + "WED", + "WEE", + "WEF", + "WFA", + "WFB", + "WFC", + "WFD", + "WFE", + "WFF", + "WFG", + "WGA", + "WGB", + "WGC", + "WGD", + "WGE", + "WGF", + "WGG", + "WHA", + "WHB", + "WHC", + "WHD", + "WHE", + "WHF", + "WIA", + "WIB", + "WIC", + "WID", + "WIE", + "WIF", + "WJA", + "WJB", + "WJC", + "WJD", + "WJE", + "WJF", + "WKA", + "WKB", + "WKC", + "WKD", + "WKE", + "WKF", + "WLA", + "WLB", + "WLC", + "WLD", + "WLE", + "WLF", + "WMA", + "WMB", + "WMC", + "WMD", + "WME", + "WMF", + "WNB", + "WNC", + "WND", + "WNE", + "WNF", + "WNG", + "WOB", + "WOC", + "WOD", + "WOE", + "WOF", + "WOG", + "WPB", + "WPC", + "WPD", + "WPE", + "WPF", + "WPG", + "WQB", + "WQC", + "WQD", + "WQE", + "WQF", + "WQG", + "WRB", + "WRC", + "WRD", + "WRE", + "WRF", + "WRG", + "WSB", + "WSC", + "WSD", + "WSE", + "WSF", + "WSG", + "WTB", + "WTC", + "WTD", + "WTE", + "WTF", + "WTG", + "WUB", + "WUC", + "WUD", + "WUE", + "WUF", + "WUG", + "WVB", + "WVC", + "WVD", + "WVE", + "WVF", + "WVG", + "WWB", + "WWC", + "WWD", + "WWE", + "WWF", + "WWG", + "WXB", + "WXC", + "WXD", + "WXE", + "WXF", + "WXG", + "WYB", + "WYC", + "WYD", + "WYE", + "WYF", + "WYG", + "WZB", + "WZC", + "WZD", + "WZE", + "WZF", + "WZG", + "XAC", + "XAD", + "XAE", + "XAF", + "XBA", + "XBB", + "XBC", + "XBD", + "XBE", + "XBF", + "XBG", + "XCA", + "XCB", + "XCC", + "XCD", + "XCE", + "XCF", + "XCG", + "XDA", + "XDB", + "XDC", + "XDD", + "XDE", + "XDF", + "XDG", + "XEA", + "XEB", + "XEC", + "XED", + "XEE", + "XEF", + "XFA", + "XFB", + "XFC", + "XFD", + "XFE", + "XFF", + "XFG", + "XGA", + "XGB", + "XGC", + "XGD", + "XGE", + "XGF", + "XGG", + "XHA", + "XHB", + "XHC", + "XHD", + "XHE", + "XHF", + "XIA", + "XIB", + "XIC", + "XID", + "XIE", + "XIF", + "XJA", + "XJB", + "XJC", + "XJD", + "XJE", + "XJF", + "XKA", + "XKB", + "XKC", + "XKD", + "XKE", + "XKF", + "XLA", + "XLB", + "XLC", + "XLD", + "XLE", + "XLF", + "XMA", + "XMB", + "XMC", + "XMD", + "XME", + "XMF", + "XNB", + "XNC", + "XND", + "XNE", + "XNF", + "XNG", + "XOB", + "XOC", + "XOD", + "XOE", + "XOF", + "XOG", + "XPB", + "XPC", + "XPD", + "XPE", + "XPF", + "XPG", + "XQB", + "XQC", + "XQD", + "XQF", + "XQG", + "XRB", + "XRC", + "XRD", + "XRE", + "XRF", + "XRG", + "XSB", + "XSC", + "XSD", + "XSE", + "XSF", + "XSG", + "XTB", + "XTC", + "XTD", + "XTE", + "XTF", + "XTG", + "XUB", + "XUC", + "XUD", + "XUE", + "XUF", + "XUG", + "XVB", + "XVC", + "XVD", + "XVE", + "XVF", + "XVG", + "XWB", + "XWC", + "XWD", + "XWE", + "XWF", + "XWG", + "XXB", + "XXC", + "XXD", + "XXE", + "XXF", + "XXG", + "XYB", + "XYC", + "XYD", + "XYE", + "XYF", + "XYG", + "XZB", + "XZC", + "XZD", + "XZE", + "XZF", + "XZG", + "YAB", + "YAC", + "YAD", + "YAE", + "YAF", + "YAG", + "YBA", + "YBB", + "YBC", + "YBD", + "YBE", + "YBF", + "YCA", + "YCB", + "YCD", + "YCE", + "YCF", + "YCG", + "YDA", + "YDB", + "YDC", + "YDD", + "YDE", + "YDF", + "YDG", + "YEA", + "YEB", + "YEC", + "YED", + "YEE", + "YEF", + "YFA", + "YFB", + "YFC", + "YFD", + "YFE", + "YFG", + "YGA", + "YGB", + "YGC", + "YGD", + "YGE", + "YGF", + "YGG", + "YHA", + "YHB", + "YHC", + "YHD", + "YHE", + "YHF", + "YIA", + "YIB", + "YIC", + "YID", + "YIE", + "YIF", + "YJA", + "YJB", + "YJC", + "YJD", + "YJE", + "YJF", + "YKA", + "YKB", + "YKC", + "YKD", + "YKE", + "YKF", + "YLA", + "YLB", + "YLC", + "YLD", + "YLE", + "YLF", + "YMA", + "YMB", + "YMC", + "YMD", + "YME", + "YMF", + "YNB", + "YNC", + "YND", + "YNE", + "YNF", + "YNG", + "YOB", + "YOC", + "YOD", + "YOE", + "YOF", + "YOG", + "YPB", + "YPC", + "YPD", + "YPE", + "YPF", + "YPG", + "YQB", + "YQC", + "YQD", + "YQF", + "YQG", + "YRB", + "YRC", + "YRD", + "YRE", + "YRF", + "YRG", + "YSB", + "YSC", + "YSD", + "YSE", + "YSF", + "YSG", + "YTB", + "YTC", + "YTD", + "YTE", + "YTF", + "YTG", + "YUB", + "YUC", + "YUD", + "YUE", + "YUF", + "YUG", + "YVB", + "YVC", + "YVD", + "YVE", + "YVF", + "YVG", + "YWB", + "YWC", + "YWD", + "YWE", + "YWF", + "YWG", + "YXB", + "YXC", + "YXD", + "YXE", + "YXF", + "YXG", + "YYB", + "YYC", + "YYD", + "YYE", + "YYF", + "YYG", + "YZB", + "YZC", + "YZD", + "YZE", + "YZF", + "YZG", + "ZAB", + "ZAD", + "ZAE", + "ZAF", + "ZAG", + "ZBA", + "ZBB", + "ZBC", + "ZBD", + "ZBE", + "ZBF", + "ZCA", + "ZCB", + "ZCC", + "ZCD", + "ZCE", + "ZCF", + "ZCG", + "ZDA", + "ZDB", + "ZDC", + "ZDD", + "ZDE", + "ZDF", + "ZDG", + "ZEA", + "ZEB", + "ZEC", + "ZED", + "ZEE", + "ZEF", + "ZFA", + "ZFB", + "ZFC", + "ZFD", + "ZFE", + "ZFF", + "ZFG", + "ZGA", + "ZGB", + "ZGC", + "ZGD", + "ZGE", + "ZGF", + "ZGG", + "ZHA", + "ZHB", + "ZHC", + "ZHD", + "ZHE", + "ZHF", + "ZIA", + "ZIB", + "ZIC", + "ZID", + "ZIE", + "ZIF", + "ZJA", + "ZJB", + "ZJC", + "ZJD", + "ZJE", + "ZJF", + "ZKA", + "ZKB", + "ZKC", + "ZKD", + "ZKE", + "ZKF", + "ZLA", + "ZLB", + "ZLC", + "ZLD", + "ZLE", + "ZLF", + "ZMA", + "ZMB", + "ZMC", + "ZMD", + "ZME", + "ZMF", + "ZNB", + "ZNC", + "ZND", + "ZNE", + "ZNF", + "ZNG", + "ZOB", + "ZOC", + "ZOD", + "ZOE", + "ZOF", + "ZPB", + "ZPC", + "ZPD", + "ZPE", + "ZPF", + "ZPG", + "ZQB", + "ZQC", + "ZQD", + "ZQF", + "ZQG", + "ZRB", + "ZRC", + "ZRD", + "ZRE", + "ZRF", + "ZRG", + "ZSB", + "ZSC", + "ZSD", + "ZSE", + "ZSF", + "ZSG", + "ZTB", + "ZTC", + "ZTD", + "ZTE", + "ZTF", + "ZTG", + "ZUB", + "ZUC", + "ZUD", + "ZUE", + "ZUF", + "ZUG", + "ZVB", + "ZVC", + "ZVD", + "ZVE", + "ZVF", + "ZVG", + "ZWB", + "ZWC", + "ZWD", + "ZWE", + "ZWF", + "ZWG", + "ZXB", + "ZXC", + "ZXD", + "ZXE", + "ZXF", + "ZXG", + "ZYB", + "ZYC", + "ZYD", + "ZYE", + "ZYF", + "ZYG", + "ZZB", + "ZZC", + "ZZD", + "ZZE", + "ZZF", + "ZZG" + ] + }, "FactionStatEnum": { "type": "string", "enum": [ @@ -4226,6 +8783,33 @@ "peace" ] }, + "FactionPositionAbilityEnum": { + "type": "string", + "enum": [ + "Medical Item Usage", + "Booster Item Usage", + "Drug Item Usage", + "Energy Refill Usage", + "Nerve Refill Usage", + "Temporary Item Loaning", + "Weapon & Armor Loaning", + "Item Retrieving", + "Organised Crimes", + "Faction API Access", + "Item Giving", + "Money Giving", + "Points Giving", + "Forum Management", + "Application Management", + "Kick Members", + "Balance Adjustment", + "War Management", + "Upgrade Management", + "Newsletter Sending", + "Announcement Changes", + "Description Changes" + ] + }, "FactionOrganizedCrimePayoutType": { "type": "string", "enum": [ @@ -4234,6 +8818,14 @@ "inventory" ] }, + "TornRacketType": { + "type": "string", + "enum": [ + "Item", + "Points", + "Money" + ] + }, "FactionNewsCategory": { "type": "string", "enum": [ @@ -4304,6 +8896,17 @@ "rank" ] }, + "FactionTerritoryWarResultEnum": { + "type": "string", + "enum": [ + "success_assault", + "fail_assault", + "end_with_nap", + "end_with_destroy_attack", + "end_with_destroy_defense", + "end_with_peace_treaty" + ] + }, "FactionAttackResult": { "type": "string", "enum": [ @@ -4576,6 +9179,13 @@ "ongoing" ] }, + "FactionTerritoryWarsCategoryEnum": { + "type": "string", + "enum": [ + "finsihed", + "ongoing" + ] + }, "FactionCrimeUserOutcome": { "type": "string", "enum": [ @@ -4618,6 +9228,10 @@ "type": "integer", "format": "int32" }, + "TerritoryWarId": { + "type": "integer", + "format": "int32" + }, "ItemUid": { "type": "integer", "format": "int64" @@ -4642,6 +9256,10 @@ "type": "integer", "format": "int32" }, + "EducationId": { + "type": "integer", + "format": "int32" + }, "FactionBranchId": { "type": "integer", "format": "int32" @@ -4650,6 +9268,10 @@ "type": "integer", "format": "int64" }, + "TornCrimeId": { + "type": "integer", + "format": "int32" + }, "ChainId": { "type": "integer", "format": "int32" @@ -5430,6 +10052,542 @@ }, "type": "object" }, + "FactionTerritoryWarFinishedFaction": { + "required": [ + "id", + "name", + "score", + "is_aggressor" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "integer", + "format": "int32" + }, + "is_aggressor": { + "type": "boolean" + } + }, + "type": "object" + }, + "FactionTerritoryWarFinished": { + "required": [ + "id", + "territory", + "start", + "end", + "target", + "result", + "factions" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/TerritoryWarId" + }, + "territory": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "start": { + "type": "integer", + "format": "int64" + }, + "end": { + "type": "integer", + "format": "int64" + }, + "target": { + "type": "integer", + "format": "int32" + }, + "result": { + "$ref": "#/components/schemas/FactionTerritoryWarResultEnum" + }, + "factions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarFinishedFaction" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarOngoingFaction": { + "required": [ + "id", + "name", + "score", + "is_aggressor", + "chain", + "playerIds" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "integer", + "format": "int32" + }, + "is_aggressor": { + "type": "boolean" + }, + "chain": { + "type": "integer", + "format": "int32" + }, + "playerIds": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserId" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarOngoing": { + "required": [ + "id", + "territory", + "start", + "end", + "target", + "factions" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/TerritoryWarId" + }, + "territory": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "start": { + "type": "integer", + "format": "int32" + }, + "end": { + "type": "integer", + "format": "int32" + }, + "target": { + "type": "integer", + "format": "int32" + }, + "factions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarOngoingFaction" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarsResponse": { + "required": [ + "territorywars" + ], + "properties": { + "territorywars": { + "description": "If the chosen category is 'ongoing' the response will be of 'FactionTerritoryWarOngoing' type, otherwise, the type will be 'FactionTerritoryWarFinished'.", + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarOngoing" + } + }, + { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarFinished" + } + } + ] + } + }, + "type": "object" + }, + "FactionTerritoryWarsHistoryResponse": { + "required": [ + "territorywars" + ], + "properties": { + "territorywars": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarFinished" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarReportMembers": { + "required": [ + "id", + "username", + "level", + "score", + "joins", + "clears" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/UserId" + }, + "username": { + "type": "string" + }, + "level": { + "type": "integer", + "format": "int32" + }, + "score": { + "type": "integer", + "format": "int32" + }, + "joins": { + "type": "integer", + "format": "int32" + }, + "clears": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "FactionTerritoryWarReportFaction": { + "required": [ + "id", + "name", + "score", + "joins", + "clears", + "is_aggressor", + "members" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionId" + }, + "name": { + "type": "string" + }, + "score": { + "type": "integer", + "format": "int32" + }, + "joins": { + "type": "integer", + "format": "int32" + }, + "clears": { + "type": "integer", + "format": "int32" + }, + "is_aggressor": { + "type": "boolean" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarReportMembers" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarReport": { + "required": [ + "id", + "territory", + "started_at", + "ended_at", + "winner", + "result", + "factions" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/TerritoryWarId" + }, + "territory": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "started_at": { + "type": "integer", + "format": "int32" + }, + "ended_at": { + "type": "integer", + "format": "int32" + }, + "winner": { + "$ref": "#/components/schemas/FactionId" + }, + "result": { + "type": "string" + }, + "factions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarReportFaction" + } + } + }, + "type": "object" + }, + "FactionTerritoryWarReportResponse": { + "required": [ + "territorywarreport" + ], + "properties": { + "territorywarreport": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryWarReport" + } + } + }, + "type": "object" + }, + "FactionTerritoryOwnership": { + "required": [ + "id", + "owned_by", + "acquired_at" + ], + "properties": { + "id": { + "type": "string" + }, + "owned_by": { + "oneOf": [ + { + "$ref": "#/components/schemas/FactionId" + }, + { + "type": "null" + } + ] + }, + "acquired_at": { + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "FactionTerritoriesOwnershipResponse": { + "required": [ + "territoryownership" + ], + "properties": { + "territoryownership": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryOwnership" + } + } + }, + "type": "object" + }, + "TornRacketReward": { + "required": [ + "type", + "quantity", + "id" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/TornRacketType" + }, + "quantity": { + "type": "integer", + "format": "int32" + }, + "id": { + "oneOf": [ + { + "$ref": "#/components/schemas/ItemId" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "TornRacket": { + "required": [ + "name", + "level", + "description", + "reward", + "created_at", + "changed_at" + ], + "properties": { + "name": { + "type": "string" + }, + "level": { + "type": "integer", + "format": "int32" + }, + "description": { + "type": "string" + }, + "reward": { + "$ref": "#/components/schemas/TornRacketReward" + }, + "created_at": { + "type": "integer", + "format": "int32" + }, + "changed_at": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "FactionRacketsReponse": { + "required": [ + "rackets" + ], + "properties": { + "rackets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TornRacket" + } + } + }, + "type": "object" + }, + "FactionTerritory": { + "required": [ + "id", + "acquired_at", + "sector", + "size", + "density", + "slots", + "respect", + "coordinates", + "racket" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "acquired_at": { + "type": "integer", + "format": "int32" + }, + "sector": { + "type": "integer", + "format": "int32" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "density": { + "type": "integer", + "format": "int32" + }, + "slots": { + "type": "integer", + "format": "int32" + }, + "respect": { + "type": "integer", + "format": "int32" + }, + "coordinates": { + "$ref": "#/components/schemas/TornTerritoryCoordinates" + }, + "racket": { + "oneOf": [ + { + "$ref": "#/components/schemas/TornRacket" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "FactionTerritoriesReponse": { + "required": [ + "territory" + ], + "properties": { + "territory": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritory" + } + } + }, + "type": "object" + }, + "FactionPosition": { + "required": [ + "name", + "is_default", + "abilities" + ], + "properties": { + "name": { + "type": "string" + }, + "is_default": { + "type": "boolean" + }, + "abilities": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionPositionAbilityEnum" + } + } + }, + "type": "object" + }, + "FactionPositionsResponse": { + "required": [ + "positions" + ], + "properties": { + "positions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionPosition" + } + } + }, + "type": "object" + }, "FactionUpgradeDetails": { "required": [ "id", @@ -5634,10 +10792,7 @@ ], "properties": { "hof": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FactionHofStats" - } + "$ref": "#/components/schemas/FactionHofStats" } }, "type": "object" @@ -5835,7 +10990,7 @@ "tag", "tag_image", "leader_id", - "co-leader_id", + "co_leader_id", "respect", "days_old", "capacity", @@ -5863,6 +11018,9 @@ "co-leader_id": { "$ref": "#/components/schemas/UserId" }, + "co_leader_id": { + "$ref": "#/components/schemas/UserId" + }, "respect": { "type": "integer", "format": "int32" @@ -6326,7 +11484,8 @@ "type": "string" }, "level": { - "type": "string" + "type": "integer", + "format": "int32" }, "stats": { "required": [ @@ -6513,7 +11672,7 @@ "details", "bonuses", "attackers", - "non-attackers" + "non_attackers" ], "properties": { "id": { @@ -6546,6 +11705,14 @@ } }, "non-attackers": { + "description": "This is replaced with 'sci_fi' field and will be removed on 1st June 2025.", + "type": "array", + "items": { + "$ref": "#/components/schemas/UserId" + }, + "deprecated": true + }, + "non_attackers": { "type": "array", "items": { "$ref": "#/components/schemas/UserId" @@ -7164,7 +12331,7 @@ "type": "object" }, "FactionSelectionName": { - "description": "The following selections will fallback to API v1 and may change at any time: 'armor', 'boosters', 'caches', 'cesium', 'crimeexp', 'drugs', 'medical', 'positions', 'reports', 'temporary', 'weapons'.", + "description": "The following selections will fallback to API v1 and may change at any time: 'armor', 'boosters', 'caches', 'cesium', 'crimeexp', 'drugs', 'medical', 'positions', 'reports', 'temporary', 'weapons'.\n * The following selections are not available in API v2: 'armorynews', 'attacknews', 'crimenews', 'currency', 'donations', 'fundsnews', 'mainnews', 'membershipnews', 'territorynews'.", "type": "string", "enum": [ "applications", @@ -7182,11 +12349,16 @@ "lookup", "members", "news", + "rackets", "rankedwars", "rankedwarreport", "revives", "revivesfull", "stats", + "territory", + "territoryownership", + "territorywarreport", + "territorywars", "timestamp", "upgrades", "wars", @@ -7200,8 +12372,16 @@ "positions", "reports", "temporary", - "territory", - "weapons" + "weapons", + "armorynews", + "attacknews", + "crimenews", + "currency", + "donations", + "fundsnews", + "mainnews", + "membershipnews", + "territorynews" ] }, "FactionLookupResponse": { @@ -8168,7 +13348,8 @@ "itemmarket", "lookup", "timestamp", - "pointsmarket" + "pointsmarket", + "bazaar" ] }, "MarketLookupResponse": { @@ -8730,6 +13911,268 @@ }, "type": "object" }, + "TornEducationRewards": { + "required": [ + "working_stats", + "effect", + "honor" + ], + "properties": { + "working_stats": { + "required": [ + "manual_labor", + "intelligence", + "endurance" + ], + "properties": { + "manual_labor": { + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "null" + } + ] + }, + "intelligence": { + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "null" + } + ] + }, + "endurance": { + "oneOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "effect": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "honor": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "TornEducationPrerequisites": { + "required": [ + "cost", + "courses" + ], + "properties": { + "cost": { + "type": "integer", + "format": "int32" + }, + "courses": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + "type": "object" + }, + "TornEducationCourses": { + "required": [ + "id", + "code", + "name", + "description", + "duration", + "rewards", + "prerequisites" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/EducationId" + }, + "code": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "duration": { + "type": "integer", + "format": "int32" + }, + "rewards": { + "$ref": "#/components/schemas/TornEducationRewards" + }, + "prerequisites": { + "$ref": "#/components/schemas/TornEducationPrerequisites" + } + }, + "type": "object" + }, + "TornEducation": { + "required": [ + "id", + "name", + "courses" + ], + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "name": { + "type": "string" + }, + "courses": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TornEducationCourses" + } + } + }, + "type": "object" + }, + "TornEducationResponse": { + "required": [ + "education" + ], + "properties": { + "education": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TornEducation" + } + } + }, + "type": "object" + }, + "TornTerritoryCoordinates": { + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "type": "number", + "format": "float" + }, + "y": { + "type": "number", + "format": "float" + } + }, + "type": "object" + }, + "TornTerritory": { + "required": [ + "id", + "sector", + "size", + "density", + "slots", + "respect", + "coordinates", + "neighbors" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + }, + "sector": { + "type": "integer", + "format": "int32" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "density": { + "type": "integer", + "format": "int32" + }, + "slots": { + "type": "integer", + "format": "int32" + }, + "respect": { + "type": "integer", + "format": "int32" + }, + "coordinates": { + "$ref": "#/components/schemas/TornTerritoryCoordinates" + }, + "neighbors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FactionTerritoryEnum" + } + } + }, + "type": "object" + }, + "TornTerritoriesResponse": { + "required": [ + "territory", + "_metadata" + ], + "properties": { + "territory": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TornTerritory" + } + }, + "_metadata": { + "$ref": "#/components/schemas/RequestMetadataWithLinks" + } + }, + "type": "object" + }, + "TornTerritoriesNoLinksReponse": { + "required": [ + "territory" + ], + "properties": { + "territory": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TornTerritory" + } + } + }, + "type": "object" + }, "TornSubcrimesResponse": { "required": [ "subcrimes" @@ -8787,13 +14230,11 @@ "enhancer_id", "enhancer_name", "unique_outcomes_count", - "unique_outcomes_ids", - "notes" + "unique_outcomes_ids" ], "properties": { "id": { - "type": "integer", - "format": "int32" + "$ref": "#/components/schemas/TornCrimeId" }, "name": { "type": "string" @@ -9013,7 +14454,7 @@ }, "TornFactionHof": { "required": [ - "faction_id", + "id", "name", "members", "position", @@ -9021,7 +14462,7 @@ "values" ], "properties": { - "faction_id": { + "id": { "$ref": "#/components/schemas/FactionId" }, "name": { @@ -9736,7 +15177,6 @@ }, "details": { "description": "If the item 'type' is 'Armor' then TornItemArmorDetails is returned.
If the item 'type' is 'Weapon' then TornItemWeaponDetails is returned.
Otherwise, null is returned.", - "type": "object", "oneOf": [ { "$ref": "#/components/schemas/TornItemWeaponDetails" @@ -9862,19 +15302,23 @@ ], "properties": { "factionTree": { - "$ref": "#/components/schemas/TornFactionTree" + "type": "array", + "items": { + "$ref": "#/components/schemas/TornFactionTree" + } } }, "type": "object" }, "TornSelectionName": { - "description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','dirtybombs','education','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','properties','rackets','raidreport','raids','rockpaperscissors','searchforcash','shoplifting','stats','stocks','territory','territorynames','territorywarreport','territorywars'.", + "description": "The following selections will fallback to API v1 and may change at any time: 'bank','cards','cityshops','companies','competition','dirtybombs','gyms','honors','itemdetails','itemstats','medals','organisedcrimes','pawnshop','pokertables','properties','raidreport','raids','rockpaperscissors','searchforcash','shoplifting','stats','stocks'.\n * The following selections are not available in API v2: 'chainreport', 'rackets', 'rankedwarreport', 'rankedwars', 'territorynames', 'territorywarreport', 'territorywars'.", "type": "string", "enum": [ "attacklog", "bounties", "calendar", "crimes", + "education", "factionHof", "factiontree", "hof", @@ -9885,6 +15329,7 @@ "logtypes", "lookup", "subcrimes", + "territory", "timestamp", "bank", "cards", @@ -9892,7 +15337,6 @@ "companies", "competition", "dirtybombs", - "education", "gyms", "honors", "itemdetails", @@ -9902,20 +15346,13 @@ "pawnshop", "pokertables", "properties", - "rackets", "raidreport", "raids", - "rankedwarreport", - "rankedwars", "rockpaperscissors", "searchforcash", "shoplifting", "stats", - "stocks", - "territory", - "territorynames", - "territorywarreport", - "territorywars" + "stocks" ] }, "TornLookupResponse": { @@ -12437,7 +17874,6 @@ ], "properties": { "crimes": { - "type": "object", "oneOf": [ { "$ref": "#/components/schemas/PersonalStatsCrimesV1" @@ -12941,6 +18377,58 @@ "scammingskill" ] }, + "UserCurrentEducation": { + "required": [ + "id", + "until" + ], + "properties": { + "id": { + "$ref": "#/components/schemas/EducationId" + }, + "until": { + "type": "integer", + "format": "int32" + } + }, + "type": "object" + }, + "UserEducation": { + "required": [ + "complete", + "current" + ], + "properties": { + "complete": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EducationId" + } + }, + "current": { + "oneOf": [ + { + "$ref": "#/components/schemas/UserCurrentEducation" + }, + { + "type": "null" + } + ] + } + }, + "type": "object" + }, + "UserEducationResponse": { + "required": [ + "education" + ], + "properties": { + "education": { + "$ref": "#/components/schemas/UserEducation" + } + }, + "type": "object" + }, "UserCrimeDetailsBootlegging": { "required": [ "online_store", @@ -12986,7 +18474,7 @@ "horror", "romance", "thriller", - "sci-fi", + "sci_fi", "total", "earnings" ], @@ -13020,6 +18508,12 @@ "format": "int32" }, "sci-fi": { + "description": "This is replaced with 'sci_fi' field and will be removed on 1st June 2025.", + "type": "integer", + "format": "int32", + "deprecated": true + }, + "sci_fi": { "type": "integer", "format": "int32" }, @@ -13624,7 +19118,6 @@ }, "miscellaneous": { "description": " Miscellaneous stats for specific crime. Results differ based on the cat id.", - "type": "object", "oneOf": [ { "$ref": "#/components/schemas/UserCrimeDetailsBootlegging" @@ -14418,6 +19911,30 @@ "minimum": 1 } }, + "ApiLimit250Default20": { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20, + "maximum": 250, + "minimum": 1 + } + }, + "ApiLimit500Default20": { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20, + "maximum": 500, + "minimum": 1 + } + }, "ApiLimit1000": { "name": "limit", "in": "query", diff --git a/torn-api-codegen/src/model/enum.rs b/torn-api-codegen/src/model/enum.rs index ca8302f..382c1f1 100644 --- a/torn-api-codegen/src/model/enum.rs +++ b/torn-api-codegen/src/model/enum.rs @@ -15,26 +15,51 @@ pub enum EnumRepr { #[derive(Debug, Clone, PartialEq, Eq)] pub enum EnumVariantTupleValue { - Ref(String), + Ref { ty_name: String }, + ArrayOfRefs { ty_name: String }, } impl EnumVariantTupleValue { pub fn from_schema(schema: &OpenApiType) -> Option { - if let OpenApiType { - ref_path: Some(path), - .. - } = schema - { - Some(Self::Ref((*path).to_owned())) - } else { - None + match schema { + OpenApiType { + ref_path: Some(path), + .. + } => Some(Self::Ref { + ty_name: path.strip_prefix("#/components/schemas/")?.to_owned(), + }), + OpenApiType { + r#type: Some("array"), + items: Some(items), + .. + } => { + let OpenApiType { + ref_path: Some(path), + .. + } = items.as_ref() + else { + return None; + }; + Some(Self::ArrayOfRefs { + ty_name: path.strip_prefix("#/components/schemas/")?.to_owned(), + }) + } + _ => None, } } - pub fn name(&self) -> Option<&str> { - let Self::Ref(path) = self; + pub fn type_name(&self) -> &str { + match self { + Self::Ref { ty_name } => ty_name, + Self::ArrayOfRefs { ty_name } => ty_name, + } + } - path.strip_prefix("#/components/schemas/") + pub fn name(&self) -> String { + match self { + Self::Ref { ty_name } => ty_name.clone(), + Self::ArrayOfRefs { ty_name } => format!("{ty_name}s"), + } } } @@ -103,7 +128,7 @@ impl EnumVariant { let mut val_tys = Vec::with_capacity(values.len()); for value in values { - let ty_name = value.name()?; + let ty_name = value.type_name(); let ty_name = format_ident!("{ty_name}"); val_tys.push(quote! { @@ -216,7 +241,7 @@ impl Enum { for schema in schemas { let value = EnumVariantTupleValue::from_schema(schema)?; - let name = value.name()?.to_owned(); + let name = value.name(); result.variants.push(EnumVariant { name, @@ -253,11 +278,15 @@ impl Enum { let mut derives = vec![]; - if self.copy { - derives.extend_from_slice(&["Copy", "Hash"]); + if self.repr.is_some() { + derives.push(quote! { serde_repr::Deserialize_repr }); + } else { + derives.push(quote! { serde::Deserialize }); } - let derives = derives.into_iter().map(|d| format_ident!("{d}")); + if self.copy { + derives.push(quote! { Copy, Hash }); + } let serde_attr = self.untagged.then(|| { quote! { @@ -279,7 +308,7 @@ impl Enum { Some(quote! { #desc - #[derive(Debug, Clone, PartialEq, serde::Deserialize, #(#derives),*)] + #[derive(Debug, Clone, PartialEq, #(#derives),*)] #serde_attr pub enum #name { #(#variants),* diff --git a/torn-api-codegen/src/model/object.rs b/torn-api-codegen/src/model/object.rs index 1ae23fa..99fa7c3 100644 --- a/torn-api-codegen/src/model/object.rs +++ b/torn-api-codegen/src/model/object.rs @@ -280,7 +280,7 @@ impl Object { for (prop_name, prop) in props { // HACK: This will cause a duplicate key otherwise - if *prop_name == "itemDetails" { + if ["itemDetails", "sci-fi", "non-attackers", "co-leader_id"].contains(prop_name) { continue; } diff --git a/torn-api-codegen/src/model/parameter.rs b/torn-api-codegen/src/model/parameter.rs index efa076e..dbe87fd 100644 --- a/torn-api-codegen/src/model/parameter.rs +++ b/torn-api-codegen/src/model/parameter.rs @@ -217,6 +217,12 @@ impl Parameter { Self(inner) } } + + impl From for #name { + fn from(inner: i32) -> Self { + Self(inner) + } + } } }; @@ -317,6 +323,14 @@ The default value [Self::{}](self::{}#variant.{})"#, Ok(()) } } + + impl From for #name where T: IntoIterator { + fn from(value: T) -> #name { + let items = value.into_iter().collect(); + + Self(items) + } + } }); Some(code) diff --git a/torn-api-codegen/src/model/path.rs b/torn-api-codegen/src/model/path.rs index 59f499e..a188314 100644 --- a/torn-api-codegen/src/model/path.rs +++ b/torn-api-codegen/src/model/path.rs @@ -154,7 +154,7 @@ impl Path { PathParameter::Component(param) => (false, param), }; - let ty = match ¶m.r#type { + let (ty, builder_param) = match ¶m.r#type { ParameterType::I32 { .. } | ParameterType::Enum { .. } => { let ty_name = format_ident!("{}", param.name); @@ -162,31 +162,43 @@ impl Path { ns.push_element(param.codegen()?); let path = ns.get_ident(); - quote! { - crate::request::models::#path::#ty_name - } + ( + quote! { + crate::request::models::#path::#ty_name + }, + Some(quote! { #[builder(into)] }), + ) } else { - quote! { - crate::parameters::#ty_name - } + ( + quote! { + crate::parameters::#ty_name + }, + Some(quote! { #[builder(into)]}), + ) } } - ParameterType::String => quote! { String }, - ParameterType::Boolean => quote! { bool }, + ParameterType::String => (quote! { String }, None), + ParameterType::Boolean => (quote! { bool }, None), ParameterType::Schema { type_name } => { let ty_name = format_ident!("{}", type_name); - quote! { - crate::models::#ty_name - } + ( + quote! { + crate::models::#ty_name + }, + None, + ) } ParameterType::Array { .. } => { ns.push_element(param.codegen()?); let ty_name = param.r#type.codegen_type_name(¶m.name); let path = ns.get_ident(); - quote! { - crate::request::models::#path::#ty_name - } + ( + quote! { + crate::request::models::#path::#ty_name + }, + Some(quote! { #[builder(into)] }), + ) } }; @@ -199,6 +211,7 @@ impl Path { let path_name = format_ident!("{}", param.value); start_fields.push(quote! { #[builder(start_fn)] + #builder_param pub #name: #ty }); fmt_val.push(quote! { @@ -218,6 +231,7 @@ impl Path { }; fields.push(quote! { + #builder_param pub #name: #ty }); } @@ -260,7 +274,7 @@ impl Path { #ns #[derive(Debug, Clone, bon::Builder)] - #[builder(state_mod(vis = "pub(crate)"))] + #[builder(state_mod(vis = "pub(crate)"), on(String, into))] pub struct #name { #(#start_fields),* } diff --git a/torn-api/src/scopes.rs b/torn-api/src/scopes.rs index 85b6dfe..98415c1 100644 --- a/torn-api/src/scopes.rs +++ b/torn-api/src/scopes.rs @@ -6,7 +6,13 @@ pub(super) mod test { use tokio::sync::mpsc; - use crate::executor::ReqwestClient; + use crate::{ + executor::{ExecutorExt, ReqwestClient}, + models::{ + AttackCode, FactionSelectionName, PersonalStatsCategoryEnum, PersonalStatsStatName, + UserListEnum, + }, + }; use super::*; @@ -54,6 +60,21 @@ pub(super) mod test { rx.recv().await.unwrap() } + #[tokio::test] + async fn faction() { + let client = test_client().await; + + let r = client + .faction() + .for_selections(|b| { + b.selections([FactionSelectionName::Basic, FactionSelectionName::Balance]) + }) + .await + .unwrap(); + + r.faction_basic_response().unwrap(); + } + #[tokio::test] async fn faction_applications() { let client = test_client().await; @@ -193,7 +214,7 @@ pub(super) mod test { let faction_scope = FactionScope(&client); faction_scope - .crime_for_id(468347.into(), |b| b) + .crime_for_crime_id(468347.into(), |b| b) .await .unwrap(); } @@ -277,7 +298,7 @@ pub(super) mod test { let faction_scope = FactionScope(&client); faction_scope - .rankedwarreport_for_id(24424.into(), |b| b) + .rankedwarreport_for_ranked_war_id(24424.into(), |b| b) .await .unwrap(); } @@ -337,7 +358,7 @@ pub(super) mod test { } #[tokio::test] - async fn lookup() { + async fn faction_lookup() { let client = test_client().await; let faction_scope = FactionScope(&client); @@ -520,7 +541,7 @@ pub(super) mod test { let racing_scope = TornScope(&client); racing_scope - .attacklog(|b| b.log("ec987a60a22155cbfb7c1625cbb2092f".to_owned())) + .attacklog(|b| b.log(AttackCode("ec987a60a22155cbfb7c1625cbb2092f".to_owned()))) .await .unwrap(); } @@ -661,7 +682,7 @@ pub(super) mod test { let torn_scope = TornScope(&client); torn_scope - .subcrimes_for_crime_id("3".into(), |b| b) + .subcrimes_for_crime_id(3.into(), |b| b) .await .unwrap(); } @@ -669,7 +690,6 @@ pub(super) mod test { #[tokio::test] async fn torn_lookup() { let client = test_client().await; - let torn_scope = TornScope(&client); torn_scope.lookup(|b| b).await.unwrap(); @@ -683,4 +703,255 @@ pub(super) mod test { torn_scope.timestamp(|b| b).await.unwrap(); } + + #[tokio::test] + async fn user_attacks() { + let client = test_client().await; + + client.user().attacks(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_attacksfull() { + let client = test_client().await; + + client.user().attacksfull(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_bounties() { + let client = test_client().await; + + client.user().bounties(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_bounties_for_id() { + let client = test_client().await; + + client + .user() + .bounties_for_id(986228.into(), |b| b) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_calendar() { + let client = test_client().await; + + client.user().calendar(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_crimes_for_crime_id() { + let client = test_client().await; + + client + .user() + .crimes_for_crime_id(10.into(), |b| b) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_enlisted_cars() { + let client = test_client().await; + + client.user().enlistedcars(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_factionbalance() { + let client = test_client().await; + + client.user().factionbalance(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumfeed() { + let client = test_client().await; + + client.user().forumfeed(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumfriends() { + let client = test_client().await; + + client.user().forumfriends(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumposts() { + let client = test_client().await; + + client.user().forumposts(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumposts_for_id() { + let client = test_client().await; + + client + .user() + .forumposts_for_id(1.into(), |b| b) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_forumsubscribedthreads() { + let client = test_client().await; + + client.user().forumsubscribedthreads(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumthreads() { + let client = test_client().await; + + client.user().forumthreads(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_forumthreads_for_id() { + let client = test_client().await; + + client + .user() + .forumthreads_for_id(1.into(), |b| b) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_hof() { + let client = test_client().await; + + client.user().hof(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_hof_for_id() { + let client = test_client().await; + + client.user().hof_for_id(1.into(), |b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_itemmarket() { + let client = test_client().await; + + client.user().itemmarket(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_jobranks() { + let client = test_client().await; + + client.user().jobranks(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_list() { + let client = test_client().await; + + client + .user() + .list(|b| b.cat(UserListEnum::Friends)) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_organizedcrime() { + let client = test_client().await; + + client.user().organizedcrime(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_personalstats() { + let client = test_client().await; + + client + .user() + .personalstats(|b| { + b.stat([PersonalStatsStatName::Piercinghits]) + .timestamp(1737661955) + }) + .await + .unwrap(); + + client + .user() + .personalstats(|b| b.cat(PersonalStatsCategoryEnum::All)) + .await + .unwrap(); + + client + .user() + .personalstats(|b| b.cat(PersonalStatsCategoryEnum::Popular)) + .await + .unwrap(); + + client + .user() + .personalstats(|b| b.cat(PersonalStatsCategoryEnum::Drugs)) + .await + .unwrap(); + + client + .user() + .personalstats(|b| b.stat([PersonalStatsStatName::Piercinghits])) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_personalstats_for_id() { + let client = test_client().await; + + client + .user() + .personalstats_for_id(1.into(), |b| b.cat(PersonalStatsCategoryEnum::All)) + .await + .unwrap(); + } + + #[tokio::test] + async fn user_races() { + let client = test_client().await; + + client.user().races(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_revives() { + let client = test_client().await; + + client.user().revives(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_revivesfull() { + let client = test_client().await; + + client.user().revives_full(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_lookup() { + let client = test_client().await; + + client.user().lookup(|b| b).await.unwrap(); + } + + #[tokio::test] + async fn user_timestamp() { + let client = test_client().await; + + client.user().attacks(|b| b).await.unwrap(); + } }