|
|
|
|
@@ -8,13 +8,13 @@ import lockResetIcon from '../assets/icons/lock_reset.svg'
|
|
|
|
|
import deleteIcon from '../assets/icons/delete.svg'
|
|
|
|
|
import SvgIcon from '../components/SvgIcon.vue'
|
|
|
|
|
import AdminFeaturedSection from '../components/admin/AdminFeaturedSection.vue'
|
|
|
|
|
import AdminGamesSection from '../components/admin/AdminGamesSection.vue'
|
|
|
|
|
import AdminTemplatesSection from '../components/admin/AdminTemplatesSection.vue'
|
|
|
|
|
import AdminItemsSection from '../components/admin/AdminItemsSection.vue'
|
|
|
|
|
import AdminTierlistsSection from '../components/admin/AdminTierlistsSection.vue'
|
|
|
|
|
import AdminUsersSection from '../components/admin/AdminUsersSection.vue'
|
|
|
|
|
import { useAdminCustomItems } from '../composables/useAdminCustomItems'
|
|
|
|
|
import { useAdminFeaturedGames } from '../composables/useAdminFeaturedGames'
|
|
|
|
|
import { useAdminGameManager } from '../composables/useAdminGameManager'
|
|
|
|
|
import { useAdminFeaturedTemplates } from '../composables/useAdminFeaturedTemplates'
|
|
|
|
|
import { useAdminTemplateManager } from '../composables/useAdminTemplateManager'
|
|
|
|
|
import { useAdminTemplateRequests } from '../composables/useAdminTemplateRequests'
|
|
|
|
|
import { useAdminUsers } from '../composables/useAdminUsers'
|
|
|
|
|
import { useAuthStore } from '../stores/auth'
|
|
|
|
|
@@ -50,7 +50,7 @@ const customItemModalTargetTemplateId = ref('')
|
|
|
|
|
|
|
|
|
|
const adminTierLists = ref([])
|
|
|
|
|
const adminTierListQuery = ref('')
|
|
|
|
|
const adminTierListGameId = ref('')
|
|
|
|
|
const adminTierListTopicId = ref('')
|
|
|
|
|
const adminTierListPage = ref(1)
|
|
|
|
|
const adminTierListLimit = ref(50)
|
|
|
|
|
const adminTierListTotal = ref(0)
|
|
|
|
|
@@ -143,7 +143,7 @@ function setThumbFileInputRef(el) {
|
|
|
|
|
thumbFileInput.value = el
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function scheduleGameItemSortableSync() {
|
|
|
|
|
function scheduleTemplateItemSortableSync() {
|
|
|
|
|
if (templateItemSortableSyncTimer) {
|
|
|
|
|
clearTimeout(templateItemSortableSyncTimer)
|
|
|
|
|
templateItemSortableSyncTimer = null
|
|
|
|
|
@@ -156,10 +156,10 @@ function scheduleGameItemSortableSync() {
|
|
|
|
|
}, 0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setGameItemListRef(el) {
|
|
|
|
|
function setTemplateItemListRef(el) {
|
|
|
|
|
templateItemListEl.value = el
|
|
|
|
|
if (!el) return
|
|
|
|
|
scheduleGameItemSortableSync()
|
|
|
|
|
scheduleTemplateItemSortableSync()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeAdminSrc(src) {
|
|
|
|
|
@@ -437,7 +437,7 @@ watch(
|
|
|
|
|
const nextMode = route.query.mode === 'all' ? 'all' : 'requests'
|
|
|
|
|
if (tierlistsMode.value !== nextMode) tierlistsMode.value = nextMode
|
|
|
|
|
const nextTierListTopicId = typeof route.query.topicId === 'string' ? route.query.topicId : ''
|
|
|
|
|
if (adminTierListGameId.value !== nextTierListTopicId) adminTierListGameId.value = nextTierListTopicId
|
|
|
|
|
if (adminTierListTopicId.value !== nextTierListTopicId) adminTierListTopicId.value = nextTierListTopicId
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
@@ -465,13 +465,13 @@ watch(
|
|
|
|
|
if (route.name !== 'adminTierlists') return
|
|
|
|
|
syncAdminRouteQuery({
|
|
|
|
|
mode: mode === 'all' ? 'all' : undefined,
|
|
|
|
|
topicId: mode === 'all' && adminTierListGameId.value ? adminTierListGameId.value : undefined,
|
|
|
|
|
topicId: mode === 'all' && adminTierListTopicId.value ? adminTierListTopicId.value : undefined,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => adminTierListGameId.value,
|
|
|
|
|
() => adminTierListTopicId.value,
|
|
|
|
|
(topicId) => {
|
|
|
|
|
if (route.name !== 'adminTierlists' || tierlistsMode.value !== 'all') return
|
|
|
|
|
syncAdminRouteQuery({ topicId: topicId || undefined })
|
|
|
|
|
@@ -527,7 +527,7 @@ watch(
|
|
|
|
|
() => [selectedTemplate.value?.template?.id || '', selectedTemplate.value?.items?.length || 0, !!templateItemListEl.value],
|
|
|
|
|
([templateId, itemCount, hasListEl]) => {
|
|
|
|
|
if (!templateId || !itemCount || !hasListEl) return
|
|
|
|
|
scheduleGameItemSortableSync()
|
|
|
|
|
scheduleTemplateItemSortableSync()
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@@ -715,10 +715,10 @@ async function cleanupMissingImageReferences() {
|
|
|
|
|
success.value =
|
|
|
|
|
`누락 참조를 정리했어요. ` +
|
|
|
|
|
`아바타 ${result.clearedAvatars || 0}건, ` +
|
|
|
|
|
`템플릿 썸네일 ${result.clearedGameThumbnails || 0}건, ` +
|
|
|
|
|
`템플릿 썸네일 ${result.clearedTopicThumbnails || 0}건, ` +
|
|
|
|
|
`티어표 썸네일 ${result.clearedTierListThumbnails || 0}건, ` +
|
|
|
|
|
`요청 썸네일 ${result.clearedTemplateRequestThumbnails || 0}건, ` +
|
|
|
|
|
`템플릿 아이템 ${result.deletedGameItems || 0}건, ` +
|
|
|
|
|
`템플릿 아이템 ${result.deletedTopicItems || 0}건, ` +
|
|
|
|
|
`커스텀 아이템 ${result.deletedCustomItems || 0}건`
|
|
|
|
|
} catch (e) {
|
|
|
|
|
error.value = '누락 이미지 참조 정리에 실패했어요.'
|
|
|
|
|
@@ -822,7 +822,7 @@ async function refreshAdminTierLists() {
|
|
|
|
|
try {
|
|
|
|
|
const data = await api.listAdminTierLists({
|
|
|
|
|
q: adminTierListQuery.value,
|
|
|
|
|
topicId: adminTierListGameId.value,
|
|
|
|
|
topicId: adminTierListTopicId.value,
|
|
|
|
|
page: adminTierListPage.value,
|
|
|
|
|
limit: adminTierListLimit.value,
|
|
|
|
|
})
|
|
|
|
|
@@ -839,7 +839,7 @@ async function refreshAdminTierLists() {
|
|
|
|
|
async function refreshAdminTierListStats() {
|
|
|
|
|
if (!auth.user?.isAdmin) return
|
|
|
|
|
try {
|
|
|
|
|
const data = await api.getAdminTierListStats({ q: adminTierListQuery.value, topicId: adminTierListGameId.value })
|
|
|
|
|
const data = await api.getAdminTierListStats({ q: adminTierListQuery.value, topicId: adminTierListTopicId.value })
|
|
|
|
|
adminTierListStats.value = {
|
|
|
|
|
total: data.total || 0,
|
|
|
|
|
publicCount: data.publicCount || 0,
|
|
|
|
|
@@ -919,7 +919,7 @@ const {
|
|
|
|
|
removeFeaturedTemplate,
|
|
|
|
|
moveFeaturedTemplate,
|
|
|
|
|
saveFeaturedOrder,
|
|
|
|
|
} = useAdminFeaturedGames({
|
|
|
|
|
} = useAdminFeaturedTemplates({
|
|
|
|
|
api,
|
|
|
|
|
featuredListEl,
|
|
|
|
|
featuredSortable,
|
|
|
|
|
@@ -943,7 +943,7 @@ const {
|
|
|
|
|
clearItemFiles,
|
|
|
|
|
uploadItem,
|
|
|
|
|
saveTemplateItemOrder,
|
|
|
|
|
} = useAdminGameManager({
|
|
|
|
|
} = useAdminTemplateManager({
|
|
|
|
|
api,
|
|
|
|
|
toApiUrl,
|
|
|
|
|
selectedTemplateId,
|
|
|
|
|
@@ -1306,8 +1306,8 @@ function submitAdminTierListSearch() {
|
|
|
|
|
refreshAdminTierLists()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setAdminTierListGameId(topicId) {
|
|
|
|
|
adminTierListGameId.value = topicId || ''
|
|
|
|
|
function setAdminTierListTopicId(topicId) {
|
|
|
|
|
adminTierListTopicId.value = topicId || ''
|
|
|
|
|
adminTierListPage.value = 1
|
|
|
|
|
refreshAdminTierLists()
|
|
|
|
|
}
|
|
|
|
|
@@ -1327,7 +1327,7 @@ function closeTemplatePickerModal() {
|
|
|
|
|
async function chooseTemplateFromPicker(templateId) {
|
|
|
|
|
if (!templateId) return
|
|
|
|
|
if (templatePickerMode.value === 'tierlists-filter') {
|
|
|
|
|
setAdminTierListGameId(templateId)
|
|
|
|
|
setAdminTierListTopicId(templateId)
|
|
|
|
|
closeTemplatePickerModal()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
@@ -1700,7 +1700,7 @@ function userAvatarFallback(user) {
|
|
|
|
|
:add-featured-template="addFeaturedTemplate"
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<AdminGamesSection
|
|
|
|
|
<AdminTemplatesSection
|
|
|
|
|
v-else-if="activeTab === 'template-admin'"
|
|
|
|
|
:active-template-request="activeTemplateRequest"
|
|
|
|
|
:template-request-source-url="templateRequestSourceUrl"
|
|
|
|
|
@@ -1739,7 +1739,7 @@ function userAvatarFallback(user) {
|
|
|
|
|
:remove-upload-draft="removeUploadDraft"
|
|
|
|
|
:has-template-item-order-changes="hasTemplateItemOrderChanges"
|
|
|
|
|
:save-template-item-order="saveTemplateItemOrder"
|
|
|
|
|
:template-item-list-ref="setGameItemListRef"
|
|
|
|
|
:template-item-list-ref="setTemplateItemListRef"
|
|
|
|
|
:save-template-item-label="saveTemplateItemLabel"
|
|
|
|
|
:remove-template-item="removeTemplateItem"
|
|
|
|
|
:selected-template-id="selectedTemplateId"
|
|
|
|
|
@@ -2046,34 +2046,34 @@ function userAvatarFallback(user) {
|
|
|
|
|
<option value="oldest">오래된순</option>
|
|
|
|
|
</select>
|
|
|
|
|
<button
|
|
|
|
|
v-if="templatePickerMode === 'tierlists-filter' && adminTierListGameId"
|
|
|
|
|
v-if="templatePickerMode === 'tierlists-filter' && adminTierListTopicId"
|
|
|
|
|
class="btn btn--ghost"
|
|
|
|
|
type="button"
|
|
|
|
|
@click="setAdminTierListGameId(''); closeTemplatePickerModal()"
|
|
|
|
|
@click="setAdminTierListTopicId(''); closeTemplatePickerModal()"
|
|
|
|
|
>
|
|
|
|
|
모든 주제 보기
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="gamePickerModalList">
|
|
|
|
|
<div class="templatePickerModalList">
|
|
|
|
|
<button
|
|
|
|
|
v-for="template in filteredTemplatePickerTemplates"
|
|
|
|
|
:key="template.id"
|
|
|
|
|
class="adminGamePicker__item"
|
|
|
|
|
class="adminTemplatePicker__item"
|
|
|
|
|
:class="{
|
|
|
|
|
'adminGamePicker__item--active': templatePickerMode === 'tierlists-filter'
|
|
|
|
|
? adminTierListGameId === template.id
|
|
|
|
|
'adminTemplatePicker__item--active': templatePickerMode === 'tierlists-filter'
|
|
|
|
|
? adminTierListTopicId === template.id
|
|
|
|
|
: templatePickerMode === 'custom-item-target'
|
|
|
|
|
? customItemModalTargetTemplateId === template.id
|
|
|
|
|
: selectedTemplateId === template.id,
|
|
|
|
|
'adminGamePicker__item--disabled': templatePickerMode === 'custom-item-target' && linkedCustomItemTemplateIds.has(template.id),
|
|
|
|
|
'adminTemplatePicker__item--disabled': templatePickerMode === 'custom-item-target' && linkedCustomItemTemplateIds.has(template.id),
|
|
|
|
|
}"
|
|
|
|
|
type="button"
|
|
|
|
|
:disabled="templatePickerMode === 'custom-item-target' && linkedCustomItemTemplateIds.has(template.id)"
|
|
|
|
|
@click="chooseTemplateFromPicker(template.id)"
|
|
|
|
|
>
|
|
|
|
|
<span class="adminGamePicker__name">{{ template.name }}</span>
|
|
|
|
|
<span class="adminGamePicker__meta">{{ template.id }}</span>
|
|
|
|
|
<span v-if="templatePickerMode === 'custom-item-target' && linkedCustomItemTemplateIds.has(template.id)" class="adminGamePicker__state">이미 추가됨</span>
|
|
|
|
|
<span class="adminTemplatePicker__name">{{ template.name }}</span>
|
|
|
|
|
<span class="adminTemplatePicker__meta">{{ template.id }}</span>
|
|
|
|
|
<span v-if="templatePickerMode === 'custom-item-target' && linkedCustomItemTemplateIds.has(template.id)" class="adminTemplatePicker__state">이미 추가됨</span>
|
|
|
|
|
</button>
|
|
|
|
|
<div v-if="!filteredTemplatePickerTemplates.length" class="hint hint--tight">검색 결과가 없어요.</div>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -2305,11 +2305,11 @@ function userAvatarFallback(user) {
|
|
|
|
|
<button class="btn btn--ghost" @click="submitAdminTierListSearch">검색</button>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn--ghost" @click="openTemplatePickerModal('tierlists-filter')">주제 선택</button>
|
|
|
|
|
<div v-if="adminTierListGameId" class="adminSelectionCard">
|
|
|
|
|
<div v-if="adminTierListTopicId" class="adminSelectionCard">
|
|
|
|
|
<div class="adminSelectionCard__label">필터된 주제</div>
|
|
|
|
|
<div class="adminSelectionCard__title">{{ templates.find((template) => template.id === adminTierListGameId)?.name || adminTierListGameId }}</div>
|
|
|
|
|
<div class="adminSelectionCard__meta">{{ adminTierListGameId }}</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small" @click="setAdminTierListGameId('')">필터 해제</button>
|
|
|
|
|
<div class="adminSelectionCard__title">{{ templates.find((template) => template.id === adminTierListTopicId)?.name || adminTierListTopicId }}</div>
|
|
|
|
|
<div class="adminSelectionCard__meta">{{ adminTierListTopicId }}</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small" @click="setAdminTierListTopicId('')">필터 해제</button>
|
|
|
|
|
</div>
|
|
|
|
|
<select :value="adminTierListLimit" class="select" @change="changeAdminTierListLimit(Number($event.target.value))">
|
|
|
|
|
<option :value="50">50개씩 보기</option>
|
|
|
|
|
@@ -2583,14 +2583,14 @@ function userAvatarFallback(user) {
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
color: var(--theme-text);
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker {
|
|
|
|
|
.adminUiScope .adminTemplatePicker {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
max-height: 640px;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
padding-right: 4px;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__item {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__item {
|
|
|
|
|
display: grid;
|
|
|
|
|
/* gap: 2px; */
|
|
|
|
|
padding: 11px 12px;
|
|
|
|
|
@@ -2601,32 +2601,32 @@ function userAvatarFallback(user) {
|
|
|
|
|
color: var(--theme-text);
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__item--active {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__item--active {
|
|
|
|
|
border-color: rgba(77, 127, 233, 0.58);
|
|
|
|
|
background: rgba(77, 127, 233, 0.12);
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__item--disabled {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__item--disabled {
|
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
opacity: 0.58;
|
|
|
|
|
border-style: dashed;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__name {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__name {
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__meta {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__meta {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: var(--theme-text-soft);
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .adminGamePicker__state {
|
|
|
|
|
.adminUiScope .adminTemplatePicker__state {
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
color: var(--theme-text-faint);
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gamePickerModalList {
|
|
|
|
|
.adminUiScope .templatePickerModalList {
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
@@ -2873,16 +2873,16 @@ function userAvatarFallback(user) {
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
gap: 16px;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameManagerGrid {
|
|
|
|
|
.adminUiScope .templateManagerGrid {
|
|
|
|
|
margin-top: 14px;
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
|
|
|
gap: 16px;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameManagerGrid--single {
|
|
|
|
|
.adminUiScope .templateManagerGrid--single {
|
|
|
|
|
grid-template-columns: minmax(0, 1fr);
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameManagerCard__body {
|
|
|
|
|
.adminUiScope .templateManagerCard__body {
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
@@ -3048,37 +3048,37 @@ function userAvatarFallback(user) {
|
|
|
|
|
display: flex;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .selectedGame__name {
|
|
|
|
|
.adminUiScope .selectedTemplate__name {
|
|
|
|
|
margin-top: 8px;
|
|
|
|
|
font-size: 22px;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .selectedGame__id {
|
|
|
|
|
.adminUiScope .selectedTemplate__id {
|
|
|
|
|
margin-top: 6px;
|
|
|
|
|
opacity: 0.72;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameSettingsCard {
|
|
|
|
|
.adminUiScope .templateSettingsCard {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
|
|
|
|
|
gap: 18px;
|
|
|
|
|
align-items: center;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameSettingsCard__media {
|
|
|
|
|
.adminUiScope .templateSettingsCard__media {
|
|
|
|
|
min-width: 0;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameSettingsCard__body {
|
|
|
|
|
.adminUiScope .templateSettingsCard__body {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 14px;
|
|
|
|
|
align-content: center;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameSettingsCard__meta {
|
|
|
|
|
.adminUiScope .templateSettingsCard__meta {
|
|
|
|
|
color: var(--theme-text-soft);
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
line-height: 1.5;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .gameSettingsCard__actions {
|
|
|
|
|
.adminUiScope .templateSettingsCard__actions {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
@@ -3101,11 +3101,11 @@ function userAvatarFallback(user) {
|
|
|
|
|
.adminUiScope .selectedThumb--sidebar {
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .selectedGameSidebar__name {
|
|
|
|
|
.adminUiScope .selectedTemplateSidebar__name {
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
font-weight: 900;
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .selectedGameSidebar__id {
|
|
|
|
|
.adminUiScope .selectedTemplateSidebar__id {
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
opacity: 0.68;
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
@@ -4479,8 +4479,8 @@ function userAvatarFallback(user) {
|
|
|
|
|
}
|
|
|
|
|
.adminUiScope .featuredOrderPanel,
|
|
|
|
|
.adminUiScope .section--topGrid,
|
|
|
|
|
.adminUiScope .gameManagerGrid,
|
|
|
|
|
.adminUiScope .gameSettingsCard,
|
|
|
|
|
.adminUiScope .templateManagerGrid,
|
|
|
|
|
.adminUiScope .templateSettingsCard,
|
|
|
|
|
.adminUiScope .toolbar,
|
|
|
|
|
.adminUiScope .itemComposer,
|
|
|
|
|
.adminUiScope .tierAdminCard,
|
|
|
|
|
|