diff --git a/.claude/skills/meta-compile/scripts/meta-compile.ps1 b/.claude/skills/meta-compile/scripts/meta-compile.ps1 index b12fe6e7..7c48bd17 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.ps1 +++ b/.claude/skills/meta-compile/scripts/meta-compile.ps1 @@ -1,4 +1,4 @@ -# meta-compile v1.57 — Compile 1C metadata object from JSON +# meta-compile v1.58 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)] @@ -348,7 +348,7 @@ $validTypes = @("Catalog","Document","Enum","Constant","InformationRegister","Ac "ChartOfCalculationTypes","BusinessProcess","Task","ExchangePlan","DocumentJournal", "Report","DataProcessor","CommonModule","ScheduledJob","EventSubscription", "HTTPService","WebService","DefinedType","FunctionalOption", - "Sequence","FilterCriterion","DocumentNumerator","SettingsStorage") + "Sequence","FilterCriterion","DocumentNumerator","SettingsStorage","CommonForm") if ($objType -notin $validTypes) { Write-Error "Unsupported type: $objType. Valid: $($validTypes -join ', ')" exit 1 @@ -2624,6 +2624,30 @@ function Emit-SettingsStorageProperties { Emit-VerbatimRef $i "AuxiliaryLoadForm" $def.auxiliaryLoadForm } +function Emit-CommonFormProperties { + param([string]$indent) + $i = $indent + X "$i$(Esc-Xml $objName)" + Emit-MLText $i "Synonym" $synonym + if ($def.comment) { X "$i$(Esc-XmlText $def.comment)" } else { X "$i" } + X "$i$(Get-EnumProp 'FormType' 'formType' 'Managed')" + $inclHelp = if (Get-BoolProp "includeHelpInContents" $false) { "true" } else { "false" } + X "$i$inclHelp" + # UsePurposes — назначения (использование в приложениях). Дефолт [PlatformApplication, MobilePlatformApplication]. + $purposes = if ($def.usePurposes) { @($def.usePurposes) } else { @('PlatformApplication', 'MobilePlatformApplication') } + if ($purposes.Count -gt 0) { + X "$i" + foreach ($p in $purposes) { X "$i`t$p" } + X "$i" + } else { + X "$i" + } + $useStdCmds = if (Get-BoolProp "useStandardCommands" $false) { "true" } else { "false" } + X "$i$useStdCmds" + Emit-MLText $i "ExtendedPresentation" $def.extendedPresentation + Emit-MLText $i "Explanation" $def.explanation +} + # Измерение последовательности: Name/Synonym/Comment/Type + DocumentMap/RegisterRecordsMap (списки MDObjectRef — # соответствие измерения реквизитам документов/движениям регистров). function Emit-SequenceDimension { @@ -3731,6 +3755,7 @@ switch ($objType) { "FilterCriterion" { Emit-FilterCriterionProperties "`t`t`t" } "DocumentNumerator" { Emit-DocumentNumeratorProperties "`t`t`t" } "SettingsStorage" { Emit-SettingsStorageProperties "`t`t`t" } + "CommonForm" { Emit-CommonFormProperties "`t`t`t" } "CommonModule" { Emit-CommonModuleProperties "`t`t`t" } "ScheduledJob" { Emit-ScheduledJobProperties "`t`t`t" } "EventSubscription" { Emit-EventSubscriptionProperties "`t`t`t" } @@ -4065,6 +4090,7 @@ $script:typePluralMap = @{ "FilterCriterion" = "FilterCriteria" "DocumentNumerator" = "DocumentNumerators" "SettingsStorage" = "SettingsStorages" + "CommonForm" = "CommonForms" } $typePlural = $script:typePluralMap[$objType] @@ -4342,6 +4368,25 @@ if ($objType -in $typesWithModule) { $modulesCreated += $modulePath } } +# CommonForm — заготовка структуры формы под компиляцию: Ext/Form.xml (пустая управляемая форма) + Ext/Form/Module.bsl. +# Содержимое формы наполняет form-compile/form-edit (не перезаписываем существующее). +if ($objType -eq "CommonForm") { + Ensure-ExtDir + $cfFormXmlPath = Join-Path $extDir "Form.xml" + if (-not (Test-Path $cfFormXmlPath)) { + $cfFormNs = 'xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core" xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' + $cfFormXml = "`n
`n`t`n`t`ttrue`n`t`n`t`n`n" + [System.IO.File]::WriteAllText($cfFormXmlPath, $cfFormXml, $enc) + $modulesCreated += $cfFormXmlPath + } + $cfModuleDir = Join-Path $extDir "Form" + if (-not (Test-Path $cfModuleDir)) { New-Item -ItemType Directory -Path $cfModuleDir -Force | Out-Null } + $cfModulePath = Join-Path $cfModuleDir "Module.bsl" + if (-not (Test-Path $cfModulePath)) { + [System.IO.File]::WriteAllText($cfModulePath, "", $enc) + $modulesCreated += $cfModulePath + } +} # Special files # --- Состав плана обмена (ExchangePlan, Ext/Content.xml). Ключ `content`/`Состав`: diff --git a/.claude/skills/meta-compile/scripts/meta-compile.py b/.claude/skills/meta-compile/scripts/meta-compile.py index f9163701..e81ec7d9 100644 --- a/.claude/skills/meta-compile/scripts/meta-compile.py +++ b/.claude/skills/meta-compile/scripts/meta-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# meta-compile v1.57 — Compile 1C metadata object from JSON +# meta-compile v1.58 — Compile 1C metadata object from JSON # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -463,6 +463,7 @@ valid_types = [ 'EventSubscription', 'HTTPService', 'WebService', 'DefinedType', 'FunctionalOption', 'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage', + 'CommonForm', ] if obj_type not in valid_types: print(f"Unsupported type: {obj_type}. Valid: {', '.join(valid_types)}", file=sys.stderr) @@ -2630,6 +2631,30 @@ def emit_settings_storage_properties(indent): emit_verbatim_ref(i, 'AuxiliarySaveForm', defn.get('auxiliarySaveForm')) emit_verbatim_ref(i, 'AuxiliaryLoadForm', defn.get('auxiliaryLoadForm')) +def emit_common_form_properties(indent): + i = indent + X(f'{i}{esc_xml(obj_name)}') + emit_mltext(i, 'Synonym', synonym) + if defn.get('comment'): + X(f'{i}{esc_xml_text(str(defn["comment"]))}') + else: + X(f'{i}') + X(f'{i}{get_enum_prop("FormType", "formType", "Managed")}') + incl_help = 'true' if get_bool_prop('includeHelpInContents', False) else 'false' + X(f'{i}{incl_help}') + purposes = list(defn['usePurposes']) if defn.get('usePurposes') else ['PlatformApplication', 'MobilePlatformApplication'] + if purposes: + X(f'{i}') + for p in purposes: + X(f'{i}\t{p}') + X(f'{i}') + else: + X(f'{i}') + use_std_cmds = 'true' if get_bool_prop('useStandardCommands', False) else 'false' + X(f'{i}{use_std_cmds}') + emit_mltext(i, 'ExtendedPresentation', defn.get('extendedPresentation')) + emit_mltext(i, 'Explanation', defn.get('explanation')) + def emit_sequence_dimension(indent, dim_def): uid = new_uuid() parsed = parse_attribute_shorthand(dim_def) @@ -3615,6 +3640,7 @@ property_emitters = { 'FilterCriterion': emit_filter_criterion_properties, 'DocumentNumerator': emit_document_numerator_properties, 'SettingsStorage': emit_settings_storage_properties, + 'CommonForm': emit_common_form_properties, 'CommonModule': emit_common_module_properties, 'ScheduledJob': emit_scheduled_job_properties, 'EventSubscription': emit_event_subscription_properties, @@ -3933,6 +3959,7 @@ type_plural_map = { 'FilterCriterion': 'FilterCriteria', 'DocumentNumerator': 'DocumentNumerators', 'SettingsStorage': 'SettingsStorages', + 'CommonForm': 'CommonForms', } type_plural = type_plural_map[obj_type] @@ -4006,6 +4033,31 @@ if obj_type in types_with_module: write_utf8_bom(module_path, '') modules_created.append(module_path) +# CommonForm — заготовка структуры формы под компиляцию (form-compile наполняет содержимое). +if obj_type == 'CommonForm': + ensure_ext_dir() + cf_form_xml_path = os.path.join(ext_dir, 'Form.xml') + if not os.path.isfile(cf_form_xml_path): + cf_ns = ('xmlns="http://v8.1c.ru/8.3/xcf/logform" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" ' + 'xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:dcscor="http://v8.1c.ru/8.1/data-composition-system/core" ' + 'xmlns:dcsset="http://v8.1c.ru/8.1/data-composition-system/settings" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" ' + 'xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" ' + 'xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" ' + 'xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" ' + 'xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" ' + 'xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"') + cf_form_xml = ('\n
\n' + '\t\n\t\ttrue\n\t\n' + '\t\n\n') + write_utf8_bom(cf_form_xml_path, cf_form_xml) + modules_created.append(cf_form_xml_path) + cf_module_dir = os.path.join(ext_dir, 'Form') + os.makedirs(cf_module_dir, exist_ok=True) + cf_module_path = os.path.join(cf_module_dir, 'Module.bsl') + if not os.path.isfile(cf_module_path): + write_utf8_bom(cf_module_path, '') + modules_created.append(cf_module_path) + # --- Predefined data (Ext/Predefined.xml). Элемент: "(Код) Имя [Наименование]" ИЛИ объект (+рус. синонимы). # Наименование: нет [..]/ключа → авто(Split-CamelCase); [] / "" → пусто; [текст]/текст → как есть. def resolve_predef_item(val): diff --git a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 index d6d32140..065ba849 100644 --- a/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 +++ b/.claude/skills/meta-decompile/scripts/meta-decompile.ps1 @@ -1,4 +1,4 @@ -# meta-decompile v0.48 — XML объекта метаданных 1С → JSON-черновик формата meta-compile +# meta-decompile v0.49 — XML объекта метаданных 1С → JSON-черновик формата meta-compile # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # # Поддержаны: Catalog, ExchangePlan, ChartOfCharacteristicTypes, ChartOfAccounts, ChartOfCalculationTypes, Document, @@ -92,8 +92,8 @@ foreach ($c in $rootEl.ChildNodes) { if ($c.NodeType -eq 'Element') { $objNode = if (-not $objNode) { [Console]::Error.WriteLine("meta-decompile: пустой MetaDataObject"); exit 3 } $objType = $objNode.LocalName -if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister', 'AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'BusinessProcess', 'Task', 'Enum', 'Report', 'DataProcessor', 'Constant', 'DefinedType', 'FunctionalOption', 'DocumentJournal', 'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage', 'CommonModule', 'EventSubscription', 'ScheduledJob')) { - [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (…, CommonModule, EventSubscription, ScheduledJob)"); exit 3 +if ($objType -notin @('Catalog', 'ExchangePlan', 'ChartOfCharacteristicTypes', 'ChartOfAccounts', 'ChartOfCalculationTypes', 'Document', 'InformationRegister', 'AccumulationRegister', 'AccountingRegister', 'CalculationRegister', 'BusinessProcess', 'Task', 'Enum', 'Report', 'DataProcessor', 'Constant', 'DefinedType', 'FunctionalOption', 'DocumentJournal', 'Sequence', 'FilterCriterion', 'DocumentNumerator', 'SettingsStorage', 'CommonModule', 'EventSubscription', 'ScheduledJob', 'CommonForm')) { + [Console]::Error.WriteLine("meta-decompile: тип '$objType' пока не поддержан (…, CommonModule, EventSubscription, ScheduledJob, CommonForm)"); exit 3 } $props = $objNode.SelectSingleNode('md:Properties', $nsm) @@ -437,7 +437,7 @@ if ($objType -ne 'Constant') { Add-BoolProp 'quickChoice' 'QuickChoice' $(if ($o Add-EnumProp 'choiceMode' 'ChoiceMode' 'BothWays' Add-EnumProp 'dataLockControlMode' 'DataLockControlMode' $dataLockDef Add-EnumProp 'fullTextSearch' 'FullTextSearch' 'Use' -Add-BoolProp 'useStandardCommands' 'UseStandardCommands' $(if ($objType -eq 'Enum') { $false } else { $true }) # Enum дефолт false (корпус); прочие (вкл. Report/DataProcessor) — true: авторски-безопасно (доступность через интерфейс), false фиксируем явно +Add-BoolProp 'useStandardCommands' 'UseStandardCommands' $(if ($objType -in @('Enum', 'CommonForm')) { $false } else { $true }) # Enum/CommonForm дефолт false (корпус); прочие (вкл. Report/DataProcessor) — true Add-EnumProp 'createOnInput' 'CreateOnInput' $createInpDef Add-EnumProp 'editType' 'EditType' 'InDialog' Add-BoolProp 'includeHelpInContents' 'IncludeHelpInContents' $false @@ -678,6 +678,19 @@ if ($objType -eq 'EventSubscription') { Add-EnumProp 'event' 'Event' 'BeforeWrite' $h = P 'Handler'; if ($h) { $dsl['handler'] = $h } } +# CommonForm — общая форма (метаданные; содержимое формы Ext/Form.xml вне роундтрипа, территория form-compile). +if ($objType -eq 'CommonForm') { + Add-EnumProp 'formType' 'FormType' 'Managed' + # UsePurposes — дефолт [PlatformApplication, MobilePlatformApplication]; захват при отличии. + $upNode = $props.SelectSingleNode('md:UsePurposes', $nsm) + if ($upNode) { + $ups = @($upNode.SelectNodes('v8:Value', $nsm) | ForEach-Object { $_.InnerText }) + $def2 = @('PlatformApplication', 'MobilePlatformApplication') + $same = ($ups.Count -eq $def2.Count); if ($same) { for ($k=0; $k -lt $ups.Count; $k++) { if ($ups[$k] -ne $def2[$k]) { $same=$false; break } } } + if (-not $same -and $ups.Count -gt 0) { $dsl['usePurposes'] = [System.Collections.ArrayList]@($ups) } + } + $ep = Get-MLValue ($props.SelectSingleNode('md:ExtendedPresentation', $nsm)); if ($null -ne $ep) { $dsl['extendedPresentation'] = $ep } +} # ScheduledJob — регламентное задание: метод, ключ, флаги, рестарт. if ($objType -eq 'ScheduledJob') { $mn = P 'MethodName'; if ($mn) { $dsl['methodName'] = $mn } diff --git a/docs/meta-dsl-spec.md b/docs/meta-dsl-spec.md index 7fdd4446..e740f525 100644 --- a/docs/meta-dsl-spec.md +++ b/docs/meta-dsl-spec.md @@ -1243,6 +1243,28 @@ ChildObjects и модулей. | `auxiliarySaveForm` / `auxiliaryLoadForm` | `""` | Auxiliary*Form (verbatim) | | `comment` | пусто | Comment | +### 7.15e CommonForm (Общая форма) + +Общая форма — самостоятельная управляемая форма (не привязана к объекту). meta-compile создаёт **метаданные + +структуру файлов + регистрацию**, аналогично тому, как `/form-add` делает для форм объектов; **содержимое формы +(`Ext/Form.xml`) наполняет `/form-compile` или `/form-edit`** — оно НЕ роундтрипится (территория form-навыков). + +| Поле JSON | Умолчание | XML элемент | +|-----------|----------|-------------| +| `comment` | пусто | Comment | +| `formType` | `Managed` | FormType | +| `includeHelpInContents` | `false` | IncludeHelpInContents | +| `usePurposes` | `[PlatformApplication, MobilePlatformApplication]` | UsePurposes (массив ApplicationUsePurpose) | +| `useStandardCommands` | `false` | UseStandardCommands | +| `extendedPresentation` / `explanation` | пусто | презентации (ML) | + +Создаёт: `CommonForms/<Имя>.xml` (метаданные) + `CommonForms/<Имя>/Ext/Form.xml` (пустая управляемая форма-заготовка) + +`CommonForms/<Имя>/Ext/Form/Module.bsl` + регистрацию `` в Configuration.xml. + +```json +{ "type": "CommonForm", "name": "НастройкиОбмена", "usePurposes": ["PlatformApplication"] } +``` + ### 7.16 ChartOfAccounts Полное описание типа (все поля, стандартные реквизиты, грамматика предопределённых счетов) — см. **§7.2c**. diff --git a/tests/skills/cases/meta-compile/common-form.json b/tests/skills/cases/meta-compile/common-form.json new file mode 100644 index 00000000..f547b764 --- /dev/null +++ b/tests/skills/cases/meta-compile/common-form.json @@ -0,0 +1,18 @@ +{ + "name": "Общая форма (метаданные + заготовка)", + "input": { + "type": "CommonForm", + "name": "НастройкиОбмена", + "comment": "(Демо)", + "usePurposes": ["PlatformApplication"] + }, + "validatePath": "CommonForms/НастройкиОбмена", + "skipValidation": true, + "expect": { + "files": [ + "CommonForms/НастройкиОбмена.xml", + "CommonForms/НастройкиОбмена/Ext/Form.xml", + "CommonForms/НастройкиОбмена/Ext/Form/Module.bsl" + ] + } +} diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена.xml b/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена.xml new file mode 100644 index 00000000..de052b68 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена.xml @@ -0,0 +1,23 @@ + + + + + НастройкиОбмена + + + ru + Настройки обмена + + + (Демо) + Managed + false + + PlatformApplication + + false + + + + + diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена/Ext/Form.xml b/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена/Ext/Form.xml new file mode 100644 index 00000000..891b9b66 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена/Ext/Form.xml @@ -0,0 +1,7 @@ + +
+ + true + + + diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена/Ext/Form/Module.bsl b/tests/skills/cases/meta-compile/snapshots/common-form/CommonForms/НастройкиОбмена/Ext/Form/Module.bsl new file mode 100644 index 00000000..e69de29b diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/Configuration.xml b/tests/skills/cases/meta-compile/snapshots/common-form/Configuration.xml new file mode 100644 index 00000000..851ecdbc --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/common-form/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + Biometrics + true + + + Location + false + + + BackgroundLocation + false + + + BluetoothPrinters + false + + + WiFiPrinters + false + + + Contacts + false + + + Calendars + false + + + PushNotifications + false + + + LocalNotifications + false + + + InAppPurchases + false + + + PersonalComputerFileExchange + false + + + Ads + false + + + NumberDialing + false + + + CallProcessing + false + + + CallLog + false + + + AutoSendSMS + false + + + ReceiveSMS + false + + + SMSLog + false + + + Camera + false + + + Microphone + false + + + MusicLibrary + false + + + PictureAndVideoLibraries + false + + + AudioPlaybackAndVibration + false + + + BackgroundAudioPlaybackAndVibration + false + + + InstallPackages + false + + + OSBackup + true + + + ApplicationUsageStatistics + false + + + BarcodeScanning + false + + + BackgroundAudioRecording + false + + + AllFilesAccess + false + + + Videoconferences + false + + + NFC + false + + + DocumentScanning + false + + + SpeechToText + false + + + Geofences + false + + + IncomingShareRequests + false + + + AllIncomingShareRequestsTypesProcessing + false + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + НастройкиОбмена + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/Ext/ClientApplicationInterface.xml b/tests/skills/cases/meta-compile/snapshots/common-form/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/common-form/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/meta-compile/snapshots/common-form/Languages/Русский.xml b/tests/skills/cases/meta-compile/snapshots/common-form/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/meta-compile/snapshots/common-form/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file