refactor(backend): Array.prototype.filter
での非null確認ではisNotNull
関数を使うように (#13442)
* `Array.prototype.filter`での非null確認では`isNotNull`関数を使うように * `{}` -> `NonNullable<unknown>`
This commit is contained in:
parent
080a3c20bd
commit
64953fadc9
|
@ -59,6 +59,7 @@ import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
import { UserBlockingService } from '@/core/UserBlockingService.js';
|
||||||
import { isReply } from '@/misc/is-reply.js';
|
import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
@ -816,7 +817,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
const mentions = extractMentions(tokens);
|
const mentions = extractMentions(tokens);
|
||||||
let mentionedUsers = (await Promise.all(mentions.map(m =>
|
let mentionedUsers = (await Promise.all(mentions.map(m =>
|
||||||
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
|
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
|
||||||
))).filter(x => x != null) as MiUser[];
|
))).filter(isNotNull);
|
||||||
|
|
||||||
// Drop duplicate users
|
// Drop duplicate users
|
||||||
mentionedUsers = mentionedUsers.filter((u, i, self) =>
|
mentionedUsers = mentionedUsers.filter((u, i, self) =>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit';
|
||||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||||
import { concat, unique } from '@/misc/prelude/array.js';
|
import { concat, unique } from '@/misc/prelude/array.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApIds } from './type.js';
|
import { getApIds } from './type.js';
|
||||||
import { ApPersonService } from './models/ApPersonService.js';
|
import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import type { ApObject } from './type.js';
|
import type { ApObject } from './type.js';
|
||||||
|
@ -40,7 +41,7 @@ export class ApAudienceService {
|
||||||
const limit = promiseLimit<MiUser | null>(2);
|
const limit = promiseLimit<MiUser | null>(2);
|
||||||
const mentionedUsers = (await Promise.all(
|
const mentionedUsers = (await Promise.all(
|
||||||
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
|
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
|
||||||
)).filter((x): x is MiUser => x != null);
|
)).filter(isNotNull);
|
||||||
|
|
||||||
if (toGroups.public.length > 0) {
|
if (toGroups.public.length > 0) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
|
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { MiRemoteUser } from '@/models/User.js';
|
import type { MiRemoteUser } from '@/models/User.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApNoteService } from './models/ApNoteService.js';
|
import { ApNoteService } from './models/ApNoteService.js';
|
||||||
import { ApLoggerService } from './ApLoggerService.js';
|
import { ApLoggerService } from './ApLoggerService.js';
|
||||||
|
@ -521,7 +522,7 @@ export class ApInboxService {
|
||||||
const userIds = uris
|
const userIds = uris
|
||||||
.filter(uri => uri.startsWith(this.config.url + '/users/'))
|
.filter(uri => uri.startsWith(this.config.url + '/users/'))
|
||||||
.map(uri => uri.split('/').at(-1))
|
.map(uri => uri.split('/').at(-1))
|
||||||
.filter((userId): userId is string => userId !== undefined);
|
.filter(isNotNull);
|
||||||
const users = await this.usersRepository.findBy({
|
const users = await this.usersRepository.findBy({
|
||||||
id: In(userIds),
|
id: In(userIds),
|
||||||
});
|
});
|
||||||
|
|
|
@ -315,7 +315,7 @@ export class ApRendererService {
|
||||||
const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
|
const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
||||||
return ids.map(id => items.find(item => item.id === id)).filter((item): item is MiDriveFile => item != null);
|
return ids.map(id => items.find(item => item.id === id)).filter(isNotNull);
|
||||||
};
|
};
|
||||||
|
|
||||||
let inReplyTo;
|
let inReplyTo;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit';
|
||||||
import type { MiUser } from '@/models/_.js';
|
import type { MiUser } from '@/models/_.js';
|
||||||
import { toArray, unique } from '@/misc/prelude/array.js';
|
import { toArray, unique } from '@/misc/prelude/array.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isMention } from '../type.js';
|
import { isMention } from '../type.js';
|
||||||
import { Resolver } from '../ApResolverService.js';
|
import { Resolver } from '../ApResolverService.js';
|
||||||
import { ApPersonService } from './ApPersonService.js';
|
import { ApPersonService } from './ApPersonService.js';
|
||||||
|
@ -27,7 +28,7 @@ export class ApMentionService {
|
||||||
const limit = promiseLimit<MiUser | null>(2);
|
const limit = promiseLimit<MiUser | null>(2);
|
||||||
const mentionedUsers = (await Promise.all(
|
const mentionedUsers = (await Promise.all(
|
||||||
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
|
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
|
||||||
)).filter((x): x is MiUser => x != null);
|
)).filter(isNotNull);
|
||||||
|
|
||||||
return mentionedUsers;
|
return mentionedUsers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import { ApQuestionService } from './ApQuestionService.js';
|
||||||
import { ApImageService } from './ApImageService.js';
|
import { ApImageService } from './ApImageService.js';
|
||||||
import type { Resolver } from '../ApResolverService.js';
|
import type { Resolver } from '../ApResolverService.js';
|
||||||
import type { IObject, IPost } from '../type.js';
|
import type { IObject, IPost } from '../type.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApNoteService {
|
export class ApNoteService {
|
||||||
|
@ -221,7 +222,7 @@ export class ApNoteService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const uris = unique([note._misskey_quote, note.quoteUrl].filter((x): x is string => typeof x === 'string'));
|
const uris = unique([note._misskey_quote, note.quoteUrl].filter(isNotNull));
|
||||||
const results = await Promise.all(uris.map(tryResolveNote));
|
const results = await Promise.all(uris.map(tryResolveNote));
|
||||||
|
|
||||||
quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
|
quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
import { checkHttps } from '@/misc/check-https.js';
|
import { checkHttps } from '@/misc/check-https.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
|
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
|
||||||
import { extractApHashtags } from './tag.js';
|
import { extractApHashtags } from './tag.js';
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
import type { OnModuleInit } from '@nestjs/common';
|
||||||
|
@ -636,7 +637,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
|
|
||||||
// とりあえずidを別の時間で生成して順番を維持
|
// とりあえずidを別の時間で生成して順番を維持
|
||||||
let td = 0;
|
let td = 0;
|
||||||
for (const note of featuredNotes.filter((note): note is MiNote => note != null)) {
|
for (const note of featuredNotes.filter(isNotNull)) {
|
||||||
td -= 1000;
|
td -= 1000;
|
||||||
transactionalEntityManager.insert(MiUserNotePining, {
|
transactionalEntityManager.insert(MiUserNotePining, {
|
||||||
id: this.idService.gen(Date.now() + td),
|
id: this.idService.gen(Date.now() + td),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { Config } from '@/config.js';
|
||||||
import type { IPoll } from '@/models/Poll.js';
|
import type { IPoll } from '@/models/Poll.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isQuestion } from '../type.js';
|
import { isQuestion } from '../type.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApResolverService } from '../ApResolverService.js';
|
import { ApResolverService } from '../ApResolverService.js';
|
||||||
|
@ -51,7 +52,7 @@ export class ApQuestionService {
|
||||||
|
|
||||||
const choices = question[multiple ? 'anyOf' : 'oneOf']
|
const choices = question[multiple ? 'anyOf' : 'oneOf']
|
||||||
?.map((x) => x.name)
|
?.map((x) => x.name)
|
||||||
.filter((x): x is string => typeof x === 'string')
|
.filter(isNotNull)
|
||||||
?? [];
|
?? [];
|
||||||
|
|
||||||
const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0);
|
const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { toArray } from '@/misc/prelude/array.js';
|
import { toArray } from '@/misc/prelude/array.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isHashtag } from '../type.js';
|
import { isHashtag } from '../type.js';
|
||||||
import type { IObject, IApHashtag } from '../type.js';
|
import type { IObject, IApHashtag } from '../type.js';
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined):
|
||||||
return hashtags.map(tag => {
|
return hashtags.map(tag => {
|
||||||
const m = tag.name.match(/^#(.+)/);
|
const m = tag.name.match(/^#(.+)/);
|
||||||
return m ? m[1] : null;
|
return m ? m[1] : null;
|
||||||
}).filter((x): x is string => x != null);
|
}).filter(isNotNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] {
|
export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] {
|
||||||
|
|
|
@ -259,7 +259,7 @@ export class DriveFileEntityService {
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
): Promise<Packed<'DriveFile'>[]> {
|
): Promise<Packed<'DriveFile'>[]> {
|
||||||
const items = await Promise.all(files.map(f => this.packNullable(f, options)));
|
const items = await Promise.all(files.map(f => this.packNullable(f, options)));
|
||||||
return items.filter((x): x is Packed<'DriveFile'> => x != null);
|
return items.filter(isNotNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -14,6 +14,7 @@ import type { MiPage } from '@/models/Page.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ export class PageEntityService {
|
||||||
script: page.script,
|
script: page.script,
|
||||||
eyeCatchingImageId: page.eyeCatchingImageId,
|
eyeCatchingImageId: page.eyeCatchingImageId,
|
||||||
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
|
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
|
||||||
attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is MiDriveFile => x != null)),
|
attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)),
|
||||||
likedCount: page.likedCount,
|
likedCount: page.likedCount,
|
||||||
isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined,
|
isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined,
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { IdService } from '@/core/IdService.js';
|
||||||
import type { AnnouncementService } from '@/core/AnnouncementService.js';
|
import type { AnnouncementService } from '@/core/AnnouncementService.js';
|
||||||
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
import type { NoteEntityService } from './NoteEntityService.js';
|
||||||
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||||
|
@ -384,7 +385,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
|
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
|
||||||
alsoKnownAs: user.alsoKnownAs
|
alsoKnownAs: user.alsoKnownAs
|
||||||
? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null)))
|
? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null)))
|
||||||
.then(xs => xs.length === 0 ? null : xs.filter(x => x != null) as string[])
|
.then(xs => xs.length === 0 ? null : xs.filter(isNotNull))
|
||||||
: null,
|
: null,
|
||||||
createdAt: this.idService.parse(user.id).date.toISOString(),
|
createdAt: this.idService.parse(user.id).date.toISOString(),
|
||||||
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// we are using {} as "any non-nullish value" as expected
|
export function isNotNull<T extends NonNullable<unknown>>(input: T | undefined | null): input is T {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
export function isNotNull<T extends {}>(input: T | undefined | null): input is T {
|
|
||||||
return input != null;
|
return input != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['gallery'],
|
tags: ['gallery'],
|
||||||
|
@ -69,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: fileId,
|
id: fileId,
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
}),
|
}),
|
||||||
))).filter((file): file is MiDriveFile => file != null);
|
))).filter(isNotNull);
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['gallery'],
|
tags: ['gallery'],
|
||||||
|
@ -67,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: fileId,
|
id: fileId,
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
}),
|
}),
|
||||||
))).filter((file): file is MiDriveFile => file != null);
|
))).filter(isNotNull);
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['users'],
|
tags: ['users'],
|
||||||
|
@ -52,7 +53,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
host: acct.host ?? IsNull(),
|
host: acct.host ?? IsNull(),
|
||||||
})));
|
})));
|
||||||
|
|
||||||
return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { schema: 'UserDetailed' });
|
return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue