mirror of
https://github.com/Nikolay-Shirokov/cc-1c-skills.git
synced 2026-09-20 17:25:52 +03:00
fix(epf-build): конвертация в заглушку не калечит имена с суффиксом вида объекта
Замена ExternalReport. -> Report. шла по всему тексту XML и попадала внутрь
имени объекта, если оно оканчивается так же (ПриёмкаExternalReport). Имя берётся
из <Name> до замены и остаётся авторским везде — в имени файла, GeneratedType и
составе конфигурации, — а ссылка в скопированном XML расходилась с ним, и
заглушка не грузилась: «Неизвестный объект метаданных - Report.ПриёмкаReport…».
Заменяется только префикс вида объекта в начале квалифицированного имени.
Регрессии строят фикстуру навыками (erf-init --WithSKD, epf-init, form-add) —
так в кейс попадает и настоящая ссылка вида cfg:ExternalReportObject.<Имя>.
Соседние кейсы каталога переведены на {fakePlatform} и прямые слэши.
Closes #90
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
56b0c0cfd7
commit
e2c7f38518
@@ -1,4 +1,4 @@
|
|||||||
# stub-db-create v1.10 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.11 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
param(
|
param(
|
||||||
[Parameter(Mandatory)]
|
[Parameter(Mandatory)]
|
||||||
@@ -387,6 +387,16 @@ if ($needsRegistrator) {
|
|||||||
#
|
#
|
||||||
# Подстановка типа делается ТОЛЬКО в .xml (это DefaultForm и основной реквизит формы); в .bsl
|
# Подстановка типа делается ТОЛЬКО в .xml (это DefaultForm и основной реквизит формы); в .bsl
|
||||||
# такой же текст был бы кодом, и трогать его нельзя.
|
# такой же текст был бы кодом, и трогать его нельзя.
|
||||||
|
function Convert-RefTags {
|
||||||
|
param([string]$Text, [string]$ExtTag, [string]$CfgTag)
|
||||||
|
|
||||||
|
# Только префикс вида объекта в начале квалифицированного имени. Глобальная замена подстроки
|
||||||
|
# резала бы и имя самого объекта, если оно оканчивается так же (ПриёмкаExternalReport), —
|
||||||
|
# ссылка расходилась с именем, и заглушка не грузилась. [regex]::Replace, а не -replace:
|
||||||
|
# оператор регистронезависим, а теги 1С регистрозависимы.
|
||||||
|
return [regex]::Replace($Text, "(?<![\w.])$ExtTag(Object)?\.", ($CfgTag + '$1.'))
|
||||||
|
}
|
||||||
|
|
||||||
function Add-SourceObjectToConfig {
|
function Add-SourceObjectToConfig {
|
||||||
param([string]$SourceXml, [string]$CfgDir)
|
param([string]$SourceXml, [string]$CfgDir)
|
||||||
|
|
||||||
@@ -416,7 +426,7 @@ function Add-SourceObjectToConfig {
|
|||||||
|
|
||||||
$conv = $reGuid.Replace($text, $reissue)
|
$conv = $reGuid.Replace($text, $reissue)
|
||||||
$conv = $conv.Replace("<$extTag ", "<$cfgTag ").Replace("<$extTag>", "<$cfgTag>").Replace("</$extTag>", "</$cfgTag>")
|
$conv = $conv.Replace("<$extTag ", "<$cfgTag ").Replace("<$extTag>", "<$cfgTag>").Replace("</$extTag>", "</$cfgTag>")
|
||||||
$conv = $conv.Replace("${extTag}Object.", "${cfgTag}Object.").Replace("$extTag.", "$cfgTag.")
|
$conv = Convert-RefTags $conv $extTag $cfgTag
|
||||||
|
|
||||||
# Тип менеджера у внешней обработки не объявлен, а объекту конфигурации он обязателен:
|
# Тип менеджера у внешней обработки не объявлен, а объекту конфигурации он обязателен:
|
||||||
# без него платформа отвечает «отсутствует один или более типов объекта».
|
# без него платформа отвечает «отсутствует один или более типов объекта».
|
||||||
@@ -454,7 +464,7 @@ function Add-SourceObjectToConfig {
|
|||||||
if ($f.Extension -ieq '.xml') {
|
if ($f.Extension -ieq '.xml') {
|
||||||
$t = [IO.File]::ReadAllText($f.FullName, [Text.Encoding]::UTF8)
|
$t = [IO.File]::ReadAllText($f.FullName, [Text.Encoding]::UTF8)
|
||||||
$t = $reGuid.Replace($t, $reissue)
|
$t = $reGuid.Replace($t, $reissue)
|
||||||
$t = $t.Replace("${extTag}Object.", "${cfgTag}Object.").Replace("$extTag.", "$cfgTag.")
|
$t = Convert-RefTags $t $extTag $cfgTag
|
||||||
[IO.File]::WriteAllText($dst, $t, $encBom)
|
[IO.File]::WriteAllText($dst, $t, $encBom)
|
||||||
} else {
|
} else {
|
||||||
Copy-Item -Path $f.FullName -Destination $dst -Force
|
Copy-Item -Path $f.FullName -Destination $dst -Force
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# stub-db-create v1.10 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
# stub-db-create v1.11 — Create temp 1C infobase with metadata stubs for EPF/ERF build
|
||||||
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -1133,6 +1133,14 @@ def write_bom(path, content):
|
|||||||
GUID_RE = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
|
GUID_RE = re.compile(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}')
|
||||||
|
|
||||||
|
|
||||||
|
def retag_refs(text, ext_tag, cfg_tag):
|
||||||
|
# Только префикс вида объекта в начале квалифицированного имени. Глобальная замена подстроки
|
||||||
|
# резала бы и имя самого объекта, если оно оканчивается так же (ПриёмкаExternalReport), —
|
||||||
|
# ссылка расходилась с именем, и заглушка не грузилась.
|
||||||
|
return re.sub(r'(?<![\w.])%s(Object)?\.' % ext_tag,
|
||||||
|
lambda m: cfg_tag + (m.group(1) or '') + '.', text)
|
||||||
|
|
||||||
|
|
||||||
def add_source_object_to_config(source_xml, cfg_dir):
|
def add_source_object_to_config(source_xml, cfg_dir):
|
||||||
# Копия объекта живёт в конфигурации базы, а следом в ту же базу грузится исходник как ВНЕШНЯЯ
|
# Копия объекта живёт в конфигурации базы, а следом в ту же базу грузится исходник как ВНЕШНЯЯ
|
||||||
# обработка. С одинаковыми идентификаторами платформа путает их и через раз отвечает «Исключение
|
# обработка. С одинаковыми идентификаторами платформа путает их и через раз отвечает «Исключение
|
||||||
@@ -1163,7 +1171,7 @@ def add_source_object_to_config(source_xml, cfg_dir):
|
|||||||
conv = reissue(text)
|
conv = reissue(text)
|
||||||
conv = conv.replace('<%s ' % ext_tag, '<%s ' % cfg_tag).replace('<%s>' % ext_tag, '<%s>' % cfg_tag)
|
conv = conv.replace('<%s ' % ext_tag, '<%s ' % cfg_tag).replace('<%s>' % ext_tag, '<%s>' % cfg_tag)
|
||||||
conv = conv.replace('</%s>' % ext_tag, '</%s>' % cfg_tag)
|
conv = conv.replace('</%s>' % ext_tag, '</%s>' % cfg_tag)
|
||||||
conv = conv.replace('%sObject.' % ext_tag, '%sObject.' % cfg_tag).replace('%s.' % ext_tag, '%s.' % cfg_tag)
|
conv = retag_refs(conv, ext_tag, cfg_tag)
|
||||||
|
|
||||||
# Тип менеджера у внешней обработки не объявлен, а объекту конфигурации он обязателен:
|
# Тип менеджера у внешней обработки не объявлен, а объекту конфигурации он обязателен:
|
||||||
# без него платформа отвечает «отсутствует один или более типов объекта».
|
# без него платформа отвечает «отсутствует один или более типов объекта».
|
||||||
@@ -1200,7 +1208,7 @@ def add_source_object_to_config(source_xml, cfg_dir):
|
|||||||
with io.open(full, encoding='utf-8-sig') as fh:
|
with io.open(full, encoding='utf-8-sig') as fh:
|
||||||
t = fh.read()
|
t = fh.read()
|
||||||
t = reissue(t)
|
t = reissue(t)
|
||||||
t = t.replace('%sObject.' % ext_tag, '%sObject.' % cfg_tag).replace('%s.' % ext_tag, '%s.' % cfg_tag)
|
t = retag_refs(t, ext_tag, cfg_tag)
|
||||||
write_bom(dst, t)
|
write_bom(dst, t)
|
||||||
else:
|
else:
|
||||||
shutil.copyfile(full, dst)
|
shutil.copyfile(full, dst)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Внешняя обработка конвертируется в объект конфигурации",
|
"name": "Внешняя обработка конвертируется в объект конфигурации",
|
||||||
"osOnly": "win32",
|
|
||||||
"fakePlatform": {
|
"fakePlatform": {
|
||||||
"exit": 1,
|
"exit": 1,
|
||||||
"log": ""
|
"log": ""
|
||||||
@@ -27,18 +26,18 @@
|
|||||||
],
|
],
|
||||||
"args_extra": [
|
"args_extra": [
|
||||||
"-SourceDir",
|
"-SourceDir",
|
||||||
"{workDir}\\src",
|
"{workDir}/src",
|
||||||
"-V8Path",
|
"-V8Path",
|
||||||
"{workDir}\\fake.cmd",
|
"{fakePlatform}",
|
||||||
"-TempBasePath",
|
"-TempBasePath",
|
||||||
"{workDir}\\base",
|
"{workDir}/base",
|
||||||
"-EmbedSourceFile",
|
"-EmbedSourceFile",
|
||||||
"{workDir}\\src\\Проба.xml"
|
"{workDir}/src/Проба.xml"
|
||||||
],
|
],
|
||||||
"expect": {
|
"expect": {
|
||||||
"fileContains": [
|
"fileContains": [
|
||||||
{
|
{
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба.xml",
|
"file": "base/cfg/DataProcessors/Проба.xml",
|
||||||
"text": [
|
"text": [
|
||||||
"<DataProcessor uuid=",
|
"<DataProcessor uuid=",
|
||||||
"<xr:GeneratedType name=\"DataProcessorObject.Проба\" category=\"Object\">",
|
"<xr:GeneratedType name=\"DataProcessorObject.Проба\" category=\"Object\">",
|
||||||
@@ -47,12 +46,12 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "base\\cfg\\Configuration.xml",
|
"file": "base/cfg/Configuration.xml",
|
||||||
"text": "<DataProcessor>Проба</DataProcessor>"
|
"text": "<DataProcessor>Проба</DataProcessor>"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fileNotContains": {
|
"fileNotContains": {
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба.xml",
|
"file": "base/cfg/DataProcessors/Проба.xml",
|
||||||
"text": [
|
"text": [
|
||||||
"<ExternalDataProcessor",
|
"<ExternalDataProcessor",
|
||||||
"ExternalDataProcessorObject."
|
"ExternalDataProcessorObject."
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "Модуль копируется байт в байт",
|
"name": "Модуль копируется байт в байт",
|
||||||
"osOnly": "win32",
|
|
||||||
"fakePlatform": {
|
"fakePlatform": {
|
||||||
"exit": 1,
|
"exit": 1,
|
||||||
"log": ""
|
"log": ""
|
||||||
@@ -27,13 +26,13 @@
|
|||||||
],
|
],
|
||||||
"args_extra": [
|
"args_extra": [
|
||||||
"-SourceDir",
|
"-SourceDir",
|
||||||
"{workDir}\\src",
|
"{workDir}/src",
|
||||||
"-V8Path",
|
"-V8Path",
|
||||||
"{workDir}\\fake.cmd",
|
"{fakePlatform}",
|
||||||
"-TempBasePath",
|
"-TempBasePath",
|
||||||
"{workDir}\\base",
|
"{workDir}/base",
|
||||||
"-EmbedSourceFile",
|
"-EmbedSourceFile",
|
||||||
"{workDir}\\src\\Проба.xml"
|
"{workDir}/src/Проба.xml"
|
||||||
],
|
],
|
||||||
"expect": {
|
"expect": {
|
||||||
"filesEqual": [
|
"filesEqual": [
|
||||||
@@ -43,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fileContains": {
|
"fileContains": {
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба\\Ext\\ObjectModule.bsl",
|
"file": "base/cfg/DataProcessors/Проба/Ext/ObjectModule.bsl",
|
||||||
"text": "ExternalDataProcessorObject.Проба"
|
"text": "ExternalDataProcessorObject.Проба"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{
|
||||||
|
"name": "Имя, оканчивающееся на ExternalDataProcessor, не калечится в ссылках",
|
||||||
|
"fakePlatform": {
|
||||||
|
"exit": 1,
|
||||||
|
"log": ""
|
||||||
|
},
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "epf-init/scripts/init",
|
||||||
|
"args": {
|
||||||
|
"-Name": "ТестExternalDataProcessor",
|
||||||
|
"-SrcDir": "{workDir}/src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": "form-add/scripts/form-add",
|
||||||
|
"args": {
|
||||||
|
"-ObjectPath": "{workDir}/src/ТестExternalDataProcessor.xml",
|
||||||
|
"-FormName": "Форма",
|
||||||
|
"-SetDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args_extra": [
|
||||||
|
"-SourceDir",
|
||||||
|
"{workDir}/src",
|
||||||
|
"-V8Path",
|
||||||
|
"{fakePlatform}",
|
||||||
|
"-TempBasePath",
|
||||||
|
"{workDir}/base",
|
||||||
|
"-EmbedSourceFile",
|
||||||
|
"{workDir}/src/ТестExternalDataProcessor.xml"
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"fileContains": [
|
||||||
|
{
|
||||||
|
"file": "base/cfg/DataProcessors/ТестExternalDataProcessor.xml",
|
||||||
|
"text": [
|
||||||
|
"<Name>ТестExternalDataProcessor</Name>",
|
||||||
|
"<DefaultForm>DataProcessor.ТестExternalDataProcessor.Form.Форма</DefaultForm>",
|
||||||
|
"<xr:GeneratedType name=\"DataProcessorObject.ТестExternalDataProcessor\" category=\"Object\">",
|
||||||
|
"<xr:GeneratedType name=\"DataProcessorManager.ТестExternalDataProcessor\" category=\"Manager\">"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/DataProcessors/ТестExternalDataProcessor/Forms/Форма/Ext/Form.xml",
|
||||||
|
"text": "<v8:Type>cfg:DataProcessorObject.ТестExternalDataProcessor</v8:Type>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Configuration.xml",
|
||||||
|
"text": "<DataProcessor>ТестExternalDataProcessor</DataProcessor>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fileNotContains": [
|
||||||
|
{
|
||||||
|
"file": "base/cfg/DataProcessors/ТестExternalDataProcessor.xml",
|
||||||
|
"text": [
|
||||||
|
"ТестDataProcessor",
|
||||||
|
"<ExternalDataProcessor ",
|
||||||
|
">ExternalDataProcessor."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/DataProcessors/ТестExternalDataProcessor/Forms/Форма/Ext/Form.xml",
|
||||||
|
"text": "ТестDataProcessor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expectError": true,
|
||||||
|
"noSnapshot": "платформа фейковая, а GUID копии перевыпускаются случайными — проверяется сгенерированная конфигурация"
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"name": "Имя, оканчивающееся на ExternalReport, не калечится в ссылках",
|
||||||
|
"fakePlatform": {
|
||||||
|
"exit": 1,
|
||||||
|
"log": ""
|
||||||
|
},
|
||||||
|
"preRun": [
|
||||||
|
{
|
||||||
|
"script": "erf-init/scripts/init",
|
||||||
|
"args": {
|
||||||
|
"-Name": "ПриёмкаExternalReport",
|
||||||
|
"-SrcDir": "{workDir}/src",
|
||||||
|
"-WithSKD": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"script": "form-add/scripts/form-add",
|
||||||
|
"args": {
|
||||||
|
"-ObjectPath": "{workDir}/src/ПриёмкаExternalReport.xml",
|
||||||
|
"-FormName": "Форма",
|
||||||
|
"-SetDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"args_extra": [
|
||||||
|
"-SourceDir",
|
||||||
|
"{workDir}/src",
|
||||||
|
"-V8Path",
|
||||||
|
"{fakePlatform}",
|
||||||
|
"-TempBasePath",
|
||||||
|
"{workDir}/base",
|
||||||
|
"-EmbedSourceFile",
|
||||||
|
"{workDir}/src/ПриёмкаExternalReport.xml"
|
||||||
|
],
|
||||||
|
"expect": {
|
||||||
|
"fileContains": [
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Reports/ПриёмкаExternalReport.xml",
|
||||||
|
"text": [
|
||||||
|
"<Name>ПриёмкаExternalReport</Name>",
|
||||||
|
"<DefaultForm>Report.ПриёмкаExternalReport.Form.Форма</DefaultForm>",
|
||||||
|
"<xr:GeneratedType name=\"ReportObject.ПриёмкаExternalReport\" category=\"Object\">",
|
||||||
|
"<xr:GeneratedType name=\"ReportManager.ПриёмкаExternalReport\" category=\"Manager\">",
|
||||||
|
"<MainDataCompositionSchema>Report.ПриёмкаExternalReport.Template.ОсновнаяСхемаКомпоновкиДанных</MainDataCompositionSchema>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Reports/ПриёмкаExternalReport/Forms/Форма/Ext/Form.xml",
|
||||||
|
"text": "<v8:Type>cfg:ReportObject.ПриёмкаExternalReport</v8:Type>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Configuration.xml",
|
||||||
|
"text": "<Report>ПриёмкаExternalReport</Report>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"fileNotContains": [
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Reports/ПриёмкаExternalReport.xml",
|
||||||
|
"text": [
|
||||||
|
"ПриёмкаReport",
|
||||||
|
"<ExternalReport ",
|
||||||
|
">ExternalReport."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"file": "base/cfg/Reports/ПриёмкаExternalReport/Forms/Форма/Ext/Form.xml",
|
||||||
|
"text": "ПриёмкаReport"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"expectError": true,
|
||||||
|
"noSnapshot": "платформа фейковая, а GUID копии перевыпускаются случайными — проверяется сгенерированная конфигурация"
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "У копии все GUID свои",
|
"name": "У копии все GUID свои",
|
||||||
"osOnly": "win32",
|
|
||||||
"fakePlatform": {
|
"fakePlatform": {
|
||||||
"exit": 1,
|
"exit": 1,
|
||||||
"log": ""
|
"log": ""
|
||||||
@@ -27,18 +26,18 @@
|
|||||||
],
|
],
|
||||||
"args_extra": [
|
"args_extra": [
|
||||||
"-SourceDir",
|
"-SourceDir",
|
||||||
"{workDir}\\src",
|
"{workDir}/src",
|
||||||
"-V8Path",
|
"-V8Path",
|
||||||
"{workDir}\\fake.cmd",
|
"{fakePlatform}",
|
||||||
"-TempBasePath",
|
"-TempBasePath",
|
||||||
"{workDir}\\base",
|
"{workDir}/base",
|
||||||
"-EmbedSourceFile",
|
"-EmbedSourceFile",
|
||||||
"{workDir}\\src\\Проба.xml"
|
"{workDir}/src/Проба.xml"
|
||||||
],
|
],
|
||||||
"expect": {
|
"expect": {
|
||||||
"fileNotContains": [
|
"fileNotContains": [
|
||||||
{
|
{
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба.xml",
|
"file": "base/cfg/DataProcessors/Проба.xml",
|
||||||
"text": [
|
"text": [
|
||||||
"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb",
|
"aaaaaaaa-1111-2222-3333-bbbbbbbbbbbb",
|
||||||
"cccccccc-4444-5555-6666-dddddddddddd",
|
"cccccccc-4444-5555-6666-dddddddddddd",
|
||||||
@@ -46,12 +45,12 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба\\Forms\\Форма.xml",
|
"file": "base/cfg/DataProcessors/Проба/Forms/Форма.xml",
|
||||||
"text": "11111111-2222-3333-4444-555555555555"
|
"text": "11111111-2222-3333-4444-555555555555"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fileContains": {
|
"fileContains": {
|
||||||
"file": "base\\cfg\\DataProcessors\\Проба.xml",
|
"file": "base/cfg/DataProcessors/Проба.xml",
|
||||||
"text": "<xr:TypeId>"
|
"text": "<xr:TypeId>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user