Full Code of halo-dev/halo for AI

main 4af3e75a2b05 cached
2670 files
10.5 MB
2.9M tokens
10096 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (11,599K chars total). Download the full file to get everything.
Repository: halo-dev/halo
Branch: main
Commit: 4af3e75a2b05
Files: 2670
Total size: 10.5 MB

Directory structure:
gitextract_qe2hhq1p/

├── .dockerignore
├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.en.yml
│   │   ├── bug_report.zh.yml
│   │   ├── config.yml
│   │   ├── feature_request.en.yml
│   │   └── feature_request.zh.yml
│   ├── actions/
│   │   ├── docker-buildx-push/
│   │   │   └── action.yaml
│   │   └── setup-env/
│   │       └── action.yaml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── halo.yaml
│       ├── openapi-check.yaml
│       ├── packages-preview-release.yaml
│       ├── release-ui-packages.yaml
│       └── stale-issues.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY.md
├── api/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── run/
│       │           └── halo/
│       │               └── app/
│       │                   ├── content/
│       │                   │   ├── ContentWrapper.java
│       │                   │   ├── ExcerptGenerator.java
│       │                   │   ├── PatchUtils.java
│       │                   │   ├── PostContentService.java
│       │                   │   └── comment/
│       │                   │       └── CommentSubject.java
│       │                   ├── core/
│       │                   │   ├── attachment/
│       │                   │   │   ├── ThumbnailProvider.java
│       │                   │   │   └── ThumbnailSize.java
│       │                   │   ├── endpoint/
│       │                   │   │   └── WebSocketEndpoint.java
│       │                   │   ├── extension/
│       │                   │   │   ├── AnnotationSetting.java
│       │                   │   │   ├── AuthProvider.java
│       │                   │   │   ├── Counter.java
│       │                   │   │   ├── Device.java
│       │                   │   │   ├── Menu.java
│       │                   │   │   ├── MenuItem.java
│       │                   │   │   ├── Plugin.java
│       │                   │   │   ├── RememberMeToken.java
│       │                   │   │   ├── ReverseProxy.java
│       │                   │   │   ├── Role.java
│       │                   │   │   ├── RoleBinding.java
│       │                   │   │   ├── Setting.java
│       │                   │   │   ├── Theme.java
│       │                   │   │   ├── User.java
│       │                   │   │   ├── UserConnection.java
│       │                   │   │   ├── attachment/
│       │                   │   │   │   ├── Attachment.java
│       │                   │   │   │   ├── Constant.java
│       │                   │   │   │   ├── Group.java
│       │                   │   │   │   ├── Policy.java
│       │                   │   │   │   ├── PolicyTemplate.java
│       │                   │   │   │   └── endpoint/
│       │                   │   │   │       ├── AttachmentHandler.java
│       │                   │   │   │       ├── DeleteOption.java
│       │                   │   │   │       ├── SimpleFilePart.java
│       │                   │   │   │       └── UploadOption.java
│       │                   │   │   ├── content/
│       │                   │   │   │   ├── Category.java
│       │                   │   │   │   ├── Comment.java
│       │                   │   │   │   ├── Constant.java
│       │                   │   │   │   ├── Post.java
│       │                   │   │   │   ├── Reply.java
│       │                   │   │   │   ├── SinglePage.java
│       │                   │   │   │   ├── Snapshot.java
│       │                   │   │   │   └── Tag.java
│       │                   │   │   ├── endpoint/
│       │                   │   │   │   ├── CustomEndpoint.java
│       │                   │   │   │   └── SortResolver.java
│       │                   │   │   ├── notification/
│       │                   │   │   │   ├── Notification.java
│       │                   │   │   │   ├── NotificationTemplate.java
│       │                   │   │   │   ├── NotifierDescriptor.java
│       │                   │   │   │   ├── Reason.java
│       │                   │   │   │   ├── ReasonType.java
│       │                   │   │   │   └── Subscription.java
│       │                   │   │   └── service/
│       │                   │   │       └── AttachmentService.java
│       │                   │   └── user/
│       │                   │       └── service/
│       │                   │           ├── RoleService.java
│       │                   │           ├── SignUpData.java
│       │                   │           ├── UserPostCreatingHandler.java
│       │                   │           ├── UserPreCreatingHandler.java
│       │                   │           └── UserService.java
│       │                   ├── event/
│       │                   │   ├── post/
│       │                   │   │   ├── PostDeletedEvent.java
│       │                   │   │   ├── PostEvent.java
│       │                   │   │   ├── PostPublishedEvent.java
│       │                   │   │   ├── PostUnpublishedEvent.java
│       │                   │   │   ├── PostUpdatedEvent.java
│       │                   │   │   └── PostVisibleChangedEvent.java
│       │                   │   └── user/
│       │                   │       ├── UserConnectionDisconnectedEvent.java
│       │                   │       ├── UserLoginEvent.java
│       │                   │       └── UserLogoutEvent.java
│       │                   ├── extension/
│       │                   │   ├── AbstractExtension.java
│       │                   │   ├── Comparators.java
│       │                   │   ├── ConfigMap.java
│       │                   │   ├── DefaultExtensionMatcher.java
│       │                   │   ├── Extension.java
│       │                   │   ├── ExtensionClient.java
│       │                   │   ├── ExtensionMatcher.java
│       │                   │   ├── ExtensionOperator.java
│       │                   │   ├── ExtensionUtil.java
│       │                   │   ├── GVK.java
│       │                   │   ├── GroupKind.java
│       │                   │   ├── GroupVersion.java
│       │                   │   ├── GroupVersionKind.java
│       │                   │   ├── JsonExtension.java
│       │                   │   ├── ListOptions.java
│       │                   │   ├── ListResult.java
│       │                   │   ├── Metadata.java
│       │                   │   ├── MetadataOperator.java
│       │                   │   ├── MetadataUtil.java
│       │                   │   ├── PageRequest.java
│       │                   │   ├── PageRequestImpl.java
│       │                   │   ├── ReactiveExtensionClient.java
│       │                   │   ├── Ref.java
│       │                   │   ├── Scheme.java
│       │                   │   ├── SchemeManager.java
│       │                   │   ├── Secret.java
│       │                   │   ├── Unstructured.java
│       │                   │   ├── Watcher.java
│       │                   │   ├── WatcherExtensionMatchers.java
│       │                   │   ├── WatcherPredicates.java
│       │                   │   ├── controller/
│       │                   │   │   ├── Controller.java
│       │                   │   │   ├── ControllerBuilder.java
│       │                   │   │   ├── DefaultController.java
│       │                   │   │   ├── DefaultQueue.java
│       │                   │   │   ├── ExtensionWatcher.java
│       │                   │   │   ├── Reconciler.java
│       │                   │   │   ├── RequestQueue.java
│       │                   │   │   ├── RequestSynchronizer.java
│       │                   │   │   ├── RequeueException.java
│       │                   │   │   └── Synchronizer.java
│       │                   │   ├── exception/
│       │                   │   │   ├── ExtensionException.java
│       │                   │   │   ├── NotImplementedException.java
│       │                   │   │   └── SchemeNotFoundException.java
│       │                   │   ├── index/
│       │                   │   │   ├── AbstractValueIndexSpecBuilder.java
│       │                   │   │   ├── DefaultIndexAttribute.java
│       │                   │   │   ├── IndexAttribute.java
│       │                   │   │   ├── IndexAttributeFactory.java
│       │                   │   │   ├── IndexSpec.java
│       │                   │   │   ├── IndexSpecBuilder.java
│       │                   │   │   ├── IndexSpecs.java
│       │                   │   │   ├── IndexedQueryEngine.java
│       │                   │   │   ├── KeyComparator.java
│       │                   │   │   ├── MultiValueBuilder.java
│       │                   │   │   ├── MultiValueIndexSpec.java
│       │                   │   │   ├── MultiValueIndexSpecBuilder.java
│       │                   │   │   ├── SingleValueBuilder.java
│       │                   │   │   ├── SingleValueIndexSpec.java
│       │                   │   │   ├── SingleValueIndexSpecBuilder.java
│       │                   │   │   ├── UnknownKey.java
│       │                   │   │   ├── ValueIndexSpec.java
│       │                   │   │   └── query/
│       │                   │   │       ├── AllCondition.java
│       │                   │   │       ├── And.java
│       │                   │   │       ├── AndCondition.java
│       │                   │   │       ├── BetweenCondition.java
│       │                   │   │       ├── Condition.java
│       │                   │   │       ├── EmptyCondition.java
│       │                   │   │       ├── EqualCondition.java
│       │                   │   │       ├── GreaterThanCondition.java
│       │                   │   │       ├── InCondition.java
│       │                   │   │       ├── IndexCondition.java
│       │                   │   │       ├── IsNotNullCondition.java
│       │                   │   │       ├── IsNullCondition.java
│       │                   │   │       ├── LabelCondition.java
│       │                   │   │       ├── LabelEqualsCondition.java
│       │                   │   │       ├── LabelExistsCondition.java
│       │                   │   │       ├── LabelInCondition.java
│       │                   │   │       ├── LabelNotEqualsCondition.java
│       │                   │   │       ├── LabelNotExistsCondition.java
│       │                   │   │       ├── LabelNotInCondition.java
│       │                   │   │       ├── LessThanCondition.java
│       │                   │   │       ├── NoneCondition.java
│       │                   │   │       ├── NotBetweenCondition.java
│       │                   │   │       ├── NotCondition.java
│       │                   │   │       ├── NotEqualCondition.java
│       │                   │   │       ├── NotInCondition.java
│       │                   │   │       ├── OrCondition.java
│       │                   │   │       ├── Queries.java
│       │                   │   │       ├── Query.java
│       │                   │   │       ├── QueryFactory.java
│       │                   │   │       ├── StringContainsCondition.java
│       │                   │   │       ├── StringEndsWithCondition.java
│       │                   │   │       ├── StringNotContainsCondition.java
│       │                   │   │       ├── StringNotEndsWithCondition.java
│       │                   │   │       ├── StringNotStartsWithCondition.java
│       │                   │   │       └── StringStartsWithCondition.java
│       │                   │   └── router/
│       │                   │       ├── IListRequest.java
│       │                   │       ├── QueryParamBuildUtil.java
│       │                   │       ├── SortableRequest.java
│       │                   │       └── selector/
│       │                   │           ├── FieldSelector.java
│       │                   │           ├── FieldSelectorConverter.java
│       │                   │           ├── LabelSelector.java
│       │                   │           ├── LabelSelectorConverter.java
│       │                   │           ├── Operator.java
│       │                   │           ├── SelectorConverter.java
│       │                   │           ├── SelectorCriteria.java
│       │                   │           └── SelectorUtil.java
│       │                   ├── infra/
│       │                   │   ├── AnonymousUserConst.java
│       │                   │   ├── BackupRootGetter.java
│       │                   │   ├── Condition.java
│       │                   │   ├── ConditionList.java
│       │                   │   ├── ConditionStatus.java
│       │                   │   ├── ExternalLinkProcessor.java
│       │                   │   ├── ExternalUrlSupplier.java
│       │                   │   ├── FileCategoryMatcher.java
│       │                   │   ├── SystemInfo.java
│       │                   │   ├── SystemInfoGetter.java
│       │                   │   ├── SystemSetting.java
│       │                   │   ├── SystemVersionSupplier.java
│       │                   │   ├── ValidationUtils.java
│       │                   │   ├── model/
│       │                   │   │   └── License.java
│       │                   │   └── utils/
│       │                   │       ├── FileTypeDetectUtils.java
│       │                   │       ├── GenericClassUtils.java
│       │                   │       ├── JsonParseException.java
│       │                   │       ├── JsonUtils.java
│       │                   │       └── PathUtils.java
│       │                   ├── migration/
│       │                   │   ├── Backup.java
│       │                   │   └── Constant.java
│       │                   ├── notification/
│       │                   │   ├── NotificationCenter.java
│       │                   │   ├── NotificationContext.java
│       │                   │   ├── NotificationReasonEmitter.java
│       │                   │   ├── ReactiveNotifier.java
│       │                   │   ├── ReasonAttributes.java
│       │                   │   ├── ReasonPayload.java
│       │                   │   └── UserIdentity.java
│       │                   ├── plugin/
│       │                   │   ├── ApiVersion.java
│       │                   │   ├── BasePlugin.java
│       │                   │   ├── PluginConfigUpdatedEvent.java
│       │                   │   ├── PluginContext.java
│       │                   │   ├── PluginsRootGetter.java
│       │                   │   ├── ReactiveSettingFetcher.java
│       │                   │   ├── SettingFetcher.java
│       │                   │   ├── SharedEvent.java
│       │                   │   ├── event/
│       │                   │   │   └── PluginStartedEvent.java
│       │                   │   └── extensionpoint/
│       │                   │       └── ExtensionGetter.java
│       │                   ├── search/
│       │                   │   ├── HaloDocument.java
│       │                   │   ├── HaloDocumentsProvider.java
│       │                   │   ├── SearchEngine.java
│       │                   │   ├── SearchOption.java
│       │                   │   ├── SearchResult.java
│       │                   │   ├── SearchService.java
│       │                   │   └── event/
│       │                   │       ├── HaloDocumentAddRequestEvent.java
│       │                   │       ├── HaloDocumentDeleteRequestEvent.java
│       │                   │       └── HaloDocumentRebuildRequestEvent.java
│       │                   ├── security/
│       │                   │   ├── AdditionalWebFilter.java
│       │                   │   ├── AfterSecurityWebFilter.java
│       │                   │   ├── AnonymousAuthenticationSecurityWebFilter.java
│       │                   │   ├── AuthenticationSecurityWebFilter.java
│       │                   │   ├── BeforeSecurityWebFilter.java
│       │                   │   ├── FormLoginSecurityWebFilter.java
│       │                   │   ├── HttpBasicSecurityWebFilter.java
│       │                   │   ├── LoginHandlerEnhancer.java
│       │                   │   ├── OAuth2AuthorizationCodeSecurityWebFilter.java
│       │                   │   ├── PersonalAccessToken.java
│       │                   │   ├── authentication/
│       │                   │   │   ├── CryptoService.java
│       │                   │   │   ├── login/
│       │                   │   │   │   └── UsernamePasswordAuthenticationManager.java
│       │                   │   │   └── oauth2/
│       │                   │   │       └── HaloOAuth2AuthenticationToken.java
│       │                   │   └── device/
│       │                   │       └── DeviceService.java
│       │                   └── theme/
│       │                       ├── Constant.java
│       │                       ├── ReactivePostContentHandler.java
│       │                       ├── ReactiveSinglePageContentHandler.java
│       │                       ├── TemplateNameResolver.java
│       │                       ├── dialect/
│       │                       │   ├── CommentWidget.java
│       │                       │   ├── ElementTagPostProcessor.java
│       │                       │   ├── TemplateFooterProcessor.java
│       │                       │   └── TemplateHeadProcessor.java
│       │                       ├── finders/
│       │                       │   ├── Finder.java
│       │                       │   └── vo/
│       │                       │       └── ExtensionVoOperator.java
│       │                       └── router/
│       │                           ├── ModelConst.java
│       │                           ├── PageUrlUtils.java
│       │                           └── UrlContextListResult.java
│       └── test/
│           └── java/
│               └── run/
│                   └── halo/
│                       └── app/
│                           ├── core/
│                           │   └── extension/
│                           │       ├── content/
│                           │       │   └── PostTest.java
│                           │       └── notification/
│                           │           └── SubscriptionTest.java
│                           ├── extension/
│                           │   ├── ExtensionUtilTest.java
│                           │   ├── FakeExtension.java
│                           │   ├── ListOptionsTest.java
│                           │   ├── PageRequestImplTest.java
│                           │   ├── SecretTest.java
│                           │   ├── controller/
│                           │   │   ├── ControllerBuilderTest.java
│                           │   │   ├── DefaultControllerTest.java
│                           │   │   ├── DefaultDelayQueueTest.java
│                           │   │   ├── DelayedEntryTest.java
│                           │   │   ├── ExtensionWatcherTest.java
│                           │   │   └── RequestSynchronizerTest.java
│                           │   ├── index/
│                           │   │   ├── IndexAttributeFactoryTest.java
│                           │   │   ├── IndexSpecTest.java
│                           │   │   ├── KeyComparatorTest.java
│                           │   │   ├── MultiValueBuilderTest.java
│                           │   │   ├── SingleValueBuilderTest.java
│                           │   │   ├── UnknownKeyTest.java
│                           │   │   └── query/
│                           │   │       └── QueriesTest.java
│                           │   ├── indexer/
│                           │   │   ├── DefaultIndexEngineTest.java
│                           │   │   └── LabelIndexImplTest.java
│                           │   └── router/
│                           │       └── selector/
│                           │           ├── LabelSelectorTest.java
│                           │           ├── OperatorTest.java
│                           │           └── SelectorConverterTest.java
│                           └── infra/
│                               └── utils/
│                                   ├── GenericClassUtilsTest.java
│                                   ├── JsonUtilsTest.java
│                                   └── PathUtilsTest.java
├── api-docs/
│   └── openapi/
│       └── v3_0/
│           ├── aggregated.json
│           ├── apis_console.api_v1alpha1.json
│           ├── apis_extension.api_v1alpha1.json
│           ├── apis_public.api_v1alpha1.json
│           └── apis_uc.api_v1alpha1.json
├── application/
│   ├── build.gradle
│   ├── libs/
│   │   ├── thymeleaf-3.1.3.RELEASE.jar
│   │   └── thymeleaf-spring6-3.1.3.RELEASE.jar
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── run/
│       │   │       └── halo/
│       │   │           └── app/
│       │   │               ├── Application.java
│       │   │               ├── content/
│       │   │               │   ├── AbstractContentService.java
│       │   │               │   ├── AbstractEventReconciler.java
│       │   │               │   ├── CategoryPostCountUpdater.java
│       │   │               │   ├── CategoryService.java
│       │   │               │   ├── Content.java
│       │   │               │   ├── ContentRequest.java
│       │   │               │   ├── ContentUpdateParam.java
│       │   │               │   ├── Contributor.java
│       │   │               │   ├── ListedPost.java
│       │   │               │   ├── ListedSinglePage.java
│       │   │               │   ├── ListedSnapshotDto.java
│       │   │               │   ├── NotificationReasonConst.java
│       │   │               │   ├── PostContentServiceImpl.java
│       │   │               │   ├── PostHideFromListStateUpdater.java
│       │   │               │   ├── PostQuery.java
│       │   │               │   ├── PostRequest.java
│       │   │               │   ├── PostService.java
│       │   │               │   ├── PostSorter.java
│       │   │               │   ├── SinglePageQuery.java
│       │   │               │   ├── SinglePageRequest.java
│       │   │               │   ├── SinglePageService.java
│       │   │               │   ├── SnapshotService.java
│       │   │               │   ├── Stats.java
│       │   │               │   ├── comment/
│       │   │               │   │   ├── AbstractCommentService.java
│       │   │               │   │   ├── CommentEmailOwner.java
│       │   │               │   │   ├── CommentNotificationReasonPublisher.java
│       │   │               │   │   ├── CommentQuery.java
│       │   │               │   │   ├── CommentRequest.java
│       │   │               │   │   ├── CommentService.java
│       │   │               │   │   ├── CommentServiceImpl.java
│       │   │               │   │   ├── CommentStats.java
│       │   │               │   │   ├── ListedComment.java
│       │   │               │   │   ├── ListedReply.java
│       │   │               │   │   ├── OwnerInfo.java
│       │   │               │   │   ├── PostCommentSubject.java
│       │   │               │   │   ├── ReplyNotificationSubscriptionHelper.java
│       │   │               │   │   ├── ReplyQuery.java
│       │   │               │   │   ├── ReplyRequest.java
│       │   │               │   │   ├── ReplyService.java
│       │   │               │   │   ├── ReplyServiceImpl.java
│       │   │               │   │   └── SinglePageCommentSubject.java
│       │   │               │   ├── impl/
│       │   │               │   │   ├── CategoryServiceImpl.java
│       │   │               │   │   ├── PostServiceImpl.java
│       │   │               │   │   ├── SinglePageServiceImpl.java
│       │   │               │   │   └── SnapshotServiceImpl.java
│       │   │               │   ├── permalinks/
│       │   │               │   │   ├── CategoryPermalinkPolicy.java
│       │   │               │   │   ├── ExtensionLocator.java
│       │   │               │   │   ├── PermalinkPolicy.java
│       │   │               │   │   ├── PostPermalinkPolicy.java
│       │   │               │   │   └── TagPermalinkPolicy.java
│       │   │               │   └── stats/
│       │   │               │       ├── PostStatsUpdater.java
│       │   │               │       ├── ReplyEventReconciler.java
│       │   │               │       ├── TagPostCountUpdater.java
│       │   │               │       ├── VisitedEventReconciler.java
│       │   │               │       └── VotedEventReconciler.java
│       │   │               ├── core/
│       │   │               │   ├── attachment/
│       │   │               │   │   ├── AttachmentChangedEvent.java
│       │   │               │   │   ├── AttachmentLister.java
│       │   │               │   │   ├── AttachmentRootGetter.java
│       │   │               │   │   ├── PolicyConfigChangeDetector.java
│       │   │               │   │   ├── SearchRequest.java
│       │   │               │   │   ├── endpoint/
│       │   │               │   │   │   ├── AttachmentEndpoint.java
│       │   │               │   │   │   ├── LocalAttachmentUploadHandler.java
│       │   │               │   │   │   └── PolicyEndpoint.java
│       │   │               │   │   ├── extension/
│       │   │               │   │   │   ├── LocalThumbnail.java
│       │   │               │   │   │   └── Thumbnail.java
│       │   │               │   │   ├── impl/
│       │   │               │   │   │   ├── AttachmentListerImpl.java
│       │   │               │   │   │   └── AttachmentRootGetterImpl.java
│       │   │               │   │   ├── reconciler/
│       │   │               │   │   │   ├── AttachmentReconciler.java
│       │   │               │   │   │   ├── LocalThumbnailsReconciler.java
│       │   │               │   │   │   ├── PolicyReconciler.java
│       │   │               │   │   │   └── ThumbnailReconciler.java
│       │   │               │   │   └── thumbnail/
│       │   │               │   │       ├── DefaultLocalThumbnailService.java
│       │   │               │   │       ├── DefaultThumbnailService.java
│       │   │               │   │       ├── LocalThumbnailService.java
│       │   │               │   │       ├── ThumbnailImgTagPostProcessor.java
│       │   │               │   │       ├── ThumbnailResourceTransformer.java
│       │   │               │   │       ├── ThumbnailService.java
│       │   │               │   │       └── ThumbnailUtils.java
│       │   │               │   ├── counter/
│       │   │               │   │   ├── CounterService.java
│       │   │               │   │   ├── CounterServiceImpl.java
│       │   │               │   │   └── MeterUtils.java
│       │   │               │   ├── endpoint/
│       │   │               │   │   ├── AttachmentHandler.java
│       │   │               │   │   ├── WebSocketEndpointManager.java
│       │   │               │   │   ├── WebSocketHandlerMapping.java
│       │   │               │   │   ├── console/
│       │   │               │   │   │   ├── AttachmentConsoleEndpoint.java
│       │   │               │   │   │   ├── AuthProviderEndpoint.java
│       │   │               │   │   │   ├── CommentEndpoint.java
│       │   │               │   │   │   ├── ConsoleUserEndpoint.java
│       │   │               │   │   │   ├── CustomEndpointsBuilder.java
│       │   │               │   │   │   ├── PluginEndpoint.java
│       │   │               │   │   │   ├── PostEndpoint.java
│       │   │               │   │   │   ├── ReplyEndpoint.java
│       │   │               │   │   │   ├── SinglePageEndpoint.java
│       │   │               │   │   │   ├── StatsEndpoint.java
│       │   │               │   │   │   ├── SystemConfigEndpoint.java
│       │   │               │   │   │   ├── TagEndpoint.java
│       │   │               │   │   │   ├── TrackerEndpoint.java
│       │   │               │   │   │   └── UserEndpoint.java
│       │   │               │   │   ├── theme/
│       │   │               │   │   │   ├── CategoryQueryEndpoint.java
│       │   │               │   │   │   ├── CommentFinderEndpoint.java
│       │   │               │   │   │   ├── MenuQueryEndpoint.java
│       │   │               │   │   │   ├── PluginQueryEndpoint.java
│       │   │               │   │   │   ├── PostPublicQuery.java
│       │   │               │   │   │   ├── PostQueryEndpoint.java
│       │   │               │   │   │   ├── PublicApiUtils.java
│       │   │               │   │   │   ├── SinglePageQueryEndpoint.java
│       │   │               │   │   │   ├── SiteStatsQueryEndpoint.java
│       │   │               │   │   │   ├── TagQueryEndpoint.java
│       │   │               │   │   │   └── ThumbnailEndpoint.java
│       │   │               │   │   └── uc/
│       │   │               │   │       ├── AnnotationSettingEndpoint.java
│       │   │               │   │       ├── AttachmentUcEndpoint.java
│       │   │               │   │       ├── UcPostEndpoint.java
│       │   │               │   │       ├── UcSnapshotEndpoint.java
│       │   │               │   │       ├── UcUserPreferenceEndpoint.java
│       │   │               │   │       └── UserConnectionEndpoint.java
│       │   │               │   ├── reconciler/
│       │   │               │   │   ├── AnnotationSettingReconciler.java
│       │   │               │   │   ├── AuthProviderReconciler.java
│       │   │               │   │   ├── CategoryReconciler.java
│       │   │               │   │   ├── CommentReconciler.java
│       │   │               │   │   ├── MenuItemReconciler.java
│       │   │               │   │   ├── PluginReconciler.java
│       │   │               │   │   ├── PostCounterReconciler.java
│       │   │               │   │   ├── PostReconciler.java
│       │   │               │   │   ├── ReplyReconciler.java
│       │   │               │   │   ├── ReverseProxyReconciler.java
│       │   │               │   │   ├── RoleReconciler.java
│       │   │               │   │   ├── SinglePageReconciler.java
│       │   │               │   │   ├── SystemConfigReconciler.java
│       │   │               │   │   ├── TagReconciler.java
│       │   │               │   │   ├── ThemeReconciler.java
│       │   │               │   │   └── UserReconciler.java
│       │   │               │   └── user/
│       │   │               │       └── service/
│       │   │               │           ├── DefaultRoleService.java
│       │   │               │           ├── EmailPasswordRecoveryService.java
│       │   │               │           ├── EmailVerificationService.java
│       │   │               │           ├── InMemoryResetTokenRepository.java
│       │   │               │           ├── InvalidResetTokenException.java
│       │   │               │           ├── PatService.java
│       │   │               │           ├── ResetToken.java
│       │   │               │           ├── ResetTokenRepository.java
│       │   │               │           ├── SettingConfigService.java
│       │   │               │           ├── UserConnectionService.java
│       │   │               │           ├── UserLoginOrLogoutProcessing.java
│       │   │               │           └── impl/
│       │   │               │               ├── DefaultAttachmentService.java
│       │   │               │               ├── EmailPasswordRecoveryServiceImpl.java
│       │   │               │               ├── EmailVerificationServiceImpl.java
│       │   │               │               ├── PatServiceImpl.java
│       │   │               │               ├── SettingConfigServiceImpl.java
│       │   │               │               ├── UserConnectionServiceImpl.java
│       │   │               │               └── UserServiceImpl.java
│       │   │               ├── event/
│       │   │               │   ├── post/
│       │   │               │   │   ├── CategoryHiddenStateChangeEvent.java
│       │   │               │   │   ├── CommentCreatedEvent.java
│       │   │               │   │   ├── CommentUnreadReplyCountChangedEvent.java
│       │   │               │   │   ├── DownvotedEvent.java
│       │   │               │   │   ├── PostStatsChangedEvent.java
│       │   │               │   │   ├── ReplyChangedEvent.java
│       │   │               │   │   ├── ReplyCreatedEvent.java
│       │   │               │   │   ├── ReplyDeletedEvent.java
│       │   │               │   │   ├── ReplyEvent.java
│       │   │               │   │   ├── UpvotedEvent.java
│       │   │               │   │   ├── VisitedEvent.java
│       │   │               │   │   └── VotedEvent.java
│       │   │               │   └── user/
│       │   │               │       └── PasswordChangedEvent.java
│       │   │               ├── extension/
│       │   │               │   ├── DefaultSchemeManager.java
│       │   │               │   ├── DelegateExtensionClient.java
│       │   │               │   ├── ExtensionConverter.java
│       │   │               │   ├── ExtensionStoreUtil.java
│       │   │               │   ├── JSONExtensionConverter.java
│       │   │               │   ├── ReactiveExtensionClientImpl.java
│       │   │               │   ├── availability/
│       │   │               │   │   └── IndexBuildState.java
│       │   │               │   ├── controller/
│       │   │               │   │   └── DefaultControllerManager.java
│       │   │               │   ├── event/
│       │   │               │   │   ├── IndexerBuiltEvent.java
│       │   │               │   │   ├── SchemeAddedEvent.java
│       │   │               │   │   └── SchemeRemovedEvent.java
│       │   │               │   ├── exception/
│       │   │               │   │   ├── ExtensionConvertException.java
│       │   │               │   │   ├── ExtensionNotFoundException.java
│       │   │               │   │   └── SchemaViolationException.java
│       │   │               │   ├── gc/
│       │   │               │   │   ├── GcControllerInitializer.java
│       │   │               │   │   ├── GcReconciler.java
│       │   │               │   │   ├── GcRequest.java
│       │   │               │   │   ├── GcSynchronizer.java
│       │   │               │   │   └── GcWatcher.java
│       │   │               │   ├── index/
│       │   │               │   │   ├── DefaultIndexEngine.java
│       │   │               │   │   ├── DefaultIndices.java
│       │   │               │   │   ├── DefaultIndicesManager.java
│       │   │               │   │   ├── Index.java
│       │   │               │   │   ├── IndexEngine.java
│       │   │               │   │   ├── Indices.java
│       │   │               │   │   ├── IndicesInitializer.java
│       │   │               │   │   ├── IndicesManager.java
│       │   │               │   │   ├── LabelIndex.java
│       │   │               │   │   ├── LabelIndexQuery.java
│       │   │               │   │   ├── MultiValueIndex.java
│       │   │               │   │   ├── SingleValueIndex.java
│       │   │               │   │   ├── StringUnknownKeyConverter.java
│       │   │               │   │   ├── TransactionalOperation.java
│       │   │               │   │   ├── ValueIndexQuery.java
│       │   │               │   │   └── query/
│       │   │               │   │       └── QueryVisitor.java
│       │   │               │   ├── indexer/
│       │   │               │   │   └── DefaultIndicesInitializer.java
│       │   │               │   ├── router/
│       │   │               │   │   ├── ExtensionCompositeRouterFunction.java
│       │   │               │   │   ├── ExtensionCreateHandler.java
│       │   │               │   │   ├── ExtensionDeleteHandler.java
│       │   │               │   │   ├── ExtensionGetHandler.java
│       │   │               │   │   ├── ExtensionListHandler.java
│       │   │               │   │   ├── ExtensionPatchHandler.java
│       │   │               │   │   ├── ExtensionRouterFunctionFactory.java
│       │   │               │   │   ├── ExtensionUpdateHandler.java
│       │   │               │   │   └── JsonPatch.java
│       │   │               │   └── store/
│       │   │               │       ├── ExtensionStore.java
│       │   │               │       ├── ExtensionStoreClient.java
│       │   │               │       ├── ExtensionStoreClientJPAImpl.java
│       │   │               │       ├── ExtensionStoreRepository.java
│       │   │               │       ├── ReactiveExtensionStoreClient.java
│       │   │               │       └── ReactiveExtensionStoreClientImpl.java
│       │   │               ├── infra/
│       │   │               │   ├── DefaultBackupRootGetter.java
│       │   │               │   ├── DefaultExternalLinkProcessor.java
│       │   │               │   ├── DefaultInitializationStateGetter.java
│       │   │               │   ├── DefaultReactiveUrlDataBufferFetcher.java
│       │   │               │   ├── DefaultSystemConfigFetcher.java
│       │   │               │   ├── DefaultSystemVersionSupplier.java
│       │   │               │   ├── DefaultThemeRootGetter.java
│       │   │               │   ├── ExtensionInitializedEvent.java
│       │   │               │   ├── ExtensionResourceInitializer.java
│       │   │               │   ├── ExternalUrlChangedEvent.java
│       │   │               │   ├── InitializationPhase.java
│       │   │               │   ├── InitializationStateGetter.java
│       │   │               │   ├── ReactiveExtensionPaginatedOperator.java
│       │   │               │   ├── ReactiveExtensionPaginatedOperatorImpl.java
│       │   │               │   ├── ReactiveUrlDataBufferFetcher.java
│       │   │               │   ├── SchemeInitializer.java
│       │   │               │   ├── SecureRequestMappingHandlerAdapter.java
│       │   │               │   ├── SecureServerRequest.java
│       │   │               │   ├── SecureServerWebExchange.java
│       │   │               │   ├── SystemConfigChangedEvent.java
│       │   │               │   ├── SystemConfigFetcher.java
│       │   │               │   ├── SystemConfigFirstExternalUrlSupplier.java
│       │   │               │   ├── SystemConfigInitializer.java
│       │   │               │   ├── SystemInfoGetterImpl.java
│       │   │               │   ├── SystemState.java
│       │   │               │   ├── ThemeRootGetter.java
│       │   │               │   ├── actuator/
│       │   │               │   │   ├── DatabaseInfoContributor.java
│       │   │               │   │   ├── GlobalInfo.java
│       │   │               │   │   ├── GlobalInfoEndpoint.java
│       │   │               │   │   ├── GlobalInfoService.java
│       │   │               │   │   ├── GlobalInfoServiceImpl.java
│       │   │               │   │   └── RestartEndpoint.java
│       │   │               │   ├── config/
│       │   │               │   │   ├── ExtensionConfiguration.java
│       │   │               │   │   ├── HaloConfiguration.java
│       │   │               │   │   ├── JacksonAdapterModule.java
│       │   │               │   │   ├── R2dbcConfiguration.java
│       │   │               │   │   ├── SessionConfiguration.java
│       │   │               │   │   ├── SwaggerConfig.java
│       │   │               │   │   ├── WebFluxConfig.java
│       │   │               │   │   └── WebServerSecurityConfig.java
│       │   │               │   ├── exception/
│       │   │               │   │   ├── AccessDeniedException.java
│       │   │               │   │   ├── AttachmentAlreadyExistsException.java
│       │   │               │   │   ├── DuplicateNameException.java
│       │   │               │   │   ├── EmailAlreadyTakenException.java
│       │   │               │   │   ├── EmailVerificationFailed.java
│       │   │               │   │   ├── Exceptions.java
│       │   │               │   │   ├── FileSizeExceededException.java
│       │   │               │   │   ├── FileTypeNotAllowedException.java
│       │   │               │   │   ├── NotFoundException.java
│       │   │               │   │   ├── OAuth2UserAlreadyBoundException.java
│       │   │               │   │   ├── PluginAlreadyExistsException.java
│       │   │               │   │   ├── PluginDependenciesNotEnabledException.java
│       │   │               │   │   ├── PluginDependencyException.java
│       │   │               │   │   ├── PluginDependentsNotDisabledException.java
│       │   │               │   │   ├── PluginInstallationException.java
│       │   │               │   │   ├── PluginRuntimeIncompatibleException.java
│       │   │               │   │   ├── RateLimitExceededException.java
│       │   │               │   │   ├── RequestBodyValidationException.java
│       │   │               │   │   ├── RequestRestrictedException.java
│       │   │               │   │   ├── RestrictedNameException.java
│       │   │               │   │   ├── ThemeAlreadyExistsException.java
│       │   │               │   │   ├── ThemeInstallationException.java
│       │   │               │   │   ├── ThemeUninstallException.java
│       │   │               │   │   ├── ThemeUpgradeException.java
│       │   │               │   │   ├── UnsatisfiedAttributeValueException.java
│       │   │               │   │   ├── UserNotFoundException.java
│       │   │               │   │   └── handlers/
│       │   │               │   │       ├── HaloErrorConfiguration.java
│       │   │               │   │       ├── HaloErrorWebExceptionHandler.java
│       │   │               │   │       └── ProblemDetailErrorAttributes.java
│       │   │               │   ├── properties/
│       │   │               │   │   ├── AttachmentProperties.java
│       │   │               │   │   ├── CacheProperties.java
│       │   │               │   │   ├── ExtensionProperties.java
│       │   │               │   │   ├── HaloProperties.java
│       │   │               │   │   ├── JwtProperties.java
│       │   │               │   │   ├── ProxyProperties.java
│       │   │               │   │   ├── SecurityProperties.java
│       │   │               │   │   ├── ThemeProperties.java
│       │   │               │   │   └── UiProperties.java
│       │   │               │   ├── ui/
│       │   │               │   │   ├── ProxyFilter.java
│       │   │               │   │   ├── WebSocketRequestPredicate.java
│       │   │               │   │   ├── WebSocketServerWebExchangeMatcher.java
│       │   │               │   │   └── WebSocketUtils.java
│       │   │               │   ├── utils/
│       │   │               │   │   ├── Base62Utils.java
│       │   │               │   │   ├── FileNameUtils.java
│       │   │               │   │   ├── FileUtils.java
│       │   │               │   │   ├── HaloUtils.java
│       │   │               │   │   ├── IpAddressUtils.java
│       │   │               │   │   ├── ReactiveUtils.java
│       │   │               │   │   ├── SettingUtils.java
│       │   │               │   │   ├── SortUtils.java
│       │   │               │   │   ├── SystemConfigUtils.java
│       │   │               │   │   ├── VersionUtils.java
│       │   │               │   │   └── YamlUnstructuredLoader.java
│       │   │               │   └── webfilter/
│       │   │               │       ├── AdditionalWebFilterChainProxy.java
│       │   │               │       └── LocaleChangeWebFilter.java
│       │   │               ├── migration/
│       │   │               │   ├── BackupFile.java
│       │   │               │   ├── BackupReconciler.java
│       │   │               │   ├── MigrationEndpoint.java
│       │   │               │   ├── MigrationService.java
│       │   │               │   └── impl/
│       │   │               │       └── MigrationServiceImpl.java
│       │   │               ├── notification/
│       │   │               │   ├── DefaultNotificationCenter.java
│       │   │               │   ├── DefaultNotificationReasonEmitter.java
│       │   │               │   ├── DefaultNotificationSender.java
│       │   │               │   ├── DefaultNotificationService.java
│       │   │               │   ├── DefaultNotificationTemplateRender.java
│       │   │               │   ├── DefaultNotifierConfigStore.java
│       │   │               │   ├── DefaultSubscriberEmailResolver.java
│       │   │               │   ├── EmailNotifier.java
│       │   │               │   ├── EmailSenderHelper.java
│       │   │               │   ├── EmailSenderHelperImpl.java
│       │   │               │   ├── LanguageUtils.java
│       │   │               │   ├── NotificationSender.java
│       │   │               │   ├── NotificationTemplateRender.java
│       │   │               │   ├── NotificationTrigger.java
│       │   │               │   ├── NotifierConfigStore.java
│       │   │               │   ├── ReasonNotificationTemplateSelector.java
│       │   │               │   ├── ReasonNotificationTemplateSelectorImpl.java
│       │   │               │   ├── RecipientResolver.java
│       │   │               │   ├── RecipientResolverImpl.java
│       │   │               │   ├── Subscriber.java
│       │   │               │   ├── SubscriberEmailResolver.java
│       │   │               │   ├── SubscriptionService.java
│       │   │               │   ├── SubscriptionServiceImpl.java
│       │   │               │   ├── UserNotificationPreference.java
│       │   │               │   ├── UserNotificationPreferenceService.java
│       │   │               │   ├── UserNotificationPreferenceServiceImpl.java
│       │   │               │   ├── UserNotificationQuery.java
│       │   │               │   ├── UserNotificationService.java
│       │   │               │   └── endpoint/
│       │   │               │       ├── ConsoleNotifierEndpoint.java
│       │   │               │       ├── EmailConfigValidationEndpoint.java
│       │   │               │       ├── SubscriptionRouter.java
│       │   │               │       ├── UserNotificationEndpoint.java
│       │   │               │       ├── UserNotificationPreferencesEndpoint.java
│       │   │               │       └── UserNotifierEndpoint.java
│       │   │               ├── plugin/
│       │   │               │   ├── AggregatedRouterFunction.java
│       │   │               │   ├── BuiltInPluginsInitializer.java
│       │   │               │   ├── DefaultDevelopmentPluginRepository.java
│       │   │               │   ├── DefaultPluginApplicationContextFactory.java
│       │   │               │   ├── DefaultPluginGetter.java
│       │   │               │   ├── DefaultPluginRouterFunctionRegistry.java
│       │   │               │   ├── DefaultReactiveSettingFetcher.java
│       │   │               │   ├── DefaultSettingFetcher.java
│       │   │               │   ├── DefaultSpringPlugin.java
│       │   │               │   ├── DevPluginLoader.java
│       │   │               │   ├── HaloPluginManager.java
│       │   │               │   ├── HaloSharedEventDelegator.java
│       │   │               │   ├── OptionalDependentResolver.java
│       │   │               │   ├── PluginApplicationContext.java
│       │   │               │   ├── PluginApplicationContextFactory.java
│       │   │               │   ├── PluginAutoConfiguration.java
│       │   │               │   ├── PluginBeforeStopSyncListener.java
│       │   │               │   ├── PluginConst.java
│       │   │               │   ├── PluginControllerManager.java
│       │   │               │   ├── PluginDevelopmentInitializer.java
│       │   │               │   ├── PluginExtensionLoaderUtils.java
│       │   │               │   ├── PluginFinder.java
│       │   │               │   ├── PluginGetter.java
│       │   │               │   ├── PluginNotFoundException.java
│       │   │               │   ├── PluginProperties.java
│       │   │               │   ├── PluginRequestMappingHandlerMapping.java
│       │   │               │   ├── PluginRouterFunctionRegistry.java
│       │   │               │   ├── PluginService.java
│       │   │               │   ├── PluginServiceImpl.java
│       │   │               │   ├── PluginSharedEventDelegator.java
│       │   │               │   ├── PluginStartedListener.java
│       │   │               │   ├── PluginUtils.java
│       │   │               │   ├── PluginsRootGetterImpl.java
│       │   │               │   ├── PropertyPluginStatusProvider.java
│       │   │               │   ├── SharedApplicationContextFactory.java
│       │   │               │   ├── SharedEventDispatcher.java
│       │   │               │   ├── SpringComponentsFinder.java
│       │   │               │   ├── SpringExtensionFactory.java
│       │   │               │   ├── SpringPlugin.java
│       │   │               │   ├── SpringPluginFactory.java
│       │   │               │   ├── SpringPluginManager.java
│       │   │               │   ├── YamlPluginDescriptorFinder.java
│       │   │               │   ├── YamlPluginFinder.java
│       │   │               │   ├── event/
│       │   │               │   │   ├── HaloPluginBeforeStopEvent.java
│       │   │               │   │   ├── HaloPluginStartedEvent.java
│       │   │               │   │   ├── HaloPluginStoppedEvent.java
│       │   │               │   │   ├── SpringPluginStartedEvent.java
│       │   │               │   │   ├── SpringPluginStartingEvent.java
│       │   │               │   │   ├── SpringPluginStoppedEvent.java
│       │   │               │   │   └── SpringPluginStoppingEvent.java
│       │   │               │   ├── extensionpoint/
│       │   │               │   │   ├── AbstractDefinitionGetter.java
│       │   │               │   │   ├── DefaultExtensionGetter.java
│       │   │               │   │   ├── ExtensionDefinition.java
│       │   │               │   │   ├── ExtensionDefinitionGetter.java
│       │   │               │   │   ├── ExtensionDefinitionGetterImpl.java
│       │   │               │   │   ├── ExtensionPointDefinition.java
│       │   │               │   │   ├── ExtensionPointDefinitionGetter.java
│       │   │               │   │   └── ExtensionPointDefinitionGetterImpl.java
│       │   │               │   └── resources/
│       │   │               │       ├── BundleResourceUtils.java
│       │   │               │       ├── ReverseProxyRouterFunctionFactory.java
│       │   │               │       └── ReverseProxyRouterFunctionRegistry.java
│       │   │               ├── search/
│       │   │               │   ├── HaloDocumentEventsListener.java
│       │   │               │   ├── IndexEndpoint.java
│       │   │               │   ├── IndicesEndpoint.java
│       │   │               │   ├── SearchEngineUnavailableException.java
│       │   │               │   ├── SearchServiceImpl.java
│       │   │               │   ├── lucene/
│       │   │               │   │   └── LuceneSearchEngine.java
│       │   │               │   └── post/
│       │   │               │       ├── PostEventsListener.java
│       │   │               │       └── PostHaloDocumentsProvider.java
│       │   │               ├── security/
│       │   │               │   ├── AuthProviderService.java
│       │   │               │   ├── AuthProviderServiceImpl.java
│       │   │               │   ├── CorsConfigurer.java
│       │   │               │   ├── CsrfConfigurer.java
│       │   │               │   ├── DefaultServerAuthenticationEntryPoint.java
│       │   │               │   ├── DefaultSuperAdminInitializer.java
│       │   │               │   ├── DefaultUserDetailService.java
│       │   │               │   ├── ExceptionSecurityConfigurer.java
│       │   │               │   ├── HaloRedirectAuthenticationSuccessHandler.java
│       │   │               │   ├── HaloServerRequestCache.java
│       │   │               │   ├── HaloUserDetails.java
│       │   │               │   ├── InitializeRedirectionWebFilter.java
│       │   │               │   ├── ListedAuthProvider.java
│       │   │               │   ├── LoginHandlerEnhancerImpl.java
│       │   │               │   ├── LogoutSecurityConfigurer.java
│       │   │               │   ├── RedirectAccessDeniedHandler.java
│       │   │               │   ├── SecurityWebFiltersConfigurer.java
│       │   │               │   ├── SuperAdminInitializer.java
│       │   │               │   ├── authentication/
│       │   │               │   │   ├── SecurityConfigurer.java
│       │   │               │   │   ├── WebExchangeMatchers.java
│       │   │               │   │   ├── exception/
│       │   │               │   │   │   ├── TooManyRequestsException.java
│       │   │               │   │   │   └── TwoFactorAuthException.java
│       │   │               │   │   ├── impl/
│       │   │               │   │   │   └── RsaKeyService.java
│       │   │               │   │   ├── login/
│       │   │               │   │   │   ├── HaloUser.java
│       │   │               │   │   │   ├── InvalidEncryptedMessageException.java
│       │   │               │   │   │   ├── LoginAuthenticationConverter.java
│       │   │               │   │   │   ├── LoginSecurityConfigurer.java
│       │   │               │   │   │   ├── PublicKeyRouteBuilder.java
│       │   │               │   │   │   ├── UsernamePasswordDelegatingAuthenticationManager.java
│       │   │               │   │   │   └── UsernamePasswordHandler.java
│       │   │               │   │   ├── oauth2/
│       │   │               │   │   │   ├── DefaultOAuth2LoginHandlerEnhancer.java
│       │   │               │   │   │   ├── MapOAuth2AuthenticationFilter.java
│       │   │               │   │   │   ├── OAuth2AuthenticationTokenCache.java
│       │   │               │   │   │   ├── OAuth2LoginHandlerEnhancer.java
│       │   │               │   │   │   ├── OAuth2SecurityConfigurer.java
│       │   │               │   │   │   └── WebSessionOAuth2AuthenticationTokenCache.java
│       │   │               │   │   ├── pat/
│       │   │               │   │   │   ├── PatAuthenticationConverter.java
│       │   │               │   │   │   ├── PatAuthenticationManager.java
│       │   │               │   │   │   ├── PatEndpoint.java
│       │   │               │   │   │   ├── PatSecurityConfigurer.java
│       │   │               │   │   │   ├── UserScopedPatHandler.java
│       │   │               │   │   │   └── UserScopedPatHandlerImpl.java
│       │   │               │   │   ├── rememberme/
│       │   │               │   │   │   ├── CookieSignatureKeyResolver.java
│       │   │               │   │   │   ├── DefaultCookieSignatureKeyResolver.java
│       │   │               │   │   │   ├── PersistentRememberMeTokenRepository.java
│       │   │               │   │   │   ├── PersistentRememberMeTokenRepositoryImpl.java
│       │   │               │   │   │   ├── PersistentTokenBasedRememberMeServices.java
│       │   │               │   │   │   ├── RememberMeAuthenticationManager.java
│       │   │               │   │   │   ├── RememberMeConfigurer.java
│       │   │               │   │   │   ├── RememberMeCookieResolver.java
│       │   │               │   │   │   ├── RememberMeCookieResolverImpl.java
│       │   │               │   │   │   ├── RememberMeRequestCache.java
│       │   │               │   │   │   ├── RememberMeServices.java
│       │   │               │   │   │   ├── RememberMeTokenRevoker.java
│       │   │               │   │   │   ├── RememberTokenCleaner.java
│       │   │               │   │   │   ├── TokenBasedRememberMeServices.java
│       │   │               │   │   │   └── WebSessionRememberMeRequestCache.java
│       │   │               │   │   └── twofactor/
│       │   │               │   │       ├── TotpAuthenticationSuccessHandler.java
│       │   │               │   │       ├── TwoFactorAuthEndpoint.java
│       │   │               │   │       ├── TwoFactorAuthRequiredException.java
│       │   │               │   │       ├── TwoFactorAuthSecurityConfigurer.java
│       │   │               │   │       ├── TwoFactorAuthSettings.java
│       │   │               │   │       ├── TwoFactorAuthentication.java
│       │   │               │   │       ├── TwoFactorAuthenticationEntryPoint.java
│       │   │               │   │       ├── TwoFactorUtils.java
│       │   │               │   │       └── totp/
│       │   │               │   │           ├── DefaultTotpAuthService.java
│       │   │               │   │           ├── TotpAuthService.java
│       │   │               │   │           ├── TotpAuthenticationManager.java
│       │   │               │   │           ├── TotpAuthenticationToken.java
│       │   │               │   │           └── TotpCodeAuthenticationConverter.java
│       │   │               │   ├── authorization/
│       │   │               │   │   ├── Attributes.java
│       │   │               │   │   ├── AttributesRecord.java
│       │   │               │   │   ├── AuthorityUtils.java
│       │   │               │   │   ├── AuthorizationExchangeConfigurers.java
│       │   │               │   │   ├── AuthorizationRuleResolver.java
│       │   │               │   │   ├── AuthorizingVisitor.java
│       │   │               │   │   ├── DefaultRuleResolver.java
│       │   │               │   │   ├── PolicyRuleList.java
│       │   │               │   │   ├── RbacRequestEvaluation.java
│       │   │               │   │   ├── RequestInfo.java
│       │   │               │   │   ├── RequestInfoAuthorizationManager.java
│       │   │               │   │   ├── RequestInfoFactory.java
│       │   │               │   │   └── RuleAccumulator.java
│       │   │               │   ├── device/
│       │   │               │   │   ├── DeviceCookieResolver.java
│       │   │               │   │   ├── DeviceCookieResolverImpl.java
│       │   │               │   │   ├── DeviceEndpoint.java
│       │   │               │   │   ├── DeviceReconciler.java
│       │   │               │   │   ├── DeviceSecurityConfigurer.java
│       │   │               │   │   ├── DeviceServiceImpl.java
│       │   │               │   │   ├── DeviceSessionFilter.java
│       │   │               │   │   ├── NewDeviceLoginEvent.java
│       │   │               │   │   └── NewDeviceLoginListener.java
│       │   │               │   ├── jackson2/
│       │   │               │   │   ├── HaloOAuth2AuthenticationTokenMixin.java
│       │   │               │   │   ├── HaloSecurityJackson2Module.java
│       │   │               │   │   ├── HaloUserMixin.java
│       │   │               │   │   ├── SwitchUserGrantedAuthorityMixIn.java
│       │   │               │   │   └── TwoFactorAuthenticationMixin.java
│       │   │               │   ├── preauth/
│       │   │               │   │   ├── DefaultPasswordResetAvailabilityProviders.java
│       │   │               │   │   ├── EmailPasswordResetAvailabilityProvider.java
│       │   │               │   │   ├── PasswordResetAvailabilityProvider.java
│       │   │               │   │   ├── PasswordResetAvailabilityProviders.java
│       │   │               │   │   ├── PreAuthEmailPasswordResetEndpoint.java
│       │   │               │   │   ├── PreAuthLoginEndpoint.java
│       │   │               │   │   ├── PreAuthSignUpEndpoint.java
│       │   │               │   │   ├── PreAuthTwoFactorEndpoint.java
│       │   │               │   │   └── SystemSetupEndpoint.java
│       │   │               │   ├── session/
│       │   │               │   │   ├── InMemoryReactiveIndexedSessionRepository.java
│       │   │               │   │   ├── ReactiveIndexedSessionRepository.java
│       │   │               │   │   └── SessionInvalidationListener.java
│       │   │               │   └── switchuser/
│       │   │               │       └── SwitchUserConfigurer.java
│       │   │               └── theme/
│       │   │                   ├── CompositeTemplateResolver.java
│       │   │                   ├── DefaultTemplateEnum.java
│       │   │                   ├── DefaultTemplateNameResolver.java
│       │   │                   ├── DefaultViewNameResolver.java
│       │   │                   ├── HaloViewResolver.java
│       │   │                   ├── ReactiveSpelVariableExpressionEvaluator.java
│       │   │                   ├── SiteSettingVariablesAcquirer.java
│       │   │                   ├── TemplateEngineManager.java
│       │   │                   ├── ThemeContext.java
│       │   │                   ├── ThemeContextBasedVariablesAcquirer.java
│       │   │                   ├── ThemeLinkBuilder.java
│       │   │                   ├── ThemeLocaleContextResolver.java
│       │   │                   ├── ThemeResolver.java
│       │   │                   ├── UserLocaleRequestAttributeWriteFilter.java
│       │   │                   ├── ViewContextBasedVariablesAcquirer.java
│       │   │                   ├── ViewNameResolver.java
│       │   │                   ├── config/
│       │   │                   │   ├── ThemeConfiguration.java
│       │   │                   │   └── ThemeWebFluxConfigurer.java
│       │   │                   ├── dialect/
│       │   │                   │   ├── CommentElementTagProcessor.java
│       │   │                   │   ├── CommentEnabledVariableProcessor.java
│       │   │                   │   ├── ContentTemplateHeadProcessor.java
│       │   │                   │   ├── DefaultFaviconHeadProcessor.java
│       │   │                   │   ├── DefaultLinkExpressionFactory.java
│       │   │                   │   ├── DuplicateMetaTagProcessor.java
│       │   │                   │   ├── EvaluationContextEnhancer.java
│       │   │                   │   ├── GeneratorMetaProcessor.java
│       │   │                   │   ├── GlobalHeadInjectionProcessor.java
│       │   │                   │   ├── GlobalSeoProcessor.java
│       │   │                   │   ├── HaloExpressionObjectFactory.java
│       │   │                   │   ├── HaloPostTemplateHandler.java
│       │   │                   │   ├── HaloProcessorDialect.java
│       │   │                   │   ├── HaloSpringSecurityDialect.java
│       │   │                   │   ├── HaloTrackerProcessor.java
│       │   │                   │   ├── IndexSeoProcessor.java
│       │   │                   │   ├── InjectionExcluderProcessor.java
│       │   │                   │   ├── LinkExpressionObjectDialect.java
│       │   │                   │   ├── SecureTemplateContext.java
│       │   │                   │   ├── SecureTemplateContextWrapper.java
│       │   │                   │   ├── SecureTemplateWebContext.java
│       │   │                   │   ├── TemplateFooterElementTagProcessor.java
│       │   │                   │   ├── TemplateGlobalHeadProcessor.java
│       │   │                   │   └── expression/
│       │   │                   │       └── Annotations.java
│       │   │                   ├── endpoint/
│       │   │                   │   └── ThemeEndpoint.java
│       │   │                   ├── engine/
│       │   │                   │   ├── DefaultThemeTemplateAvailabilityProvider.java
│       │   │                   │   ├── HaloTemplateEngine.java
│       │   │                   │   ├── PluginClassloaderTemplateResolver.java
│       │   │                   │   └── ThemeTemplateAvailabilityProvider.java
│       │   │                   ├── finders/
│       │   │                   │   ├── CategoryFinder.java
│       │   │                   │   ├── CommentFinder.java
│       │   │                   │   ├── CommentPublicQueryService.java
│       │   │                   │   ├── ContributorFinder.java
│       │   │                   │   ├── DefaultFinderRegistry.java
│       │   │                   │   ├── FinderRegistry.java
│       │   │                   │   ├── MenuFinder.java
│       │   │                   │   ├── PluginFinder.java
│       │   │                   │   ├── PostFinder.java
│       │   │                   │   ├── PostPublicQueryService.java
│       │   │                   │   ├── SinglePageConversionService.java
│       │   │                   │   ├── SinglePageFinder.java
│       │   │                   │   ├── SiteStatsFinder.java
│       │   │                   │   ├── TagFinder.java
│       │   │                   │   ├── ThemeFinder.java
│       │   │                   │   ├── ThumbnailFinder.java
│       │   │                   │   ├── impl/
│       │   │                   │   │   ├── CategoryFinderImpl.java
│       │   │                   │   │   ├── CommentFinderImpl.java
│       │   │                   │   │   ├── CommentPublicQueryServiceImpl.java
│       │   │                   │   │   ├── ContributorFinderImpl.java
│       │   │                   │   │   ├── MenuFinderImpl.java
│       │   │                   │   │   ├── PluginFinderImpl.java
│       │   │                   │   │   ├── PostFinderImpl.java
│       │   │                   │   │   ├── PostPublicQueryServiceImpl.java
│       │   │                   │   │   ├── SinglePageConversionServiceImpl.java
│       │   │                   │   │   ├── SinglePageFinderImpl.java
│       │   │                   │   │   ├── SiteStatsFinderImpl.java
│       │   │                   │   │   ├── TagFinderImpl.java
│       │   │                   │   │   ├── ThemeFinderImpl.java
│       │   │                   │   │   └── ThumbnailFinderImpl.java
│       │   │                   │   └── vo/
│       │   │                   │       ├── CategoryTreeVo.java
│       │   │                   │       ├── CategoryVo.java
│       │   │                   │       ├── CommentStatsVo.java
│       │   │                   │       ├── CommentVo.java
│       │   │                   │       ├── CommentWithReplyVo.java
│       │   │                   │       ├── ContentVo.java
│       │   │                   │       ├── ContributorVo.java
│       │   │                   │       ├── ListedPostVo.java
│       │   │                   │       ├── ListedSinglePageVo.java
│       │   │                   │       ├── MenuItemVo.java
│       │   │                   │       ├── MenuVo.java
│       │   │                   │       ├── NavigationPostVo.java
│       │   │                   │       ├── PostArchiveVo.java
│       │   │                   │       ├── PostArchiveYearMonthVo.java
│       │   │                   │       ├── PostVo.java
│       │   │                   │       ├── ReplyVo.java
│       │   │                   │       ├── SinglePageVo.java
│       │   │                   │       ├── SiteSettingVo.java
│       │   │                   │       ├── SiteStatsVo.java
│       │   │                   │       ├── StatsVo.java
│       │   │                   │       ├── TagVo.java
│       │   │                   │       ├── ThemeVo.java
│       │   │                   │       ├── UserVo.java
│       │   │                   │       └── VisualizableTreeNode.java
│       │   │                   ├── message/
│       │   │                   │   ├── ThemeMessageResolutionUtils.java
│       │   │                   │   └── ThemeMessageResolver.java
│       │   │                   ├── router/
│       │   │                   │   ├── DefaultQueryPostPredicateResolver.java
│       │   │                   │   ├── ExtensionPermalinkPatternUpdater.java
│       │   │                   │   ├── ModelMapUtils.java
│       │   │                   │   ├── PermalinkRuleChangedEvent.java
│       │   │                   │   ├── PreviewRouterFunction.java
│       │   │                   │   ├── ReactiveQueryPostPredicateResolver.java
│       │   │                   │   ├── SinglePageRoute.java
│       │   │                   │   ├── ThemeCompositeRouterFunction.java
│       │   │                   │   ├── TitleVisibilityIdentifyCalculator.java
│       │   │                   │   └── factories/
│       │   │                   │       ├── ArchiveRouteFactory.java
│       │   │                   │       ├── AuthorPostsRouteFactory.java
│       │   │                   │       ├── CategoriesRouteFactory.java
│       │   │                   │       ├── CategoryPostRouteFactory.java
│       │   │                   │       ├── IndexRouteFactory.java
│       │   │                   │       ├── PostRouteFactory.java
│       │   │                   │       ├── RouteFactory.java
│       │   │                   │       ├── TagPostRouteFactory.java
│       │   │                   │       └── TagsRouteFactory.java
│       │   │                   ├── service/
│       │   │                   │   ├── ThemeService.java
│       │   │                   │   ├── ThemeServiceImpl.java
│       │   │                   │   └── ThemeUtils.java
│       │   │                   └── utils/
│       │   │                       └── PatternUtils.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── spring-devtools.properties
│       │       ├── application-dev.yaml
│       │       ├── application-doc.yaml
│       │       ├── application-mariadb.yaml
│       │       ├── application-mysql.yaml
│       │       ├── application-postgresql.yaml
│       │       ├── application-win.yaml
│       │       ├── application.yaml
│       │       ├── banner.txt
│       │       ├── config/
│       │       │   └── i18n/
│       │       │       ├── messages.properties
│       │       │       ├── messages_es.properties
│       │       │       └── messages_zh.properties
│       │       ├── db/
│       │       │   └── migration/
│       │       │       ├── h2/
│       │       │       │   └── .gitkeep
│       │       │       ├── mariadb/
│       │       │       │   └── .gitkeep
│       │       │       ├── mysql/
│       │       │       │   └── .gitkeep
│       │       │       └── postgresql/
│       │       │           └── .gitkeep
│       │       ├── extensions/
│       │       │   ├── attachment-local-policy.yaml
│       │       │   ├── authproviders.yaml
│       │       │   ├── extension-definitions.yaml
│       │       │   ├── extensionpoint-definitions.yaml
│       │       │   ├── notification-templates.yaml
│       │       │   ├── notification.yaml
│       │       │   ├── role-template-actuator.yaml
│       │       │   ├── role-template-anonymous.yaml
│       │       │   ├── role-template-attachment.yaml
│       │       │   ├── role-template-authenticated.yaml
│       │       │   ├── role-template-cache.yaml
│       │       │   ├── role-template-category.yaml
│       │       │   ├── role-template-comment.yaml
│       │       │   ├── role-template-configmap.yaml
│       │       │   ├── role-template-menu.yaml
│       │       │   ├── role-template-migration.yaml
│       │       │   ├── role-template-notification.yaml
│       │       │   ├── role-template-permissions.yaml
│       │       │   ├── role-template-plugin.yaml
│       │       │   ├── role-template-post.yaml
│       │       │   ├── role-template-role.yaml
│       │       │   ├── role-template-setting.yaml
│       │       │   ├── role-template-singlepage.yaml
│       │       │   ├── role-template-snapshot.yaml
│       │       │   ├── role-template-tag.yaml
│       │       │   ├── role-template-theme.yaml
│       │       │   ├── role-template-uc-attachment.yaml
│       │       │   ├── role-template-uc-content.yaml
│       │       │   ├── role-template-user.yaml
│       │       │   ├── system-configurable-configmap.yaml
│       │       │   ├── system-default-role.yaml
│       │       │   ├── system-setting.yaml
│       │       │   └── user.yaml
│       │       ├── initial-data.yaml
│       │       ├── schema-h2.sql
│       │       ├── schema-mariadb.sql
│       │       ├── schema-mysql.sql
│       │       ├── schema-postgresql.sql
│       │       ├── static/
│       │       │   ├── halo-tracker.js
│       │       │   ├── js/
│       │       │   │   └── main.js
│       │       │   └── styles/
│       │       │       └── main.css
│       │       ├── templates/
│       │       │   ├── challenges/
│       │       │   │   └── two-factor/
│       │       │   │       ├── totp.html
│       │       │   │       ├── totp.properties
│       │       │   │       ├── totp_en.properties
│       │       │   │       ├── totp_es.properties
│       │       │   │       └── totp_zh_TW.properties
│       │       │   ├── error/
│       │       │   │   └── error.html
│       │       │   ├── gateway_fragments/
│       │       │   │   ├── common.html
│       │       │   │   ├── common.properties
│       │       │   │   ├── common_en.properties
│       │       │   │   ├── common_es.properties
│       │       │   │   ├── common_zh_TW.properties
│       │       │   │   ├── input.html
│       │       │   │   ├── layout.html
│       │       │   │   ├── login.html
│       │       │   │   ├── login.properties
│       │       │   │   ├── login_en.properties
│       │       │   │   ├── login_es.properties
│       │       │   │   ├── login_zh_TW.properties
│       │       │   │   ├── logout.html
│       │       │   │   ├── logout.properties
│       │       │   │   ├── logout_en.properties
│       │       │   │   ├── logout_es.properties
│       │       │   │   ├── logout_zh_TW.properties
│       │       │   │   ├── password_reset_email_reset.html
│       │       │   │   ├── password_reset_email_reset.properties
│       │       │   │   ├── password_reset_email_reset_en.properties
│       │       │   │   ├── password_reset_email_reset_es.properties
│       │       │   │   ├── password_reset_email_reset_zh_TW.properties
│       │       │   │   ├── password_reset_email_send.html
│       │       │   │   ├── password_reset_email_send.properties
│       │       │   │   ├── password_reset_email_send_en.properties
│       │       │   │   ├── password_reset_email_send_es.properties
│       │       │   │   ├── password_reset_email_send_zh_TW.properties
│       │       │   │   ├── signup.html
│       │       │   │   ├── signup.properties
│       │       │   │   ├── signup_en.properties
│       │       │   │   ├── signup_es.properties
│       │       │   │   ├── signup_zh_TW.properties
│       │       │   │   ├── totp.html
│       │       │   │   ├── totp.properties
│       │       │   │   ├── totp_en.properties
│       │       │   │   ├── totp_es.properties
│       │       │   │   └── totp_zh_TW.properties
│       │       │   ├── login.html
│       │       │   ├── login.properties
│       │       │   ├── login_en.properties
│       │       │   ├── login_es.properties
│       │       │   ├── login_local.html
│       │       │   ├── login_local.properties
│       │       │   ├── login_local_en.properties
│       │       │   ├── login_local_es.properties
│       │       │   ├── login_local_zh_TW.properties
│       │       │   ├── login_zh_TW.properties
│       │       │   ├── logout.html
│       │       │   ├── logout.properties
│       │       │   ├── logout_en.properties
│       │       │   ├── logout_es.properties
│       │       │   ├── logout_zh_TW.properties
│       │       │   ├── password-reset/
│       │       │   │   └── email/
│       │       │   │       ├── reset.html
│       │       │   │       ├── reset.properties
│       │       │   │       ├── reset_en.properties
│       │       │   │       ├── reset_es.properties
│       │       │   │       ├── reset_zh_TW.properties
│       │       │   │       ├── send.html
│       │       │   │       ├── send.properties
│       │       │   │       ├── send_en.properties
│       │       │   │       ├── send_es.properties
│       │       │   │       └── send_zh_TW.properties
│       │       │   ├── setup.html
│       │       │   ├── setup.properties
│       │       │   ├── setup_en.properties
│       │       │   ├── setup_es.properties
│       │       │   ├── setup_zh_TW.properties
│       │       │   ├── signup.html
│       │       │   ├── signup.properties
│       │       │   ├── signup_en.properties
│       │       │   ├── signup_es.properties
│       │       │   └── signup_zh_TW.properties
│       │       └── thumbnailator.properties
│       └── test/
│           ├── java/
│           │   └── run/
│           │       └── halo/
│           │           └── app/
│           │               ├── ApplicationTests.java
│           │               ├── PathPrefixPredicateTest.java
│           │               ├── XForwardHeaderTest.java
│           │               ├── config/
│           │               │   ├── CorsTest.java
│           │               │   ├── ExtensionConfigurationTest.java
│           │               │   ├── HaloConfigurationTest.java
│           │               │   ├── SecurityConfigTest.java
│           │               │   ├── ServerCodecTest.java
│           │               │   └── WebFluxConfigTest.java
│           │               ├── content/
│           │               │   ├── CategoryPostCountUpdaterTest.java
│           │               │   ├── ContentRequestTest.java
│           │               │   ├── PostIntegrationTests.java
│           │               │   ├── TestPost.java
│           │               │   ├── comment/
│           │               │   │   ├── CommentEmailOwnerTest.java
│           │               │   │   ├── CommentNotificationReasonPublisherTest.java
│           │               │   │   ├── CommentRequestTest.java
│           │               │   │   ├── CommentServiceImplIntegrationTest.java
│           │               │   │   ├── CommentServiceImplTest.java
│           │               │   │   ├── PostCommentSubjectTest.java
│           │               │   │   ├── ReplyNotificationSubscriptionHelperTest.java
│           │               │   │   ├── ReplyServiceImplIntegrationTest.java
│           │               │   │   └── SinglePageCommentSubjectTest.java
│           │               │   └── permalinks/
│           │               │       ├── CategoryPermalinkPolicyTest.java
│           │               │       ├── PostPermalinkPolicyTest.java
│           │               │       └── TagPermalinkPolicyTest.java
│           │               ├── core/
│           │               │   ├── attachment/
│           │               │   │   ├── PolicyConfigChangeDetectorTest.java
│           │               │   │   ├── endpoint/
│           │               │   │   │   ├── LocalAttachmentUploadHandlerTest.java
│           │               │   │   │   └── PolicyEndpointTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   └── AttachmentRootGetterImplTest.java
│           │               │   │   └── thumbnail/
│           │               │   │       ├── DefaultLocalThumbnailServiceTest.java
│           │               │   │       ├── DefaultThumbnailServiceTest.java
│           │               │   │       ├── ThumbnailImgTagPostProcessorTest.java
│           │               │   │       ├── ThumbnailResourceTransformerTest.java
│           │               │   │       └── ThumbnailUtilsTest.java
│           │               │   ├── counter/
│           │               │   │   └── MeterUtilsTest.java
│           │               │   ├── endpoint/
│           │               │   │   ├── WebSocketHandlerMappingTest.java
│           │               │   │   ├── console/
│           │               │   │   │   ├── EmailVerificationCodeTest.java
│           │               │   │   │   ├── PluginEndpointTest.java
│           │               │   │   │   ├── PostEndpointTest.java
│           │               │   │   │   ├── SinglePageEndpointTest.java
│           │               │   │   │   ├── TagEndpointTest.java
│           │               │   │   │   ├── UserEndpointIntegrationTest.java
│           │               │   │   │   └── UserEndpointTest.java
│           │               │   │   ├── theme/
│           │               │   │   │   ├── CategoryQueryEndpointTest.java
│           │               │   │   │   ├── CommentFinderEndpointTest.java
│           │               │   │   │   ├── MenuQueryEndpointTest.java
│           │               │   │   │   ├── PluginQueryEndpointTest.java
│           │               │   │   │   ├── PostQueryEndpointTest.java
│           │               │   │   │   ├── PublicApiUtilsTest.java
│           │               │   │   │   ├── SinglePageQueryEndpointTest.java
│           │               │   │   │   └── ThumbnailEndpointTest.java
│           │               │   │   └── uc/
│           │               │   │       ├── AnnotationSettingEndpointTest.java
│           │               │   │       └── UcUserPreferenceEndpointTest.java
│           │               │   ├── extension/
│           │               │   │   ├── PostTest.java
│           │               │   │   ├── RoleBindingTest.java
│           │               │   │   ├── SettingTest.java
│           │               │   │   ├── TestRole.java
│           │               │   │   ├── ThemeTest.java
│           │               │   │   └── attachment/
│           │               │   │       └── endpoint/
│           │               │   │           └── AttachmentEndpointTest.java
│           │               │   ├── reconciler/
│           │               │   │   ├── CommentReconcilerTest.java
│           │               │   │   ├── MenuItemReconcilerTest.java
│           │               │   │   ├── PluginReconcilerTest.java
│           │               │   │   ├── PostReconcilerTest.java
│           │               │   │   ├── ReverseProxyReconcilerTest.java
│           │               │   │   ├── SinglePageReconcilerTest.java
│           │               │   │   ├── SystemConfigReconcilerTest.java
│           │               │   │   ├── TagReconcilerTest.java
│           │               │   │   ├── ThemeReconcilerTest.java
│           │               │   │   └── UserReconcilerTest.java
│           │               │   └── user/
│           │               │       └── service/
│           │               │           ├── DefaultRoleServiceTest.java
│           │               │           └── impl/
│           │               │               ├── EmailPasswordRecoveryServiceImplTest.java
│           │               │               ├── EmailVerificationServiceImplTest.java
│           │               │               └── UserServiceImplTest.java
│           │               ├── extension/
│           │               │   ├── AbstractExtensionTest.java
│           │               │   ├── ComparatorsTest.java
│           │               │   ├── ConfigMapTest.java
│           │               │   ├── DefaultSchemeManagerTest.java
│           │               │   ├── ExtensionOperatorTest.java
│           │               │   ├── ExtensionStoreUtilTest.java
│           │               │   ├── FakeExtension.java
│           │               │   ├── GroupVersionKindTest.java
│           │               │   ├── GroupVersionTest.java
│           │               │   ├── JsonExtensionConverterTest.java
│           │               │   ├── JsonExtensionTest.java
│           │               │   ├── ListResultTest.java
│           │               │   ├── MetadataOperatorTest.java
│           │               │   ├── ReactiveExtensionClientTest.java
│           │               │   ├── RefTest.java
│           │               │   ├── SchemeTest.java
│           │               │   ├── UnstructuredTest.java
│           │               │   ├── gc/
│           │               │   │   ├── GcReconcilerTest.java
│           │               │   │   ├── GcSynchronizerTest.java
│           │               │   │   └── GcWatcherTest.java
│           │               │   ├── index/
│           │               │   │   ├── DefaultIndexEngineTest.java
│           │               │   │   ├── DefaultIndicesManagerTest.java
│           │               │   │   ├── DefaultIndicesTest.java
│           │               │   │   ├── Fake.java
│           │               │   │   ├── LabelIndexTest.java
│           │               │   │   ├── MultiValueIndexTest.java
│           │               │   │   ├── SingleValueIndexTest.java
│           │               │   │   └── query/
│           │               │   │       └── QueryVisitorTest.java
│           │               │   ├── router/
│           │               │   │   ├── ExtensionCompositeRouterFunctionTest.java
│           │               │   │   ├── ExtensionCreateHandlerTest.java
│           │               │   │   ├── ExtensionDeleteHandlerTest.java
│           │               │   │   ├── ExtensionGetHandlerTest.java
│           │               │   │   ├── ExtensionListHandlerTest.java
│           │               │   │   ├── ExtensionRouterFunctionFactoryTest.java
│           │               │   │   ├── ExtensionUpdateHandlerTest.java
│           │               │   │   └── PathPatternGeneratorTest.java
│           │               │   └── store/
│           │               │       └── ReactiveExtensionStoreClientImplTest.java
│           │               ├── infra/
│           │               │   ├── ConditionListTest.java
│           │               │   ├── DefaultBackupRootGetterTest.java
│           │               │   ├── DefaultExternalLinkProcessorTest.java
│           │               │   ├── DefaultSystemConfigFetcherTest.java
│           │               │   ├── DefaultSystemVersionSupplierTest.java
│           │               │   ├── ExtensionResourceInitializerTest.java
│           │               │   ├── InitializationStateGetterTest.java
│           │               │   ├── ReactiveExtensionPaginatedOperatorImplTest.java
│           │               │   ├── SystemConfigFirstExternalUrlSupplierTest.java
│           │               │   ├── SystemSettingTest.java
│           │               │   ├── SystemStateTest.java
│           │               │   ├── ValidationUtilsTest.java
│           │               │   ├── config/
│           │               │   │   └── SessionConfigurationTest.java
│           │               │   ├── exception/
│           │               │   │   └── handlers/
│           │               │   │       └── I18nExceptionTest.java
│           │               │   ├── properties/
│           │               │   │   └── HaloPropertiesTest.java
│           │               │   └── utils/
│           │               │       ├── Base62UtilsTest.java
│           │               │       ├── FileNameUtilsTest.java
│           │               │       ├── FileTypeDetectUtilsTest.java
│           │               │       ├── FileUtilsTest.java
│           │               │       ├── HaloUtilsTest.java
│           │               │       ├── IpAddressUtilsTest.java
│           │               │       ├── SettingUtilsTest.java
│           │               │       ├── SortUtilsTest.java
│           │               │       ├── SystemConfigUtilsTest.java
│           │               │       ├── VersionUtilsTest.java
│           │               │       └── YamlUnstructuredLoaderTest.java
│           │               ├── migration/
│           │               │   ├── BackupReconcilerTest.java
│           │               │   └── impl/
│           │               │       └── MigrationServiceImplTest.java
│           │               ├── notification/
│           │               │   ├── DefaultNotificationCenterTest.java
│           │               │   ├── DefaultNotificationReasonEmitterTest.java
│           │               │   ├── DefaultNotificationSenderTest.java
│           │               │   ├── DefaultNotificationTemplateRenderTest.java
│           │               │   ├── DefaultNotifierConfigStoreTest.java
│           │               │   ├── DefaultSubscriberEmailResolverTest.java
│           │               │   ├── LanguageUtilsTest.java
│           │               │   ├── NotificationContextTest.java
│           │               │   ├── NotificationTriggerTest.java
│           │               │   ├── ReasonNotificationTemplateSelectorImplTest.java
│           │               │   ├── ReasonPayloadTest.java
│           │               │   ├── RecipientResolverImplTest.java
│           │               │   ├── SubscriptionServiceImplTest.java
│           │               │   ├── UserIdentityTest.java
│           │               │   ├── UserNotificationPreferenceServiceImplTest.java
│           │               │   ├── UserNotificationPreferenceTest.java
│           │               │   └── endpoint/
│           │               │       ├── SubscriptionRouterTest.java
│           │               │       └── UserNotificationPreferencesEndpointTest.java
│           │               ├── plugin/
│           │               │   ├── BuiltInPluginsInitializerTest.java
│           │               │   ├── DefaultDevelopmentPluginRepositoryTest.java
│           │               │   ├── DefaultPluginApplicationContextFactoryTest.java
│           │               │   ├── DefaultPluginRouterFunctionRegistryTest.java
│           │               │   ├── DefaultSettingFetcherTest.java
│           │               │   ├── HaloPluginManagerTest.java
│           │               │   ├── OptionalDependentResolverTest.java
│           │               │   ├── PluginExtensionLoaderUtilsTest.java
│           │               │   ├── PluginRequestMappingHandlerMappingTest.java
│           │               │   ├── PluginServiceImplTest.java
│           │               │   ├── PluginsRootGetterImplTest.java
│           │               │   ├── SharedApplicationContextFactoryTest.java
│           │               │   ├── SharedEventDispatcherTest.java
│           │               │   ├── SpringComponentsFinderTest.java
│           │               │   ├── YamlPluginDescriptorFinderTest.java
│           │               │   ├── YamlPluginFinderTest.java
│           │               │   ├── extensionpoint/
│           │               │   │   └── DefaultExtensionGetterTest.java
│           │               │   └── resources/
│           │               │       ├── BundleResourceUtilsTest.java
│           │               │       ├── ReverseProxyRouterFunctionFactoryTest.java
│           │               │       └── ReverseProxyRouterFunctionRegistryTest.java
│           │               ├── search/
│           │               │   ├── HaloDocumentEventsListenerTest.java
│           │               │   ├── IndexEndpointTest.java
│           │               │   ├── IndicesEndpointTest.java
│           │               │   ├── SearchServiceImplTest.java
│           │               │   ├── lucene/
│           │               │   │   ├── LuceneSearchEngineIntegrationTest.java
│           │               │   │   └── LuceneSearchEngineTest.java
│           │               │   └── post/
│           │               │       ├── PostEventsListenerTest.java
│           │               │       └── PostHaloDocumentsProviderTest.java
│           │               ├── security/
│           │               │   ├── AuthProviderServiceImplTest.java
│           │               │   ├── CsrfSecurityTest.java
│           │               │   ├── DefaultServerAuthenticationEntryPointTest.java
│           │               │   ├── DefaultSuperAdminInitializerTest.java
│           │               │   ├── DefaultUserDetailServiceTest.java
│           │               │   ├── HaloServerRequestCacheTest.java
│           │               │   ├── InitializeRedirectionWebFilterTest.java
│           │               │   ├── ResponseMap.java
│           │               │   ├── authentication/
│           │               │   │   ├── WebExchangeMatchersTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   └── RsaKeyServiceTest.java
│           │               │   │   ├── login/
│           │               │   │   │   ├── LoginAuthenticationConverterTest.java
│           │               │   │   │   └── PublicKeyRouteBuilderTest.java
│           │               │   │   ├── pat/
│           │               │   │   │   └── PatTest.java
│           │               │   │   ├── rememberme/
│           │               │   │   │   ├── PersistentTokenBasedRememberMeServicesTest.java
│           │               │   │   │   ├── RememberTokenCleanerTest.java
│           │               │   │   │   └── TokenBasedRememberMeServicesTest.java
│           │               │   │   └── twofactor/
│           │               │   │       └── TwoFactorAuthSettingsTest.java
│           │               │   ├── authorization/
│           │               │   │   ├── AuthorityUtilsTest.java
│           │               │   │   ├── AuthorizationTest.java
│           │               │   │   ├── DefaultRuleResolverTest.java
│           │               │   │   ├── PolicyRuleTest.java
│           │               │   │   ├── RbacRequestEvaluationTest.java
│           │               │   │   └── RequestInfoResolverTest.java
│           │               │   ├── device/
│           │               │   │   └── DeviceServiceImplTest.java
│           │               │   ├── jackson2/
│           │               │   │   └── HaloSecurityJacksonModuleTest.java
│           │               │   ├── preauth/
│           │               │   │   └── SystemSetupEndpointTest.java
│           │               │   ├── session/
│           │               │   │   └── InMemoryReactiveIndexedSessionRepositoryTest.java
│           │               │   └── switchuser/
│           │               │       ├── SwitchUserConfigurerTest.java
│           │               │       ├── SwitchUserSecurityContextFactory.java
│           │               │       └── WithSwitchUser.java
│           │               ├── theme/
│           │               │   ├── CompositeTemplateResolverTest.java
│           │               │   ├── ReactiveFinderExpressionParserTests.java
│           │               │   ├── SiteSettingVariablesAcquirerTest.java
│           │               │   ├── ThemeContextTest.java
│           │               │   ├── ThemeIntegrationTest.java
│           │               │   ├── ThemeLinkBuilderTest.java
│           │               │   ├── ThemeLocaleContextResolverTest.java
│           │               │   ├── ViewNameResolverTest.java
│           │               │   ├── dialect/
│           │               │   │   ├── CommentElementTagProcessorTest.java
│           │               │   │   ├── CommentEnabledVariableProcessorTest.java
│           │               │   │   ├── ContentTemplateHeadProcessorIntegrationTest.java
│           │               │   │   ├── ContentTemplateHeadProcessorTest.java
│           │               │   │   ├── DuplicateMetaTagProcessorTest.java
│           │               │   │   ├── GeneratorMetaProcessorTest.java
│           │               │   │   ├── HaloPostTemplateHandlerTest.java
│           │               │   │   ├── HaloProcessorDialectTest.java
│           │               │   │   ├── HaloSpringSecurityDialectTest.java
│           │               │   │   ├── InjectionExcluderProcessorTest.java
│           │               │   │   ├── LinkExpressionObjectDialectTest.java
│           │               │   │   └── TemplateFooterElementTagProcessorTest.java
│           │               │   ├── endpoint/
│           │               │   │   └── ThemeEndpointTest.java
│           │               │   ├── engine/
│           │               │   │   ├── DefaultThemeTemplateAvailabilityProviderTest.java
│           │               │   │   └── PluginClassloaderTemplateResolverTest.java
│           │               │   ├── finders/
│           │               │   │   ├── FinderRegistryTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   ├── CategoryFinderImplTest.java
│           │               │   │   │   ├── CommentPublicQueryServiceImplTest.java
│           │               │   │   │   ├── CommentPublicQueryServiceIntegrationTest.java
│           │               │   │   │   ├── MenuFinderImplTest.java
│           │               │   │   │   ├── PluginFinderImplTest.java
│           │               │   │   │   ├── PostFinderImplIntegrationTest.java
│           │               │   │   │   ├── PostFinderImplTest.java
│           │               │   │   │   ├── PostPublicQueryServiceImplTest.java
│           │               │   │   │   ├── SinglePageConversionServiceImplTest.java
│           │               │   │   │   ├── SinglePageFinderImplTest.java
│           │               │   │   │   ├── TagFinderImplTest.java
│           │               │   │   │   └── ThumbnailFinderImplTest.java
│           │               │   │   └── vo/
│           │               │   │       └── UserVoTest.java
│           │               │   ├── message/
│           │               │   │   ├── ThemeMessageResolutionUtilsTest.java
│           │               │   │   └── ThemeMessageResolverIntegrationTest.java
│           │               │   ├── router/
│           │               │   │   ├── EmptyView.java
│           │               │   │   ├── PageUrlUtilsTest.java
│           │               │   │   ├── PreviewRouterFunctionTest.java
│           │               │   │   ├── ReactiveQueryPostPredicateResolverTest.java
│           │               │   │   ├── SinglePageRouteTest.java
│           │               │   │   └── factories/
│           │               │   │       ├── ArchiveRouteFactoryTest.java
│           │               │   │       ├── AuthorPostsRouteFactoryTest.java
│           │               │   │       ├── CategoriesRouteFactoryTest.java
│           │               │   │       ├── IndexRouteFactoryTest.java
│           │               │   │       ├── PostRouteFactoryTest.java
│           │               │   │       ├── RouteFactoryTest.java
│           │               │   │       ├── RouteFactoryTestSuite.java
│           │               │   │       └── TagPostRouteFactoryTest.java
│           │               │   ├── service/
│           │               │   │   └── ThemeServiceImplTest.java
│           │               │   └── utils/
│           │               │       └── PatternUtilsTest.java
│           │               ├── ui/
│           │               │   ├── WebSocketServerWebExchangeMatcherTest.java
│           │               │   └── WebSocketUtilsTest.java
│           │               └── webfilter/
│           │                   └── LocaleChangeWebFilterTest.java
│           └── resources/
│               ├── apiToken.salt
│               ├── app.key
│               ├── app.pub
│               ├── application.yaml
│               ├── backups/
│               │   └── backup-for-restoration/
│               │       ├── extensions.data
│               │       └── workdir/
│               │           └── fake-file
│               ├── categories/
│               │   └── independent-post-count.json
│               ├── config/
│               │   └── i18n/
│               │       ├── messages.properties
│               │       └── messages_zh.properties
│               ├── console/
│               │   ├── assets/
│               │   │   └── fake.txt
│               │   └── index.html
│               ├── file-type-detect/
│               │   ├── index.html
│               │   ├── index.js
│               │   ├── other.xlsx
│               │   ├── test.docx
│               │   └── test.json
│               ├── folder-to-zip/
│               │   └── examplefile
│               ├── plugin/
│               │   ├── plugin-0.0.1/
│               │   │   ├── extensions/
│               │   │   │   ├── reverseProxy.yaml
│               │   │   │   ├── roles.yaml
│               │   │   │   ├── setting.yaml
│               │   │   │   └── test.yml
│               │   │   └── plugin.yaml
│               │   ├── plugin-0.0.2/
│               │   │   └── plugin.yaml
│               │   ├── plugin-for-finder/
│               │   │   └── META-INF/
│               │   │       └── plugin-components.idx
│               │   ├── plugin-for-reverseproxy/
│               │   │   └── static/
│               │   │       └── test.txt
│               │   └── plugin.yaml
│               ├── presets/
│               │   └── plugins/
│               │       └── fake-plugin.jar
│               ├── themes/
│               │   ├── default/
│               │   │   ├── i18n/
│               │   │   │   ├── default.properties
│               │   │   │   ├── en.properties
│               │   │   │   └── zh.properties
│               │   │   ├── templates/
│               │   │   │   ├── index.html
│               │   │   │   ├── index.properties
│               │   │   │   ├── index_zh.properties
│               │   │   │   └── timezone.html
│               │   │   └── theme.yaml
│               │   ├── invalid-missing-manifest/
│               │   │   ├── i18n/
│               │   │   │   ├── default.properties
│               │   │   │   └── en.properties
│               │   │   └── templates/
│               │   │       ├── index.html
│               │   │       └── timezone.html
│               │   └── other/
│               │       ├── i18n/
│               │       │   ├── default.properties
│               │       │   └── en.properties
│               │       ├── templates/
│               │       │   └── index.html
│               │       └── theme.yaml
│               └── ui/
│                   ├── console.html
│                   ├── uc.html
│                   └── ui-assets/
│                       └── fake.txt
├── buildSrc/
│   ├── build.gradle
│   └── src/
│       └── main/
│           └── groovy/
│               ├── UploadBundleTask.groovy
│               └── halo.publish.gradle
├── config/
│   └── checkstyle/
│       └── checkstyle.xml
├── docs/
│   ├── authentication/
│   │   └── README.md
│   ├── backup-and-restore.md
│   ├── cache/
│   │   └── page.md
│   ├── developer-guide/
│   │   ├── custom-endpoint.md
│   │   └── plugin-configuration-properties.md
│   ├── email-verification/
│   │   └── README.md
│   ├── extension-points/
│   │   ├── authentication.md
│   │   ├── content.md
│   │   └── search-engine.md
│   ├── full-text-search/
│   │   └── README.md
│   ├── index/
│   │   └── README.md
│   ├── notification/
│   │   └── README.md
│   └── plugin/
│       ├── shared-event.md
│       └── websocket.md
├── e2e/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── compose-mysql.yaml
│   ├── compose-postgres.yaml
│   ├── compose.yaml
│   ├── start.sh
│   └── testsuite.yaml
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── hack/
│   └── cherry_pick_pull.sh
├── platform/
│   ├── application/
│   │   └── build.gradle
│   └── plugin/
│       └── build.gradle
├── settings.gradle
└── ui/
    ├── .editorconfig
    ├── .husky/
    │   └── pre-commit
    ├── .npmrc
    ├── .oxfmtrc.json
    ├── Makefile
    ├── build.gradle
    ├── console-src/
    │   ├── App.vue
    │   ├── components/
    │   │   └── snapshots/
    │   │       ├── BaseSnapshots.vue
    │   │       ├── SnapshotContent.vue
    │   │       ├── SnapshotDiffContent.vue
    │   │       ├── SnapshotListItem.vue
    │   │       └── query-keys.ts
    │   ├── composables/
    │   │   ├── use-content-snapshot.ts
    │   │   ├── use-dashboard-stats.ts
    │   │   ├── use-entity-extension-points.ts
    │   │   ├── use-operation-extension-points.ts
    │   │   ├── use-save-keybinding.ts
    │   │   └── use-slugify.ts
    │   ├── layouts/
    │   │   ├── BasicLayout.vue
    │   │   └── BlankLayout.vue
    │   ├── main.ts
    │   ├── modules/
    │   │   ├── contents/
    │   │   │   ├── attachments/
    │   │   │   │   ├── AttachmentList.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── AttachmentDetailModal.vue
    │   │   │   │   │   ├── AttachmentError.vue
    │   │   │   │   │   ├── AttachmentGroupBadge.vue
    │   │   │   │   │   ├── AttachmentGroupEditingModal.vue
    │   │   │   │   │   ├── AttachmentGroupList.vue
    │   │   │   │   │   ├── AttachmentListItem.vue
    │   │   │   │   │   ├── AttachmentLoading.vue
    │   │   │   │   │   ├── AttachmentPoliciesListItem.vue
    │   │   │   │   │   ├── AttachmentPoliciesModal.vue
    │   │   │   │   │   ├── AttachmentPolicyBadge.vue
    │   │   │   │   │   ├── AttachmentPolicyEditingModal.vue
    │   │   │   │   │   ├── AttachmentSelectorModal.vue
    │   │   │   │   │   ├── AttachmentUploadArea.vue
    │   │   │   │   │   ├── AttachmentUploadModal.vue
    │   │   │   │   │   ├── DisplayNameEditForm.vue
    │   │   │   │   │   ├── UploadFromUrl.vue
    │   │   │   │   │   └── selector-providers/
    │   │   │   │   │       ├── CoreSelectorProvider.vue
    │   │   │   │   │       └── components/
    │   │   │   │   │           ├── AttachmentSelectorListItem.vue
    │   │   │   │   │           ├── GroupFilter.vue
    │   │   │   │   │           └── PolicyFilter.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   ├── use-attachment-group.ts
    │   │   │   │   │   ├── use-attachment-policy.ts
    │   │   │   │   │   └── use-attachment.ts
    │   │   │   │   └── module.ts
    │   │   │   ├── comments/
    │   │   │   │   ├── CommentList.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── CommentDetailModal.vue
    │   │   │   │   │   ├── CommentEditor.vue
    │   │   │   │   │   ├── CommentListItem.vue
    │   │   │   │   │   ├── DefaultCommentContent.vue
    │   │   │   │   │   ├── DefaultCommentEditor.vue
    │   │   │   │   │   ├── OwnerButton.vue
    │   │   │   │   │   ├── ReplyCreationModal.vue
    │   │   │   │   │   ├── ReplyDetailModal.vue
    │   │   │   │   │   ├── ReplyListItem.vue
    │   │   │   │   │   ├── SubjectQueryCommentList.vue
    │   │   │   │   │   └── SubjectQueryCommentListModal.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   ├── use-comment-last-readtime-mutate.ts
    │   │   │   │   │   ├── use-comments-fetch.ts
    │   │   │   │   │   ├── use-content-provider-extension-point.ts
    │   │   │   │   │   └── use-subject-ref.ts
    │   │   │   │   └── module.ts
    │   │   │   ├── pages/
    │   │   │   │   ├── DeletedSinglePageList.vue
    │   │   │   │   ├── SinglePageEditor.vue
    │   │   │   │   ├── SinglePageList.vue
    │   │   │   │   ├── SinglePageSnapshots.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── SinglePageListItem.vue
    │   │   │   │   │   ├── SinglePageSettingModal.vue
    │   │   │   │   │   └── entity-fields/
    │   │   │   │   │       ├── ContributorsField.vue
    │   │   │   │   │       ├── CoverField.vue
    │   │   │   │   │       ├── PublishStatusField.vue
    │   │   │   │   │       ├── PublishTimeField.vue
    │   │   │   │   │       ├── TitleField.vue
    │   │   │   │   │       └── VisibleField.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   └── use-page-update-mutate.ts
    │   │   │   │   └── module.ts
    │   │   │   └── posts/
    │   │   │       ├── DeletedPostList.vue
    │   │   │       ├── PostEditor.vue
    │   │   │       ├── PostList.vue
    │   │   │       ├── PostSnapshots.vue
    │   │   │       ├── categories/
    │   │   │       │   ├── CategoryList.vue
    │   │   │       │   ├── components/
    │   │   │       │   │   ├── CategoryEditingModal.vue
    │   │   │       │   │   ├── CategoryListItem.vue
    │   │   │       │   │   └── __tests__/
    │   │   │       │   │       └── CategoryEditingModal.spec.ts
    │   │   │       │   ├── composables/
    │   │   │       │   │   └── use-post-category.ts
    │   │   │       │   └── utils/
    │   │   │       │       ├── __tests__/
    │   │   │       │       │   └── index.spec.ts
    │   │   │       │       └── index.ts
    │   │   │       ├── components/
    │   │   │       │   ├── PostBatchSettingModal.vue
    │   │   │       │   ├── PostListItem.vue
    │   │   │       │   ├── PostSettingModal.vue
    │   │   │       │   ├── __tests__/
    │   │   │       │   │   └── PostSettingModal.spec.ts
    │   │   │       │   └── entity-fields/
    │   │   │       │       ├── ContributorsField.vue
    │   │   │       │       ├── CoverField.vue
    │   │   │       │       ├── PublishStatusField.vue
    │   │   │       │       ├── PublishTimeField.vue
    │   │   │       │       ├── TitleField.vue
    │   │   │       │       └── VisibleField.vue
    │   │   │       ├── composables/
    │   │   │       │   └── use-post-update-mutate.ts
    │   │   │       ├── module.ts
    │   │   │       └── tags/
    │   │   │           ├── TagList.vue
    │   │   │           ├── components/
    │   │   │           │   ├── PostTag.vue
    │   │   │           │   ├── TagEditingModal.vue
    │   │   │           │   └── TagListItem.vue
    │   │   │           └── composables/
    │   │   │               └── use-post-tag.ts
    │   │   ├── dashboard/
    │   │   │   ├── Dashboard.vue
    │   │   │   ├── DashboardDesigner.vue
    │   │   │   ├── components/
    │   │   │   │   ├── ActionButton.vue
    │   │   │   │   ├── WidgetCard.vue
    │   │   │   │   ├── WidgetConfigFormModal.vue
    │   │   │   │   ├── WidgetEditableItem.vue
    │   │   │   │   ├── WidgetHubModal.vue
    │   │   │   │   └── WidgetViewItem.vue
    │   │   │   ├── composables/
    │   │   │   │   ├── use-dashboard-extension-point.ts
    │   │   │   │   └── use-dashboard-widgets-fetch.ts
    │   │   │   ├── module.ts
    │   │   │   ├── styles/
    │   │   │   │   └── dashboard.css
    │   │   │   └── widgets/
    │   │   │       ├── defaults.ts
    │   │   │       ├── index.ts
    │   │   │       └── presets/
    │   │   │           ├── comments/
    │   │   │           │   ├── CommentItem.vue
    │   │   │           │   ├── CommentStatsWidget.vue
    │   │   │           │   └── PendingCommentsWidget.vue
    │   │   │           ├── core/
    │   │   │           │   ├── iframe/
    │   │   │           │   │   └── IframeWidget.vue
    │   │   │           │   ├── quick-action/
    │   │   │           │   │   ├── QuickActionItem.vue
    │   │   │           │   │   ├── QuickActionWidget.vue
    │   │   │           │   │   ├── ThemePreviewItem.vue
    │   │   │           │   │   └── composables/
    │   │   │           │   │       └── use-dashboard-extension-point.ts
    │   │   │           │   ├── stack/
    │   │   │           │   │   ├── StackWidget.vue
    │   │   │           │   │   ├── StackWidgetConfigModal.vue
    │   │   │           │   │   ├── components/
    │   │   │           │   │   │   ├── IndexIndicator.vue
    │   │   │           │   │   │   ├── WidgetEditableItem.vue
    │   │   │           │   │   │   └── WidgetViewItem.vue
    │   │   │           │   │   └── types.ts
    │   │   │           │   ├── upvotes-stats/
    │   │   │           │   │   └── UpvotesStatsWidget.vue
    │   │   │           │   └── view-stats/
    │   │   │           │       └── ViewsStatsWidget.vue
    │   │   │           ├── posts/
    │   │   │           │   ├── PostStatsWidget.vue
    │   │   │           │   ├── RecentPublishedWidget.vue
    │   │   │           │   └── components/
    │   │   │           │       └── PostListItem.vue
    │   │   │           ├── single-pages/
    │   │   │           │   └── SinglePageStatsWidget.vue
    │   │   │           └── users/
    │   │   │               ├── NotificationWidget.vue
    │   │   │               └── UserStatsWidget.vue
    │   │   ├── index.ts
    │   │   ├── interface/
    │   │   │   ├── menus/
    │   │   │   │   ├── Menus.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── MenuEditingModal.vue
    │   │   │   │   │   ├── MenuItemEditingModal.vue
    │   │   │   │   │   └── MenuList.vue
    │   │   │   │   ├── module.ts
    │   │   │   │   └── utils/
    │   │   │   │       ├── __tests__/
    │   │   │   │       │   ├── __snapshots__/
    │   │   │   │       │   │   └── index.spec.ts.snap
    │   │   │   │       │   └── index.spec.ts
    │   │   │   │       └── index.ts
    │   │   │   └── themes/
    │   │   │       ├── ThemeDetail.vue
    │   │   │       ├── ThemeSetting.vue
    │   │   │       ├── components/
    │   │   │       │   ├── ThemeListItem.vue
    │   │   │       │   ├── ThemeListModal.vue
    │   │   │       │   ├── list-tabs/
    │   │   │       │   │   ├── InstalledThemes.vue
    │   │   │       │   │   ├── LocalUpload.vue
    │   │   │       │   │   ├── NotInstalledThemes.vue
    │   │   │       │   │   └── RemoteDownload.vue
    │   │   │       │   ├── operation/
    │   │   │       │   │   ├── MoreOperationItem.vue
    │   │   │       │   │   └── UninstallOperationItem.vue
    │   │   │       │   └── preview/
    │   │   │       │       ├── ThemePreviewListItem.vue
    │   │   │       │       └── ThemePreviewModal.vue
    │   │   │       ├── composables/
    │   │   │       │   └── use-theme.ts
    │   │   │       ├── constants/
    │   │   │       │   └── index.ts
    │   │   │       ├── layouts/
    │   │   │       │   └── ThemeLayout.vue
    │   │   │       ├── module.ts
    │   │   │       └── types/
    │   │   │           └── index.ts
    │   │   └── system/
    │   │       ├── auth-providers/
    │   │       │   ├── AuthProviderDetail.vue
    │   │       │   ├── AuthProviders.vue
    │   │       │   ├── components/
    │   │       │   │   ├── AuthProviderListItem.vue
    │   │       │   │   └── AuthProvidersSection.vue
    │   │       │   └── module.ts
    │   │       ├── backup/
    │   │       │   ├── Backups.vue
    │   │       │   ├── components/
    │   │       │   │   └── BackupListItem.vue
    │   │       │   ├── composables/
    │   │       │   │   └── use-backup.ts
    │   │       │   ├── module.ts
    │   │       │   └── tabs/
    │   │       │       ├── List.vue
    │   │       │       └── Restore.vue
    │   │       ├── overview/
    │   │       │   ├── Overview.vue
    │   │       │   ├── components/
    │   │       │   │   ├── ExternalUrlForm.vue
    │   │       │   │   └── ExternalUrlItem.vue
    │   │       │   └── module.ts
    │   │       ├── plugins/
    │   │       │   ├── PluginDetail.vue
    │   │       │   ├── PluginExtensionPointSettings.vue
    │   │       │   ├── PluginList.vue
    │   │       │   ├── components/
    │   │       │   │   ├── PluginConditionsModal.vue
    │   │       │   │   ├── PluginDetailModal.vue
    │   │       │   │   ├── PluginInstallationModal.vue
    │   │       │   │   ├── PluginListItem.vue
    │   │       │   │   ├── entity-fields/
    │   │       │   │   │   ├── AuthorField.vue
    │   │       │   │   │   ├── LogoField.vue
    │   │       │   │   │   ├── ReloadField.vue
    │   │       │   │   │   ├── SwitchField.vue
    │   │       │   │   │   └── TitleField.vue
    │   │       │   │   ├── extension-points/
    │   │       │   │   │   ├── ExtensionDefinitionListItem.vue
    │   │       │   │   │   ├── ExtensionDefinitionMultiInstanceView.vue
    │   │       │   │   │   └── ExtensionDefinitionSingletonView.vue
    │   │       │   │   ├── installation-tabs/
    │   │       │   │   │   ├── LocalUpload.vue
    │   │       │   │   │   └── RemoteDownload.vue
    │   │       │   │   └── tabs/
    │   │       │   │       ├── Detail.vue
    │   │       │   │       └── Setting.vue
    │   │       │   ├── composables/
    │   │       │   │   ├── use-extension-definition-fetch.ts
    │   │       │   │   └── use-plugin.ts
    │   │       │   ├── constants/
    │   │       │   │   └── index.ts
    │   │       │   ├── module.ts
    │   │       │   └── types/
    │   │       │       └── index.ts
    │   │       ├── roles/
    │   │       │   ├── RoleDetail.vue
    │   │       │   ├── RoleList.vue
    │   │       │   ├── components/
    │   │       │   │   └── RoleEditingModal.vue
    │   │       │   └── module.ts
    │   │       ├── settings/
    │   │       │   ├── SystemSettings.vue
    │   │       │   ├── module.ts
    │   │       │   └── tabs/
    │   │       │       ├── NotificationSetting.vue
    │   │       │       ├── Notifications.vue
    │   │       │       └── Setting.vue
    │   │       ├── tools/
    │   │       │   ├── Tools.vue
    │   │       │   └── module.ts
    │   │       └── users/
    │   │           ├── UserDetail.vue
    │   │           ├── UserList.vue
    │   │           ├── components/
    │   │           │   ├── GrantPermissionModal.vue
    │   │           │   ├── RolesView.vue
    │   │           │   ├── UserCreationModal.vue
    │   │           │   ├── UserEditingModal.vue
    │   │           │   ├── UserListItem.vue
    │   │           │   └── UserPasswordChangeModal.vue
    │   │           ├── composables/
    │   │           │   ├── use-role.ts
    │   │           │   └── use-user.ts
    │   │           ├── module.ts
    │   │           └── tabs/
    │   │               └── Detail.vue
    │   ├── router/
    │   │   ├── constant.ts
    │   │   ├── guards/
    │   │   │   ├── auth-check.ts
    │   │   │   └── permission.ts
    │   │   ├── index.ts
    │   │   └── routes.config.ts
    │   └── stores/
    │       └── theme.ts
    ├── console.html
    ├── docs/
    │   ├── components/
    │   │   └── README.md
    │   ├── custom-formkit-input/
    │   │   └── README.md
    │   ├── extension-points/
    │   │   ├── backup.md
    │   │   ├── comment-content.md
    │   │   ├── comment-editor.md
    │   │   ├── comment-subject-ref.md
    │   │   ├── dashboard.md
    │   │   ├── default-editor–extension.md
    │   │   ├── editor.md
    │   │   ├── entity-listitem-field.md
    │   │   ├── entity-listitem-operation.md
    │   │   ├── plugin-installation-tabs.md
    │   │   ├── plugin-self-tabs.md
    │   │   └── theme-list-tabs.md
    │   ├── project-structure/
    │   │   └── README.md
    │   └── routes-generation/
    │       └── README.md
    ├── env.d.ts
    ├── eslint.config.ts
    ├── package.json
    ├── packages/
    │   ├── api-client/
    │   │   ├── .openapi_config.yaml
    │   │   ├── README.md
    │   │   ├── entry/
    │   │   │   ├── api-client.ts
    │   │   │   ├── index.ts
    │   │   │   └── utils/
    │   │   │       ├── index.ts
    │   │   │       └── paginate.ts
    │   │   ├── openapitools.json
    │   │   ├── package.json
    │   │   ├── src/
    │   │   │   ├── .gitignore
    │   │   │   ├── .npmignore
    │   │   │   ├── .openapi-generator/
    │   │   │   │   ├── FILES
    │   │   │   │   └── VERSION
    │   │   │   ├── .openapi-generator-ignore
    │   │   │   ├── api/
    │   │   │   │   ├── annotation-setting-v1-alpha-uc-api.ts
    │   │   │   │   ├── annotation-setting-v1alpha1-api.ts
    │   │   │   │   ├── attachment-v1alpha1-api.ts
    │   │   │   │   ├── attachment-v1alpha1-console-api.ts
    │   │   │   │   ├── attachment-v1alpha1-uc-api.ts
    │   │   │   │   ├── auth-provider-v1alpha1-api.ts
    │   │   │   │   ├── auth-provider-v1alpha1-console-api.ts
    │   │   │   │   ├── backup-v1alpha1-api.ts
    │   │   │   │   ├── category-v1alpha1-api.ts
    │   │   │   │   ├── category-v1alpha1-public-api.ts
    │   │   │   │   ├── comment-v1alpha1-api.ts
    │   │   │   │   ├── comment-v1alpha1-console-api.ts
    │   │   │   │   ├── comment-v1alpha1-public-api.ts
    │   │   │   │   ├── config-map-v1alpha1-api.ts
    │   │   │   │   ├── counter-v1alpha1-api.ts
    │   │   │   │   ├── device-v1alpha1-api.ts
    │   │   │   │   ├── device-v1alpha1-uc-api.ts
    │   │   │   │   ├── extension-definition-v1alpha1-api.ts
    │   │   │   │   ├── extension-point-definition-v1alpha1-api.ts
    │   │   │   │   ├── group-v1alpha1-api.ts
    │   │   │   │   ├── index-v1alpha1-public-api.ts
    │   │   │   │   ├── indices-v1alpha1-console-api.ts
    │   │   │   │   ├── local-thumbnail-v1alpha1-api.ts
    │   │   │   │   ├── menu-item-v1alpha1-api.ts
    │   │   │   │   ├── menu-v1alpha1-api.ts
    │   │   │   │   ├── menu-v1alpha1-public-api.ts
    │   │   │   │   ├── metrics-v1alpha1-public-api.ts
    │   │   │   │   ├── migration-v1alpha1-console-api.ts
    │   │   │   │   ├── notification-template-v1alpha1-api.ts
    │   │   │   │   ├── notification-v1alpha1-api.ts
    │   │   │   │   ├── notification-v1alpha1-public-api.ts
    │   │   │   │   ├── notification-v1alpha1-uc-api.ts
    │   │   │   │   ├── notifier-descriptor-v1alpha1-api.ts
    │   │   │   │   ├── notifier-v1alpha1-console-api.ts
    │   │   │   │   ├── notifier-v1alpha1-uc-api.ts
    │   │   │   │   ├── personal-access-token-v1alpha1-api.ts
    │   │   │   │   ├── personal-access-token-v1alpha1-uc-api.ts
    │   │   │   │   ├── plugin-v1alpha1-api.ts
    │   │   │   │   ├── plugin-v1alpha1-console-api.ts
    │   │   │   │   ├── plugin-v1alpha1-public-api.ts
    │   │   │   │   ├── policy-alpha1-console-api.ts
    │   │   │   │   ├── policy-template-v1alpha1-api.ts
    │   │   │   │   ├── policy-v1alpha1-api.ts
    │   │   │   │   ├── post-v1alpha1-api.ts
    │   │   │   │   ├── post-v1alpha1-console-api.ts
    │   │   │   │   ├── post-v1alpha1-public-api.ts
    │   │   │   │   ├── post-v1alpha1-uc-api.ts
    │   │   │   │   ├── reason-type-v1alpha1-api.ts
    │   │   │   │   ├── reason-v1alpha1-api.ts
    │   │   │   │   ├── remember-me-token-v1alpha1-api.ts
    │   │   │   │   ├── reply-v1alpha1-api.ts
    │   │   │   │   ├── reply-v1alpha1-console-api.ts
    │   │   │   │   ├── reverse-proxy-v1alpha1-api.ts
    │   │   │   │   ├── role-binding-v1alpha1-api.ts
    │   │   │   │   ├── role-v1alpha1-api.ts
    │   │   │   │   ├── secret-v1alpha1-api.ts
    │   │   │   │   ├── setting-v1alpha1-api.ts
    │   │   │   │   ├── single-page-v1alpha1-api.ts
    │   │   │   │   ├── single-page-v1alpha1-console-api.ts
    │   │   │   │   ├── single-page-v1alpha1-public-api.ts
    │   │   │   │   ├── snapshot-v1alpha1-api.ts
    │   │   │   │   ├── snapshot-v1alpha1-uc-api.ts
    │   │   │   │   ├── subscription-v1alpha1-api.ts
    │   │   │   │   ├── system-config-v1alpha1-console-api.ts
    │   │   │   │   ├── system-v1alpha1-console-api.ts
    │   │   │   │   ├── system-v1alpha1-public-api.ts
    │   │   │   │   ├── tag-v1alpha1-api.ts
    │   │   │   │   ├── tag-v1alpha1-console-api.ts
    │   │   │   │   ├── tag-v1alpha1-public-api.ts
    │   │   │   │   ├── theme-v1alpha1-api.ts
    │   │   │   │   ├── theme-v1alpha1-console-api.ts
    │   │   │   │   ├── thumbnail-v1alpha1-api.ts
    │   │   │   │   ├── thumbnail-v1alpha1-public-api.ts
    │   │   │   │   ├── two-factor-auth-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-connection-v1alpha1-api.ts
    │   │   │   │   ├── user-connection-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-preference-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-v1alpha1-api.ts
    │   │   │   │   └── user-v1alpha1-console-api.ts
    │   │   │   ├── api.ts
    │   │   │   ├── base.ts
    │   │   │   ├── common.ts
    │   │   │   ├── configuration.ts
    │   │   │   ├── git_push.sh
    │   │   │   ├── index.ts
    │   │   │   └── models/
    │   │   │       ├── add-operation.ts
    │   │   │       ├── annotation-setting-list.ts
    │   │   │       ├── annotation-setting-spec.ts
    │   │   │       ├── annotation-setting.ts
    │   │   │       ├── attachment-list.ts
    │   │   │       ├── attachment-spec.ts
    │   │   │       ├── attachment-status.ts
    │   │   │       ├── attachment.ts
    │   │   │       ├── auth-provider-list.ts
    │   │   │       ├── auth-provider-spec.ts
    │   │   │       ├── auth-provider.ts
    │   │   │       ├── author.ts
    │   │   │       ├── backup-file.ts
    │   │   │       ├── backup-list.ts
    │   │   │       ├── backup-spec.ts
    │   │   │       ├── backup-status.ts
    │   │   │       ├── backup.ts
    │   │   │       ├── category-list.ts
    │   │   │       ├── category-spec.ts
    │   │   │       ├── category-status.ts
    │   │   │       ├── category-vo-list.ts
    │   │   │       ├── category-vo.ts
    │   │   │       ├── category.ts
    │   │   │       ├── change-own-password-request.ts
    │   │   │       ├── change-password-request.ts
    │   │   │       ├── comment-email-owner.ts
    │   │   │       ├── comment-list.ts
    │   │   │       ├── comment-owner.ts
    │   │   │       ├── comment-request.ts
    │   │   │       ├── comment-spec.ts
    │   │   │       ├── comment-stats-vo.ts
    │   │   │       ├── comment-stats.ts
    │   │   │       ├── comment-status.ts
    │   │   │       ├── comment-vo-list.ts
    │   │   │       ├── comment-vo.ts
    │   │   │       ├── comment-with-reply-vo-list.ts
    │   │   │       ├── comment-with-reply-vo.ts
    │   │   │       ├── comment.ts
    │   │   │       ├── condition.ts
    │   │   │       ├── config-map-list.ts
    │   │   │       ├── config-map-ref.ts
    │   │   │       ├── config-map.ts
    │   │   │       ├── content-update-param.ts
    │   │   │       ├── content-vo.ts
    │   │   │       ├── content-wrapper.ts
    │   │   │       ├── content.ts
    │   │   │       ├── contributor-vo.ts
    │   │   │       ├── contributor.ts
    │   │   │       ├── copy-operation.ts
    │   │   │       ├── counter-list.ts
    │   │   │       ├── counter-request.ts
    │   │   │       ├── counter.ts
    │   │   │       ├── create-user-request.ts
    │   │   │       ├── custom-templates.ts
    │   │   │       ├── dashboard-stats.ts
    │   │   │       ├── detailed-user.ts
    │   │   │       ├── device-list.ts
    │   │   │       ├── device-spec.ts
    │   │   │       ├── device-status.ts
    │   │   │       ├── device.ts
    │   │   │       ├── email-config-validation-request.ts
    │   │   │       ├── email-verify-request.ts
    │   │   │       ├── excerpt.ts
    │   │   │       ├── extension-definition-list.ts
    │   │   │       ├── extension-definition.ts
    │   │   │       ├── extension-point-definition-list.ts
    │   │   │       ├── extension-point-definition.ts
    │   │   │       ├── extension-point-spec.ts
    │   │   │       ├── extension-spec.ts
    │   │   │       ├── extension.ts
    │   │   │       ├── file-reverse-proxy-provider.ts
    │   │   │       ├── grant-request.ts
    │   │   │       ├── group-kind.ts
    │   │   │       ├── group-list.ts
    │   │   │       ├── group-spec.ts
    │   │   │       ├── group-status.ts
    │   │   │       ├── group.ts
    │   │   │       ├── halo-document.ts
    │   │   │       ├── index.ts
    │   │   │       ├── install-from-uri-request.ts
    │   │   │       ├── interest-reason-subject.ts
    │   │   │       ├── interest-reason.ts
    │   │   │       ├── json-patch-inner.ts
    │   │   │       ├── license.ts
    │   │   │       ├── list-result-reply-vo.ts
    │   │   │       ├── listed-auth-provider.ts
    │   │   │       ├── listed-comment-list.ts
    │   │   │       ├── listed-comment.ts
    │   │   │       ├── listed-post-list.ts
    │   │   │       ├── listed-post-vo-list.ts
    │   │   │       ├── listed-post-vo.ts
    │   │   │       ├── listed-post.ts
    │   │   │       ├── listed-reply-list.ts
    │   │   │       ├── listed-reply.ts
    │   │   │       ├── listed-single-page-list.ts
    │   │   │       ├── listed-single-page-vo-list.ts
    │   │   │       ├── listed-single-page-vo.ts
    │   │   │       ├── listed-single-page.ts
    │   │   │       ├── listed-snapshot-dto.ts
    │   │   │       ├── listed-snapshot-spec.ts
    │   │   │       ├── listed-user.ts
    │   │   │       ├── local-thumbnail-list.ts
    │   │   │       ├── local-thumbnail-spec.ts
    │   │   │       ├── local-thumbnail-status.ts
    │   │   │       ├── local-thumbnail.ts
    │   │   │       ├── mark-specified-request.ts
    │   │   │       ├── menu-item-list.ts
    │   │   │       ├── menu-item-spec.ts
    │   │   │       ├── menu-item-status.ts
    │   │   │       ├── menu-item-vo.ts
    │   │   │       ├── menu-item.ts
    │   │   │       ├── menu-list.ts
    │   │   │       ├── menu-spec.ts
    │   │   │       ├── menu-vo.ts
    │   │   │       ├── menu.ts
    │   │   │       ├── metadata.ts
    │   │   │       ├── move-operation.ts
    │   │   │       ├── navigation-post-vo.ts
    │   │   │       ├── notification-list.ts
    │   │   │       ├── notification-spec.ts
    │   │   │       ├── notification-template-list.ts
    │   │   │       ├── notification-template-spec.ts
    │   │   │       ├── notification-template.ts
    │   │   │       ├── notification.ts
    │   │   │       ├── notifier-descriptor-list.ts
    │   │   │       ├── notifier-descriptor-spec.ts
    │   │   │       ├── notifier-descriptor.ts
    │   │   │       ├── notifier-info.ts
    │   │   │       ├── notifier-setting-ref.ts
    │   │   │       ├── owner-info.ts
    │   │   │       ├── password-request.ts
    │   │   │       ├── pat-spec.ts
    │   │   │       ├── personal-access-token-list.ts
    │   │   │       ├── personal-access-token.ts
    │   │   │       ├── plugin-author.ts
    │   │   │       ├── plugin-list.ts
    │   │   │       ├── plugin-running-state-request.ts
    │   │   │       ├── plugin-spec.ts
    │   │   │       ├── plugin-status.ts
    │   │   │       ├── plugin.ts
    │   │   │       ├── policy-list.ts
    │   │   │       ├── policy-rule.ts
    │   │   │       ├── policy-spec.ts
    │   │   │       ├── policy-template-list.ts
    │   │   │       ├── policy-template-spec.ts
    │   │   │       ├── policy-template.ts
    │   │   │       ├── policy.ts
    │   │   │       ├── post-list.ts
    │   │   │       ├── post-request.ts
    │   │   │       ├── post-spec.ts
    │   │   │       ├── post-status.ts
    │   │   │       ├── post-vo.ts
    │   │   │       ├── post.ts
    │   │   │       ├── reason-attributes.ts
    │   │   │       ├── reason-list.ts
    │   │   │       ├── reason-property.ts
    │   │   │       ├── reason-selector.ts
    │   │   │       ├── reason-spec.ts
    │   │   │       ├── reason-subject.ts
    │   │   │       ├── reason-type-info.ts
    │   │   │       ├── reason-type-list.ts
    │   │   │       ├── reason-type-notifier-collection-request.ts
    │   │   │       ├── reason-type-notifier-matrix.ts
    │   │   │       ├── reason-type-notifier-request.ts
    │   │   │       ├── reason-type-spec.ts
    │   │   │       ├── reason-type.ts
    │   │   │       ├── reason.ts
    │   │   │       ├── ref.ts
    │   │   │       ├── remember-me-token-list.ts
    │   │   │       ├── remember-me-token-spec.ts
    │   │   │       ├── remember-me-token.ts
    │   │   │       ├── remove-operation.ts
    │   │   │       ├── replace-operation.ts
    │   │   │       ├── reply-list.ts
    │   │   │       ├── reply-request.ts
    │   │   │       ├── reply-spec.ts
    │   │   │       ├── reply-status.ts
    │   │   │       ├── reply-vo-list.ts
    │   │   │       ├── reply-vo.ts
    │   │   │       ├── reply.ts
    │   │   │       ├── reverse-proxy-list.ts
    │   │   │       ├── reverse-proxy-rule.ts
    │   │   │       ├── reverse-proxy.ts
    │   │   │       ├── revert-snapshot-for-post-param.ts
    │   │   │       ├── revert-snapshot-for-single-param.ts
    │   │   │       ├── role-binding-list.ts
    │   │   │       ├── role-binding.ts
    │   │   │       ├── role-list.ts
    │   │   │       ├── role-ref.ts
    │   │   │       ├── role.ts
    │   │   │       ├── search-option.ts
    │   │   │       ├── search-result.ts
    │   │   │       ├── secret-list.ts
    │   │   │       ├── secret.ts
    │   │   │       ├── setting-form.ts
    │   │   │       ├── setting-list.ts
    │   │   │       ├── setting-ref.ts
    │   │   │       ├── setting-spec.ts
    │   │   │       ├── setting.ts
    │   │   │       ├── setup-request.ts
    │   │   │       ├── single-page-list.ts
    │   │   │       ├── single-page-request.ts
    │   │   │       ├── single-page-spec.ts
    │   │   │       ├── single-page-status.ts
    │   │   │       ├── single-page-vo.ts
    │   │   │       ├── single-page.ts
    │   │   │       ├── site-stats-vo.ts
    │   │   │       ├── snap-shot-spec.ts
    │   │   │       ├── snapshot-list.ts
    │   │   │       ├── snapshot.ts
    │   │   │       ├── stats-vo.ts
    │   │   │       ├── stats.ts
    │   │   │       ├── subject.ts
    │   │   │       ├── subscription-list.ts
    │   │   │       ├── subscription-spec.ts
    │   │   │       ├── subscription-subscriber.ts
    │   │   │       ├── subscription.ts
    │   │   │       ├── tag-list.ts
    │   │   │       ├── tag-spec.ts
    │   │   │       ├── tag-status.ts
    │   │   │       ├── tag-vo-list.ts
    │   │   │       ├── tag-vo.ts
    │   │   │       ├── tag.ts
    │   │   │       ├── template-content.ts
    │   │   │       ├── template-descriptor.ts
    │   │   │       ├── test-operation.ts
    │   │   │       ├── theme-list.ts
    │   │   │       ├── theme-spec.ts
    │   │   │       ├── theme-status.ts
    │   │   │       ├── theme.ts
    │   │   │       ├── thumbnail-list.ts
    │   │   │       ├── thumbnail-spec.ts
    │   │   │       ├── thumbnail.ts
    │   │   │       ├── totp-auth-link-response.ts
    │   │   │       ├── totp-request.ts
    │   │   │       ├── two-factor-auth-settings.ts
    │   │   │       ├── uc-upload-from-url-request.ts
    │   │   │       ├── upgrade-from-uri-request.ts
    │   │   │       ├── upload-from-url-request.ts
    │   │   │       ├── user-connection-list.ts
    │   │   │       ├── user-connection-spec.ts
    │   │   │       ├── user-connection.ts
    │   │   │       ├── user-device.ts
    │   │   │       ├── user-endpoint-listed-user-list.ts
    │   │   │       ├── user-list.ts
    │   │   │       ├── user-permission.ts
    │   │   │       ├── user-spec.ts
    │   │   │       ├── user-status.ts
    │   │   │       ├── user.ts
    │   │   │       ├── verify-code-request.ts
    │   │   │       └── vote-request.ts
    │   │   ├── tsconfig.json
    │   │   └── tsdown.config.ts
    │   ├── components/
    │   │   ├── .storybook/
    │   │   │   ├── main.ts
    │   │   │   └── preview.ts
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── postcss.config.cjs
    │   │   ├── src/
    │   │   │   ├── components/
    │   │   │   │   ├── alert/
    │   │   │   │   │   ├── Alert.stories.ts
    │   │   │   │   │   ├── Alert.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Alert.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── avatar/
    │   │   │   │   │   ├── Avatar.stories.ts
    │   │   │   │   │   ├── Avatar.vue
    │   │   │   │   │   ├── AvatarGroup.stories.ts
    │   │   │   │   │   ├── AvatarGroup.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── button/
    │   │   │   │   │   ├── Button.stories.ts
    │   │   │   │   │   ├── Button.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Button.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── Button.spec.ts.snap
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── card/
    │   │   │   │   │   ├── Card.stories.ts
    │   │   │   │   │   ├── Card.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Card.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── description/
    │   │   │   │   │   ├── Description.vue
    │   │   │   │   │   ├── DescriptionItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── dialog/
    │   │   │   │   │   ├── Dialog.stories.ts
    │   │   │   │   │   ├── Dialog.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Dialog.spec.ts
    │   │   │   │   │   ├── dialog-manager.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── dropdown/
    │   │   │   │   │   ├── Draopdown.stories.ts
    │   │   │   │   │   ├── DropdownDivider.vue
    │   │   │   │   │   ├── DropdownItem.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── style.scss
    │   │   │   │   ├── empty/
    │   │   │   │   │   ├── Empty.stories.ts
    │   │   │   │   │   ├── Empty.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Empty.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── Empty.spec.ts.snap
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── entity/
    │   │   │   │   │   ├── Entity.vue
    │   │   │   │   │   ├── EntityContainer.vue
    │   │   │   │   │   ├── EntityField.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Entity.spec.ts
    │   │   │   │   │   │   └── EntityField.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── header/
    │   │   │   │   │   ├── PageHeader.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── loading/
    │   │   │   │   │   ├── Loading.stories.ts
    │   │   │   │   │   ├── Loading.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── menu/
    │   │   │   │   │   ├── Menu.stories.ts
    │   │   │   │   │   ├── Menu.vue
    │   │   │   │   │   ├── MenuItem.vue
    │   │   │   │   │   ├── MenuLabel.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Menu.spec.tsx
    │   │   │   │   │   │   ├── MenuLabel.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       ├── Menu.spec.tsx.snap
    │   │   │   │   │   │       └── MenuLabel.spec.ts.snap
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── modal/
    │   │   │   │   │   ├── Modal.stories.ts
    │   │   │   │   │   ├── Modal.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Modal.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── pagination/
    │   │   │   │   │   ├── Pagination.stories.ts
    │   │   │   │   │   ├── Pagination.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Pagination.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── space/
    │   │   │   │   │   ├── Space.stories.ts
    │   │   │   │   │   ├── Space.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Space.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── status/
    │   │   │   │   │   ├── StatusDot.stories.ts
    │   │   │   │   │   ├── StatusDot.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── StatusDot.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── StatusDot.spec.ts.snap
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── switch/
    │   │   │   │   │   ├── Switch.stories.ts
    │   │   │   │   │   ├── Switch.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Switch.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── tabs/
    │   │   │   │   │   ├── TabItem.vue
    │   │   │   │   │   ├── Tabbar.stories.ts
    │   │   │   │   │   ├── Tabbar.vue
    │   │   │   │   │   ├── Tabs.stories.ts
    │   │   │   │   │   ├── Tabs.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── TabItem.spec.ts
    │   │   │   │   │   │   ├── Tabbar.spec.ts
    │   │   │   │   │   │   └── Tabs.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── tag/
    │   │   │   │   │   ├── Tag.stories.ts
    │   │   │   │   │   ├── Tag.story.vue
    │   │   │   │   │   ├── Tag.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Tag.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── toast/
    │   │   │   │   │   ├── Toast.story.vue
    │   │   │   │   │   ├── Toast.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── toast-manager.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   └── tooltip/
    │   │   │   │       ├── index.ts
    │   │   │   │       └── style.css
    │   │   │   ├── components.ts
    │   │   │   ├── icons/
    │   │   │   │   └── icons.ts
    │   │   │   ├── index.ts
    │   │   │   ├── stories/
    │   │   │   │   └── Introduction.mdx
    │   │   │   └── styles/
    │   │   │       └── tailwind.css
    │   │   ├── tailwind.config.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   ├── tsconfig.vitest.json
    │   │   └── vite.config.ts
    │   ├── console-shared/
    │   │   ├── README.md
    │   │   ├── index.js
    │   │   └── package.json
    │   ├── editor/
    │   │   ├── README.md
    │   │   ├── docs/
    │   │   │   └── extension.md
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── postcss.config.cjs
    │   │   ├── src/
    │   │   │   ├── components/
    │   │   │   │   ├── Editor.vue
    │   │   │   │   ├── EditorHeader.vue
    │   │   │   │   ├── base/
    │   │   │   │   │   ├── DropdownItem.vue
    │   │   │   │   │   ├── Input.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── block/
    │   │   │   │   │   ├── BlockActionButton.vue
    │   │   │   │   │   ├── BlockActionHorizontalSeparator.vue
    │   │   │   │   │   ├── BlockActionSeparator.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bubble/
    │   │   │   │   │   ├── BubbleButton.vue
    │   │   │   │   │   ├── BubbleItem.vue
    │   │   │   │   │   ├── EditorBubbleMenu.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── common/
    │   │   │   │   │   └── ColorPickerDropdown.vue
    │   │   │   │   ├── drag/
    │   │   │   │   │   ├── EditorDragButtonItem.vue
    │   │   │   │   │   ├── EditorDragHandle.vue
    │   │   │   │   │   ├── EditorDragMenu.vue
    │   │   │   │   │   ├── default-drag.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── icon/
    │   │   │   │   │   └── MingcuteDelete2Line.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── toolbar/
    │   │   │   │   │   ├── ToolbarItem.vue
    │   │   │   │   │   ├── ToolbarSubItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── toolbox/
    │   │   │   │   │   ├── ToolboxItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── upload/
    │   │   │   │       ├── EditorLinkObtain.vue
    │   │   │   │       ├── ResourceReplaceButton.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── composables/
    │   │   │   │   └── use-attachment.ts
    │   │   │   ├── extensions/
    │   │   │   │   ├── align/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── audio/
    │   │   │   │   │   ├── AudioView.vue
    │   │   │   │   │   ├── BubbleItemAudioLink.vue
    │   │   │   │   │   ├── BubbleItemAudioPosition.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── block-position/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── blockquote/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bold/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bullet-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── character-count/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── clear-format/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── code/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── code-block/
    │   │   │   │   │   ├── CodeBlockSelect.vue
    │   │   │   │   │   ├── CodeBlockViewRenderer.vue
    │   │   │   │   │   ├── code-block.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── color/
    │   │   │   │   │   ├── ColorBubbleItem.vue
    │   │   │   │   │   ├── ColorToolbarItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── columns/
    │   │   │   │   │   ├── column.ts
    │   │   │   │   │   ├── columns.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── commands-menu/
    │   │   │   │   │   ├── CommandsView.vue
    │   │   │   │   │   ├── commands.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── details/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── document/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── drop-cursor/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── extensions-kit.ts
    │   │   │   │   ├── figure/
    │   │   │   │   │   ├── FigureCaptionView.vue
    │   │   │   │   │   ├── figure-caption.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── font-size/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── format-brush/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── util.ts
    │   │   │   │   ├── gallery/
    │   │   │   │   │   ├── BubbleItemAddImage.vue
    │   │   │   │   │   ├── BubbleItemGap.vue
    │   │   │   │   │   ├── BubbleItemGroupSize.vue
    │   │   │   │   │   ├── BubbleItemLayout.vue
    │   │   │   │   │   ├── GalleryView.vue
    │   │   │   │   │   ├── gallery-bubble.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── useGalleryImages.ts
    │   │   │   │   ├── gap-cursor/
    │   │   │   │   │   ├── gap-cursor-selection.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── hard-break/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── heading/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── highlight/
    │   │   │   │   │   ├── HighlightBubbleItem.vue
    │   │   │   │   │   ├── HighlightToolbarItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── history/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── horizontal-rule/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── iframe/
    │   │   │   │   │   ├── BubbleItemIframeAlign.vue
    │   │   │   │   │   ├── BubbleItemIframeLink.vue
    │   │   │   │   │   ├── BubbleItemIframeSize.vue
    │   │   │   │   │   ├── IframeView.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── image/
    │   │   │   │   │   ├── BubbleItemImageAlt.vue
    │   │   │   │   │   ├── BubbleItemImageHref.vue
    │   │   │   │   │   ├── BubbleItemImageLink.vue
    │   │   │   │   │   ├── BubbleItemImagePosition.vue
    │   │   │   │   │   ├── BubbleItemImageSize.vue
    │   │   │   │   │   ├── ImageView.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── indent/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── italic/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── link/
    │   │   │   │   │   ├── LinkBubbleButton.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── list-extra/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── list-keymap/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── node-selected/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── ordered-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── paragraph/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── placeholder/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── range-selection/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── range-selection.ts
    │   │   │   │   ├── search-and-replace/
    │   │   │   │   │   ├── IconButton.vue
    │   │   │   │   │   ├── MatchToggleButton.vue
    │   │   │   │   │   ├── SearchAndReplace.vue
    │   │   │   │   │   ├── SearchAndReplacePlugin.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── smart-scroll/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── strike/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── subscript/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── superscript/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── table/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── table-cell.ts
    │   │   │   │   │   ├── table-header.ts
    │   │   │   │   │   ├── table-row.ts
    │   │   │   │   │   └── util.ts
    │   │   │   │   ├── task-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text/
    │   │   │   │   │   ├── BubbleItemTextType.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text-align/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text-style/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── trailing-node/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── underline/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── upload/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── video/
    │   │   │   │       ├── BubbleItemVideoLink.vue
    │   │   │   │       ├── BubbleItemVideoPosition.vue
    │   │   │   │       ├── BubbleItemVideoSize.vue
    │   │   │   │       ├── VideoView.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── locales/
    │   │   │   │   ├── en.json
    │   │   │   │   ├── es.json
    │   │   │   │   ├── index.ts
    │   │   │   │   └── zh-CN.json
    │   │   │   ├── styles/
    │   │   │   │   ├── base.scss
    │   │   │   │   ├── columns.scss
    │   │   │   │   ├── details.scss
    │   │   │   │   ├── draggable.scss
    │   │   │   │   ├── figure.scss
    │   │   │   │   ├── format-brush.scss
    │   │   │   │   ├── gap-cursor.scss
    │   │   │   │   ├── index.scss
    │   │   │   │   ├── node-select.scss
    │   │   │   │   ├── range-selection.scss
    │   │   │   │   ├── resizer.scss
    │   │   │   │   ├── search.scss
    │   │   │   │   ├── table.scss
    │   │   │   │   └── tailwind.css
    │   │   │   ├── tiptap/
    │   │   │   │   ├── core/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── pm/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── vue-3/
    │   │   │   │       └── index.ts
    │   │   │   ├── types/
    │   │   │   │   └── index.ts
    │   │   │   └── utils/
    │   │   │       ├── anchor.ts
    │   │   │       ├── attachment.ts
    │   │   │       ├── clipboard.ts
    │   │   │       ├── delete-node.ts
    │   │   │       ├── filter-duplicate-extensions.ts
    │   │   │       ├── index.ts
    │   │   │       ├── is-allowed-uri.ts
    │   │   │       ├── is-list-active.ts
    │   │   │       ├── is-node-empty.ts
    │   │   │       ├── keyboard.ts
    │   │   │       └── upload.ts
    │   │   ├── tailwind.config.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   ├── tsconfig.vitest.json
    │   │   └── vite.config.ts
    │   ├── shared/
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── src/
    │   │   │   ├── events/
    │   │   │   │   └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── plugin/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types/
    │   │   │   │       ├── attachment-selector.ts
    │   │   │   │       ├── backup.ts
    │   │   │   │       ├── comment.ts
    │   │   │   │       ├── dashboard-widget.ts
    │   │   │   │       ├── editor-provider.ts
    │   │   │   │       ├── index.ts
    │   │   │   │       ├── list-entity-field.ts
    │   │   │   │       ├── list-operation.ts
    │   │   │   │       ├── plugin-installation-tab.ts
    │   │   │   │       ├── plugin-tab.ts
    │   │   │   │       ├── theme-list-tab.ts
    │   │   │   │       ├── ui-plugin-entry.ts
    │   │   │   │       ├── ui-plugin-module.ts
    │   │   │   │       └── user-tab.ts
    │   │   │   ├── stores/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types/
    │   │   │   │       ├── actuator.ts
    │   │   │   │       ├── index.ts
    │   │   │   │       └── slug.ts
    │   │   │   ├── types/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── menus.ts
    │   │   │   └── utils/
    │   │   │       ├── attachment.ts
    │   │   │       ├── date.ts
    │   │   │       ├── id.ts
    │   │   │       ├── index.ts
    │   │   │       └── permission.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   └── tsdown.config.ts
    │   └── ui-plugin-bundler-kit/
    │       ├── README.md
    │       ├── package.json
    │       ├── src/
    │       │   ├── constants/
    │       │   │   ├── build.ts
    │       │   │   ├── externals.ts
    │       │   │   └── halo-plugin.ts
    │       │   ├── index.ts
    │       │   ├── legacy.ts
    │       │   ├── rsbuild.ts
    │       │   ├── utils/
    │       │   │   └── halo-plugin.ts
    │       │   └── vite.ts
    │       ├── tsconfig.json
    │       └── tsdown.config.ts
    ├── patches/
    │   └── @tiptap__extension-drag-handle@3.17.1.patch
    ├── pnpm-workspace.yaml
    ├── postcss.config.cjs
    ├── scripts/
    │   ├── apply_missing_translations.mjs
    │   ├── find_missing_translations.mjs
    │   └── fix_translations.mjs
    ├── src/
    │   ├── components/
    │   │   ├── alerts/
    │   │   │   └── H2WarningAlert.vue
    │   │   ├── attachment/
    │   │   │   ├── AttachmentGridListItem.vue
    │   │   │   ├── AttachmentImagePreview.vue
    │   │   │   └── AttachmentPermalinkList.vue
    │   │   ├── back-to-top/
    │   │   │   └── BackToTop.vue
    │   │   ├── base-app/
    │   │   │   └── BaseApp.vue
    │   │   ├── button/
    │   │   │   └── SubmitButton.vue
    │   │   ├── codemirror/
    │   │   │   ├── Codemirror.vue
    │   │   │   └── supports.ts
    │   │   ├── common/
    │   │   │   └── AppDownloadAlert.vue
    │   │   ├── dropdown-selector/
    │   │   │   └── EditorProviderSelector.vue
    │   │   ├── editor/
    │   │   │   └── DefaultEditor.vue
    │   │   ├── entity/
    │   │   │   └── EntityDropdownItems.vue
    │   │   ├── entity-fields/
    │   │   │   ├── EntityFieldItems.vue
    │   │   │   └── StatusDotField.vue
    │   │   ├── filter/
    │   │   │   ├── CategoryFilterDropdown.vue
    │   │   │   ├── FilterCleanButton.vue
    │   │   │   ├── FilterDropdown.vue
    │   │   │   ├── FilterTag.vue
    │   │   │   ├── TagFilterDropdown.vue
    │   │   │   └── UserFilterDropdown.vue
    │   │   ├── form/
    │   │   │   └── AnnotationsForm.vue
    │   │   ├── global-search/
    │   │   │   └── GlobalSearchModal.vue
    │   │   ├── icon/
    │   │   │   └── AttachmentFileTypeIcon.vue
    │   │   ├── input/
    │   │   │   └── SearchInput.vue
    │   │   ├── menu/
    │   │   │   ├── MenuLoading.vue
    │   │   │   └── RoutesMenu.tsx
    │   │   ├── permission/
    │   │   │   └── HasPermission.vue
    │   │   ├── preview/
    │   │   │   └── UrlPreviewModal.vue
    │   │   ├── sticky-block/
    │   │   │   └── StickyBlock.vue
    │   │   ├── upload/
    │   │   │   └── UppyUpload.vue
    │   │   ├── user/
    │   │   │   └── PostContributorList.vue
    │   │   ├── user-avatar/
    │   │   │   ├── UserAvatar.vue
    │   │   │   └── UserAvatarCropper.vue
    │   │   └── video/
    │   │       └── LazyVideo.vue
    │   ├── composables/
    │   │   ├── use-auto-save-content.ts
    │   │   ├── use-content-cache.ts
    │   │   ├── use-editor-extension-points.ts
    │   │   ├── use-role.ts
    │   │   ├── use-route-menu-generator.ts
    │   │   ├── use-session-keep-alive.ts
    │   │   └── use-title.ts
    │   ├── constants/
    │   │   ├── annotations.ts
    │   │   ├── app.ts
    │   │   ├── constants.ts
    │   │   ├── error-types.ts
    │   │   ├── finalizers.ts
    │   │   ├── labels.ts
    │   │   └── regex.ts
    │   ├── formkit/
    │   │   ├── formkit.config.ts
    │   │   ├── inputs/
    │   │   │   ├── array/
    │   │   │   │   ├── ArrayFormModal.vue
    │   │   │   │   ├── ArrayInput.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── labels/
    │   │   │   │   │   ├── ColorLabel.vue
    │   │   │   │   │   └── IconifyLabel.vue
    │   │   │   │   ├── renderers/
    │   │   │   │   │   ├── attachment.ts
    │   │   │   │   │   ├── category-select.ts
    │   │   │   │   │   ├── checkbox.ts
    │   │   │   │   │   ├── helpers/
    │   │   │   │   │   │   └── findOption.ts
    │   │   │   │   │   ├── iconify.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── native-select.ts
    │   │   │   │   │   ├── radio.ts
    │   │   │   │   │   ├── select.ts
    │   │   │   │   │   ├── tag-select.ts
    │   │   │   │   │   ├── toggle.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── attachment/
    │   │   │   │   ├── AttachmentDropdownItem.vue
    │   │   │   │   ├── AttachmentInput.vue
    │   │   │   │   ├── AttachmentPreview.vue
    │   │   │   │   ├── CustomLinkDropdownItem.vue
    │   │   │   │   ├── UploadDropdownItem.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── attachment-group-select.ts
    │   │   │   ├── attachment-input/
    │   │   │   │   ├── AttachmentInput.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── attachment-policy-select.ts
    │   │   │   ├── category-checkbox.ts
    │   │   │   ├── category-select/
    │   │   │   │   ├── CategorySelect.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── CategoryListItem.vue
    │   │   │   │   │   ├── CategoryTag.vue
    │   │   │   │   │   └── SearchResultListItem.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── code/
    │   │   │   │   ├── CodeInput.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── color/
    │   │   │   │   ├── ColorInput.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types.ts
    │   │   │   ├── form.ts
    │   │   │   ├── group.ts
    │   │   │   ├── iconify/
    │   │   │   │   ├── Collections.vue
    │   │   │   │   ├── CollectionsView.vue
    │   │   │   │   ├── Icon.vue
    │   │   │   │   ├── IconConfirmPanel.vue
    │   │   │   │   ├── IconifyInput.vue
    │   │   │   │   ├── IconifyPicker.vue
    │   │   │   │   ├── Icons.vue
    │   │   │   │   ├── SearchView.vue
    │   │   │   │   ├── api.ts
    │   │   │   │   ├── feature.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types.ts
    │   │   │   ├── list/
    │   │   │   │   ├── AddButton.vue
    │   │   │   │   ├── features/
    │   │   │   │   │   └── lists.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── listSection.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── menu-checkbox.ts
    │   │   │   ├── menu-item-select.ts
    │   │   │   ├── menu-radio.ts
    │   │   │   ├── menu-select.ts
    │   │   │   ├── password/
    │   │   │   │   ├── RevealButton.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── post-select.ts
    │   │   │   ├── repeater/
    │   │   │   │   ├── AddButton.vue
    │   │   │   │   ├── features/
    │   │   │   │   │   └── repeats.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── repeaterSection.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── role-select.ts
    │   │   │   ├── secret/
    │   │   │   │   ├── SecretSelect.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── SecretCreationModal.vue
    │   │   │   │   │   ├── SecretEditModal.vue
    │   │   │   │   │   ├── SecretForm.vue
    │   │   │   │   │   ├── SecretListItem.vue
    │   │   │   │   │   └── SecretListModal.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   └── use-secrets-fetch.ts
    │   │   │   │   ├── feature.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── sections/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── types/
    │   │   │   │       └── index.ts
    │   │   │   ├── select/
    │   │   │   │   ├── MultipleOverflow.vue
    │   │   │   │   ├── MultipleOverflowItem.vue
    │   │   │   │   ├── MultipleSelect.vue
    │   │   │   │   ├── MultipleSelectItem.vue
    │   │   │   │   ├── MultipleSelectSearchInput.vue
    │   │   │   │   ├── MultipleSelectSelector.vue
    │   │   │   │   ├── SelectContainer.vue
    │   │   │   │   ├── SelectDropdownContainer.vue
    │   │   │   │   ├── SelectMain.vue
    │   │   │   │   ├── SelectOption.vue
    │   │   │   │   ├── SelectOptionItem.vue
    │   │   │   │   ├── SelectSearchInput.vue
    │   │   │   │   ├── SelectSelector.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── isFalse.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── singlePage-select.ts
    │   │   │   ├── switch/
    │   │   │   │   ├── SwitchInput.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── tag-checkbox.ts
    │   │   │   ├── tag-select/
    │   │   │   │   ├── TagSelect.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── toggle/
    │   │   │   │   ├── ToggleInput.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── user-select.ts
    │   │   │   └── verify-form/
    │   │   │       ├── VerificationButton.vue
    │   │   │       ├── features/
    │   │   │       │   └── index.ts
    │   │   │       └── index.ts
    │   │   ├── plugins/
    │   │   │   ├── auto-scroll-to-errors.ts
    │   │   │   ├── password-prevent-autocomplete.ts
    │   │   │   ├── radio-alt.ts
    │   │   │   ├── required-asterisk.ts
    │   │   │   └── stop-implicit-submission.ts
    │   │   ├── theme.ts
    │   │   └── utils/
    │   │       └── focus.ts
    │   ├── layouts/
    │   │   ├── MobileMenu.vue
    │   │   └── UserProfileBanner.vue
    │   ├── locales/
    │   │   ├── en.json
    │   │   ├── es.json
    │   │   ├── index.ts
    │   │   ├── zh-CN.json
    │   │   └── zh-TW.json
    │   ├── router/
    │   │   └── process-bar.ts
    │   ├── setup/
    │   │   ├── setupApiClient.ts
    │   │   ├── setupComponents.ts
    │   │   ├── setupModules.ts
    │   │   ├── setupStyles.ts
    │   │   ├── setupUserPermissions.ts
    │   │   └── setupVueQuery.ts
    │   ├── stores/
    │   │   ├── plugin.ts
    │   │   └── role.ts
    │   ├── styles/
    │   │   ├── index.css
    │   │   └── tailwind.css
    │   ├── utils/
    │   │   ├── __tests__/
    │   │   │   └── media-type.spec.ts
    │   │   ├── cookie.ts
    │   │   ├── device.ts
    │   │   ├── image.ts
    │   │   ├── load-style.ts
    │   │   ├── media-type.ts
    │   │   ├── modal.ts
    │   │   └── role.ts
    │   ├── views/
    │   │   └── exceptions/
    │   │       ├── Forbidden.vue
    │   │       ├── NotFound.vue
    │   │       ├── __tests__/
    │   │       │   └── NotFound.spec.ts
    │   │       └── components/
    │   │           └── Exception.vue
    │   └── vite/
    │       ├── library-external.ts
    │       └── plugin-dev.ts
    ├── tailwind.config.ts
    ├── tsconfig.app.json
    ├── tsconfig.json
    ├── tsconfig.node.json
    ├── tsconfig.vitest.json
    ├── uc-src/
    │   ├── App.vue
    │   ├── layouts/
    │   │   └── BasicLayout.vue
    │   ├── main.ts
    │   ├── modules/
    │   │   ├── contents/
    │   │   │   ├── attachments/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── AttachmentDetailModal.vue
    │   │   │   │   │   ├── AttachmentSelectorModal.vue
    │   │   │   │   │   └── selector-providers/
    │   │   │   │   │       ├── AttachmentUploadModal.vue
    │   │   │   │   │       ├── CoreSelectorProvider.vue
    │   │   │   │   │       └── components/
    │   │   │   │   │           └── AttachmentSelectorListItem.vue
    │   │   │   │   └── module.ts
    │   │   │   └── posts/
    │   │   │       ├── PostEditor.vue
    │   │   │       ├── PostList.vue
    │   │   │       ├── components/
    │   │   │       │   ├── PostCreationModal.vue
    │   │   │       │   ├── PostListItem.vue
    │   │   │       │   ├── PostSettingEditModal.vue
    │   │   │       │   └── PostSettingForm.vue
    │   │   │       ├── composables/
    │   │   │       │   ├── use-post-publish-mutate.ts
    │   │   │       │   └── use-post-update-mutate.ts
    │   │   │       ├── module.ts
    │   │   │       └── types/
    │   │   │           └── index.ts
    │   │   ├── index.ts
    │   │   ├── notifications/
    │   │   │   ├── Notifications.vue
    │   │   │   ├── components/
    │   │   │   │   ├── NotificationContent.vue
    │   │   │   │   └── NotificationListItem.vue
    │   │   │   └── module.ts
    │   │   └── profile/
    │   │       ├── Profile.vue
    │   │       ├── components/
    │   │       │   ├── EmailVerifyModal.vue
    │   │       │   ├── PasswordChangeModal.vue
    │   │       │   ├── PersonalAccessTokenCreationModal.vue
    │   │       │   ├── PersonalAccessTokenListItem.vue
    │   │       │   └── ProfileEditingModal.vue
    │   │       ├── module.ts
    │   │       └── tabs/
    │   │           ├── Authentication.vue
    │   │           ├── Detail.vue
    │   │           ├── Devices.vue
    │   │           ├── NotificationPreferences.vue
    │   │           ├── PersonalAccessTokens.vue
    │   │           ├── components/
    │   │           │   ├── AuthProviders.vue
    │   │           │   ├── DeviceDetailModal.vue
    │   │           │   ├── DeviceListItem.vue
    │   │           │   ├── PasswordValidationForm.vue
    │   │           │   ├── TotpConfigureModal.vue
    │   │           │   ├── TotpDeletionModal.vue
    │   │           │   ├── TwoFactor.vue
    │   │           │   ├── TwoFactorDisableModal.vue
    │   │           │   └── TwoFactorEnableModal.vue
    │   │           └── composables/
    │   │               ├── use-user-agent.ts
    │   │               └── use-user-device.ts
    │   └── router/
    │       ├── constant.ts
    │       ├── guards/
    │       │   ├── auth-check.ts
    │       │   └── permission.ts
    │       ├── index.ts
    │       └── routes.config.ts
    ├── uc.html
    └── vite.config.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
ui
.github
.git

================================================
FILE: .editorconfig
================================================
root=true

[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 120
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_wrap_on_typing = false

[*.java]
max_line_length = 100
ij_continuation_indent_size = 4
ij_java_align_consecutive_assignments = false
ij_java_align_consecutive_variable_declarations = false
ij_java_align_group_field_declarations = false
ij_java_align_multiline_annotation_parameters = false
ij_java_align_multiline_array_initializer_expression = false
ij_java_align_multiline_assignment = false
ij_java_align_multiline_binary_operation = false
ij_java_align_multiline_chained_methods = false
ij_java_align_multiline_extends_list = false
ij_java_align_multiline_for = true
ij_java_align_multiline_method_parentheses = false
ij_java_align_multiline_parameters = false
ij_java_align_multiline_parameters_in_calls = false
ij_java_align_multiline_parenthesized_expression = false
ij_java_align_multiline_records = true
ij_java_align_multiline_resources = true
ij_java_align_multiline_ternary_operation = false
ij_java_align_multiline_text_blocks = false
ij_java_align_multiline_throws_list = false
ij_java_align_subsequent_simple_methods = false
ij_java_align_throws_keyword = false
ij_java_annotation_parameter_wrap = off
ij_java_array_initializer_new_line_after_left_brace = false
ij_java_array_initializer_right_brace_on_new_line = false
ij_java_array_initializer_wrap = normal
ij_java_assert_statement_colon_on_next_line = false
ij_java_assert_statement_wrap = normal
ij_java_assignment_wrap = normal
ij_java_binary_operation_sign_on_next_line = true
ij_java_binary_operation_wrap = normal
ij_java_blank_lines_after_anonymous_class_header = 0
ij_java_blank_lines_after_class_header = 0
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_after_package = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_around_field = 0
ij_java_blank_lines_around_field_in_interface = 0
ij_java_blank_lines_around_initializer = 1
ij_java_blank_lines_around_method = 1
ij_java_blank_lines_around_method_in_interface = 1
ij_java_blank_lines_before_class_end = 0
ij_java_blank_lines_before_imports = 0
ij_java_blank_lines_before_method_body = 0
ij_java_blank_lines_before_package = 1
ij_java_block_brace_style = end_of_line
ij_java_block_comment_at_first_column = false
ij_java_call_parameters_new_line_after_left_paren = false
ij_java_call_parameters_right_paren_on_new_line = false
ij_java_call_parameters_wrap = normal
ij_java_case_statement_on_separate_line = true
ij_java_catch_on_new_line = false
ij_java_class_annotation_wrap = split_into_lines
ij_java_class_brace_style = end_of_line
ij_java_class_count_to_use_import_on_demand = 999
ij_java_class_names_in_javadoc = 1
ij_java_do_not_indent_top_level_class_members = false
ij_java_do_not_wrap_after_single_annotation = false
ij_java_do_while_brace_force = always
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_align_exception_comments = true
ij_java_doc_align_param_comments = false
ij_java_doc_do_not_wrap_if_one_line = false
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = false
ij_java_doc_keep_empty_lines = true
ij_java_doc_keep_empty_parameter_tag = true
ij_java_doc_keep_empty_return_tag = true
ij_java_doc_keep_empty_throws_tag = true
ij_java_doc_keep_invalid_tags = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_preserve_line_breaks = false
ij_java_doc_use_throws_not_exception_tag = true
ij_java_else_on_new_line = false
ij_java_enum_constants_wrap = normal
ij_java_extends_keyword_wrap = normal
ij_java_extends_list_wrap = normal
ij_java_field_annotation_wrap = split_into_lines
ij_java_finally_on_new_line = false
ij_java_for_brace_force = always
ij_java_for_statement_new_line_after_left_paren = false
ij_java_for_statement_right_paren_on_new_line = false
ij_java_for_statement_wrap = normal
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_if_brace_force = always
ij_java_imports_layout = $*, |, *, |, *
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
ij_java_keep_blank_lines_before_right_brace = 2
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
ij_java_keep_blank_lines_in_code = 2
ij_java_keep_blank_lines_in_declarations = 2
ij_java_keep_control_statement_in_one_line = true
ij_java_keep_first_column_comment = true
ij_java_keep_indents_on_empty_lines = false
ij_java_keep_line_breaks = true
ij_java_keep_multiple_expressions_in_one_line = false
ij_java_keep_simple_blocks_in_one_line = false
ij_java_keep_simple_classes_in_one_line = false
ij_java_keep_simple_lambdas_in_one_line = false
ij_java_keep_simple_methods_in_one_line = false
ij_java_label_indent_absolute = false
ij_java_label_indent_size = 0
ij_java_lambda_brace_style = end_of_line
ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = true
ij_java_line_comment_at_first_column = false
ij_java_method_annotation_wrap = split_into_lines
ij_java_method_brace_style = end_of_line
ij_java_method_call_chain_wrap = normal
ij_java_method_parameters_new_line_after_left_paren = false
ij_java_method_parameters_right_paren_on_new_line = false
ij_java_method_parameters_wrap = normal
ij_java_modifier_list_wrap = false
ij_java_names_count_to_use_import_on_demand = 999
ij_java_new_line_after_lparen_in_record_header = false
ij_java_parameter_annotation_wrap = normal
ij_java_parentheses_expression_new_line_after_left_paren = false
ij_java_parentheses_expression_right_paren_on_new_line = false
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_record_components_wrap = normal
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = true
ij_java_replace_sum_lambda_with_method_ref = true
ij_java_resource_list_new_line_after_left_paren = false
ij_java_resource_list_right_paren_on_new_line = false
ij_java_resource_list_wrap = normal
ij_java_rparen_on_new_line_in_record_header = false
ij_java_space_after_closing_angle_bracket_in_type_argument = false
ij_java_space_after_colon = true
ij_java_space_after_comma = true
ij_java_space_after_comma_in_type_arguments = true
ij_java_space_after_for_semicolon = true
ij_java_space_after_quest = true
ij_java_space_after_type_cast = true
ij_java_space_before_annotation_array_initializer_left_brace = false
ij_java_space_before_annotation_parameter_list = false
ij_java_space_before_array_initializer_left_brace = true
ij_java_space_before_catch_keyword = true
ij_java_space_before_catch_left_brace = true
ij_java_space_before_catch_parentheses = true
ij_java_space_before_class_left_brace = true
ij_java_space_before_colon = true
ij_java_space_before_colon_in_foreach = true
ij_java_space_before_comma = false
ij_java_space_before_do_left_brace = true
ij_java_space_before_else_keyword = true
ij_java_space_before_else_left_brace = true
ij_java_space_before_finally_keyword = true
ij_java_space_before_finally_left_brace = true
ij_java_space_before_for_left_brace = true
ij_java_space_before_for_parentheses = true
ij_java_space_before_for_semicolon = false
ij_java_space_before_if_left_brace = true
ij_java_space_before_if_parentheses = true
ij_java_space_before_method_call_parentheses = false
ij_java_space_before_method_left_brace = true
ij_java_space_before_method_parentheses = false
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
ij_java_space_before_quest = true
ij_java_space_before_switch_left_brace = true
ij_java_space_before_switch_parentheses = true
ij_java_space_before_synchronized_left_brace = true
ij_java_space_before_synchronized_parentheses = true
ij_java_space_before_try_left_brace = true
ij_java_space_before_try_parentheses = true
ij_java_space_before_type_parameter_list = false
ij_java_space_before_while_keyword = true
ij_java_space_before_while_left_brace = true
ij_java_space_before_while_parentheses = true
ij_java_space_inside_one_line_enum_braces = false
ij_java_space_within_empty_array_initializer_braces = false
ij_java_space_within_empty_method_call_parentheses = false
ij_java_space_within_empty_method_parentheses = false
ij_java_spaces_around_additive_operators = true
ij_java_spaces_around_assignment_operators = true
ij_java_spaces_around_bitwise_operators = true
ij_java_spaces_around_equality_operators = true
ij_java_spaces_around_lambda_arrow = true
ij_java_spaces_around_logical_operators = true
ij_java_spaces_around_method_ref_dbl_colon = false
ij_java_spaces_around_multiplicative_operators = true
ij_java_spaces_around_relational_operators = true
ij_java_spaces_around_shift_operators = true
ij_java_spaces_around_type_bounds_in_type_parameters = true
ij_java_spaces_around_unary_operator = false
ij_java_spaces_within_angle_brackets = false
ij_java_spaces_within_annotation_parentheses = false
ij_java_spaces_within_array_initializer_braces = false
ij_java_spaces_within_braces = false
ij_java_spaces_within_brackets = false
ij_java_spaces_within_cast_parentheses = false
ij_java_spaces_within_catch_parentheses = false
ij_java_spaces_within_for_parentheses = false
ij_java_spaces_within_if_parentheses = false
ij_java_spaces_within_method_call_parentheses = false
ij_java_spaces_within_method_parentheses = false
ij_java_spaces_within_parentheses = false
ij_java_spaces_within_switch_parentheses = false
ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_subclass_name_suffix = Impl
ij_java_ternary_operation_signs_on_next_line = true
ij_java_ternary_operation_wrap = normal
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = normal
ij_java_throws_list_wrap = normal
ij_java_use_external_annotations = false
ij_java_use_fq_class_names = false
ij_java_use_relative_indents = false
ij_java_use_single_class_imports = true
ij_java_variable_annotation_wrap = normal
ij_java_visibility = public
ij_java_while_brace_force = always
ij_java_while_on_new_line = false
ij_java_wrap_comments = false
ij_java_wrap_first_method_in_call_chain = false
ij_java_wrap_long_lines = true

[*.properties]
ij_properties_align_group_field_declarations = false
ij_properties_keep_blank_lines = false
ij_properties_key_value_delimiter = equals
ij_properties_spaces_around_key_value_delimiter = false

[.editorconfig]
ij_editorconfig_align_group_field_declarations = false
ij_editorconfig_space_after_colon = false
ij_editorconfig_space_after_comma = true
ij_editorconfig_space_before_colon = false
ij_editorconfig_space_before_comma = false
ij_editorconfig_spaces_around_assignment_operators = true

[{*.ant, *.fxml, *.jhm, *.jnlp, *.jrxml, *.jspx, *.pom, *.rng, *.tagx, *.tld, *.wsdl, *.xml, *.xsd, *.xsl, *.xslt, *.xul}]
ij_xml_align_attributes = true
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = true
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = false
ij_xml_text_wrap = normal

[{*.bash, *.sh, *.zsh}]
indent_size = 2
tab_width = 2
ij_shell_binary_ops_start_line = false
ij_shell_keep_column_alignment_padding = false
ij_shell_minify_program = false
ij_shell_redirect_followed_by_space = false
ij_shell_switch_cases_indented = false

[{*.gant, *.gradle, *.groovy, *.gy}]
ij_groovy_align_group_field_declarations = false
ij_groovy_align_multiline_array_initializer_expression = false
ij_groovy_align_multiline_assignment = false
ij_groovy_align_multiline_binary_operation = false
ij_groovy_align_multiline_chained_methods = false
ij_groovy_align_multiline_extends_list = false
ij_groovy_align_multiline_for = true
ij_groovy_align_multiline_list_or_map = true
ij_groovy_align_multiline_method_parentheses = false
ij_groovy_align_multiline_parameters = true
ij_groovy_align_multiline_parameters_in_calls = false
ij_groovy_align_multiline_resources = true
ij_groovy_align_multiline_ternary_operation = false
ij_groovy_align_multiline_throws_list = false
ij_groovy_align_named_args_in_map = true
ij_groovy_align_throws_keyword = false
ij_groovy_array_initializer_new_line_after_left_brace = false
ij_groovy_array_initializer_right_brace_on_new_line = false
ij_groovy_array_initializer_wrap = off
ij_groovy_assert_statement_wrap = off
ij_groovy_assignment_wrap = off
ij_groovy_binary_operation_wrap = off
ij_groovy_blank_lines_after_class_header = 0
ij_groovy_blank_lines_after_imports = 1
ij_groovy_blank_lines_after_package = 1
ij_groovy_blank_lines_around_class = 1
ij_groovy_blank_lines_around_field = 0
ij_groovy_blank_lines_around_field_in_interface = 0
ij_groovy_blank_lines_around_method = 1
ij_groovy_blank_lines_around_method_in_interface = 1
ij_groovy_blank_lines_before_imports = 1
ij_groovy_blank_lines_before_method_body = 0
ij_groovy_blank_lines_before_package = 0
ij_groovy_block_brace_style = end_of_line
ij_groovy_block_comment_at_first_column = true
ij_groovy_call_parameters_new_line_after_left_paren = false
ij_groovy_call_parameters_right_paren_on_new_line = false
ij_groovy_call_parameters_wrap = off
ij_groovy_catch_on_new_line = false
ij_groovy_class_annotation_wrap = split_into_lines
ij_groovy_class_brace_style = end_of_line
ij_groovy_class_count_to_use_import_on_demand = 5
ij_groovy_do_while_brace_force = never
ij_groovy_else_on_new_line = false
ij_groovy_enum_constants_wrap = off
ij_groovy_extends_keyword_wrap = off
ij_groovy_extends_list_wrap = off
ij_groovy_field_annotation_wrap = split_into_lines
ij_groovy_finally_on_new_line = false
ij_groovy_for_brace_force = never
ij_groovy_for_statement_new_line_after_left_paren = false
ij_groovy_for_statement_right_paren_on_new_line = false
ij_groovy_for_statement_wrap = off
ij_groovy_if_brace_force = never
ij_groovy_import_annotation_wrap = 2
ij_groovy_indent_case_from_switch = true
ij_groovy_indent_label_blocks = true
ij_groovy_insert_inner_class_imports = false
ij_groovy_keep_blank_lines_before_right_brace = 2
ij_groovy_keep_blank_lines_in_code = 2
ij_groovy_keep_blank_lines_in_declarations = 2
ij_groovy_keep_control_statement_in_one_line = true
ij_groovy_keep_first_column_comment = true
ij_groovy_keep_indents_on_empty_lines = false
ij_groovy_keep_line_breaks = true
ij_groovy_keep_multiple_expressions_in_one_line = false
ij_groovy_keep_simple_blocks_in_one_line = false
ij_groovy_keep_simple_classes_in_one_line = true
ij_groovy_keep_simple_lambdas_in_one_line = true
ij_groovy_keep_simple_methods_in_one_line = true
ij_groovy_label_indent_absolute = false
ij_groovy_label_indent_size = 0
ij_groovy_lambda_brace_style = end_of_line
ij_groovy_layout_static_imports_separately = true
ij_groovy_line_comment_add_space = false
ij_groovy_line_comment_at_first_column = true
ij_groovy_method_annotation_wrap = split_into_lines
ij_groovy_method_brace_style = end_of_line
ij_groovy_method_call_chain_wrap = off
ij_groovy_method_parameters_new_line_after_left_paren = false
ij_groovy_method_parameters_right_paren_on_new_line = false
ij_groovy_method_parameters_wrap = off
ij_groovy_modifier_list_wrap = false
ij_groovy_names_count_to_use_import_on_demand = 3
ij_groovy_parameter_annotation_wrap = off
ij_groovy_parentheses_expression_new_line_after_left_paren = false
ij_groovy_parentheses_expression_right_paren_on_new_line = false
ij_groovy_prefer_parameters_wrap = false
ij_groovy_resource_list_new_line_after_left_paren = false
ij_groovy_resource_list_right_paren_on_new_line = false
ij_groovy_resource_list_wrap = off
ij_groovy_space_after_assert_separator = true
ij_groovy_space_after_colon = true
ij_groovy_space_after_comma = true
ij_groovy_space_after_comma_in_type_arguments = true
ij_groovy_space_after_for_semicolon = true
ij_groovy_space_after_quest = true
ij_groovy_space_after_type_cast = true
ij_groovy_space_before_annotation_parameter_list = false
ij_groovy_space_before_array_initializer_left_brace = false
ij_groovy_space_before_assert_separator = false
ij_groovy_space_before_catch_keyword = true
ij_groovy_space_before_catch_left_brace = true
ij_groovy_space_before_catch_parentheses = true
ij_groovy_space_before_class_left_brace = true
ij_groovy_space_before_closure_left_brace = true
ij_groovy_space_before_colon = true
ij_groovy_space_before_comma = false
ij_groovy_space_before_do_left_brace = true
ij_groovy_space_before_else_keyword = true
ij_groovy_space_before_else_left_brace = true
ij_groovy_space_before_finally_keyword = true
ij_groovy_space_before_finally_left_brace = true
ij_groovy_space_before_for_left_brace = true
ij_groovy_space_before_for_parentheses = true
ij_groovy_space_before_for_semicolon = false
ij_groovy_space_before_if_left_brace = true
ij_groovy_space_before_if_parentheses = true
ij_groovy_space_before_method_call_parentheses = false
ij_groovy_space_before_method_left_brace = true
ij_groovy_space_before_method_parentheses = false
ij_groovy_space_before_quest = true
ij_groovy_space_before_switch_left_brace = true
ij_groovy_space_before_switch_parentheses = true
ij_groovy_space_before_synchronized_left_brace = true
ij_groovy_space_before_synchronized_parentheses = true
ij_groovy_space_before_try_left_brace = true
ij_groovy_space_before_try_parentheses = true
ij_groovy_space_before_while_keyword = true
ij_groovy_space_before_while_left_brace = true
ij_groovy_space_before_while_parentheses = true
ij_groovy_space_in_named_argument = true
ij_groovy_space_in_named_argument_before_colon = false
ij_groovy_space_within_empty_array_initializer_braces = false
ij_groovy_space_within_empty_method_call_parentheses = false
ij_groovy_spaces_around_additive_operators = true
ij_groovy_spaces_around_assignment_operators = true
ij_groovy_spaces_around_bitwise_operators = true
ij_groovy_spaces_around_equality_operators = true
ij_groovy_spaces_around_lambda_arrow = true
ij_groovy_spaces_around_logical_operators = true
ij_groovy_spaces_around_multiplicative_operators = true
ij_groovy_spaces_around_regex_operators = true
ij_groovy_spaces_around_relational_operators = true
ij_groovy_spaces_around_shift_operators = true
ij_groovy_spaces_within_annotation_parentheses = false
ij_groovy_spaces_within_array_initializer_braces = false
ij_groovy_spaces_within_braces = true
ij_groovy_spaces_within_brackets = false
ij_groovy_spaces_within_cast_parentheses = false
ij_groovy_spaces_within_catch_parentheses = false
ij_groovy_spaces_within_for_parentheses = false
ij_groovy_spaces_within_gstring_injection_braces = false
ij_groovy_spaces_within_if_parentheses = false
ij_groovy_spaces_within_list_or_map = false
ij_groovy_spaces_within_method_call_parentheses = false
ij_groovy_spaces_within_method_parentheses = false
ij_groovy_spaces_within_parentheses = false
ij_groovy_spaces_within_switch_parentheses = false
ij_groovy_spaces_within_synchronized_parentheses = false
ij_groovy_spaces_within_try_parentheses = false
ij_groovy_spaces_within_tuple_expression = false
ij_groovy_spaces_within_while_parentheses = false
ij_groovy_special_else_if_treatment = true
ij_groovy_ternary_operation_wrap = off
ij_groovy_throws_keyword_wrap = off
ij_groovy_throws_list_wrap = off
ij_groovy_use_flying_geese_braces = false
ij_groovy_use_fq_class_names = false
ij_groovy_use_fq_class_names_in_javadoc = true
ij_groovy_use_relative_indents = false
ij_groovy_use_single_class_imports = true
ij_groovy_variable_annotation_wrap = off
ij_groovy_while_brace_force = never
ij_groovy_while_on_new_line = false
ij_groovy_wrap_long_lines = false

[{*.har, *.json}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false

[{*.htm, *.html, *.sht, *.shtm, *.shtml}]
ij_html_add_new_line_before_tags = body, div, p, form, h1, h2, h3
ij_html_align_attributes = true
ij_html_align_text = false
ij_html_attribute_wrap = normal
ij_html_block_comment_at_first_column = true
ij_html_do_not_align_children_of_min_lines = 0
ij_html_do_not_break_if_inline_tags = title, h1, h2, h3, h4, h5, h6, p
ij_html_do_not_indent_children_of_tags = html, body, thead, tbody, tfoot
ij_html_enforce_quotes = false
ij_html_inline_tags = a, abbr, acronym, b, basefont, bdo, big, br, cite, cite, code, dfn, em, font, i, img, input, kbd, label, q, s, samp, select, small, span, strike, strong, sub, sup, textarea, tt, u, var
ij_html_keep_blank_lines = 2
ij_html_keep_indents_on_empty_lines = false
ij_html_keep_line_breaks = true
ij_html_keep_line_breaks_in_text = true
ij_html_keep_whitespaces = false
ij_html_keep_whitespaces_inside = span, pre, textarea
ij_html_line_comment_at_first_column = true
ij_html_new_line_after_last_attribute = never
ij_html_new_line_before_first_attribute = never
ij_html_quote_style = double
ij_html_remove_new_line_before_tags = br
ij_html_space_after_tag_name = false
ij_html_space_around_equality_in_attribute = false
ij_html_space_inside_empty_tag = false
ij_html_text_wrap = normal

[{*.yaml, *.yml}]
indent_size = 2
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true

[*.md]
indent_size = 2


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.en.yml
================================================
name: Bug Report
description: File a bug report
labels: [bug]
body:
  - type: checkboxes
    id: preface
    attributes:
      label: Prerequisites
      description: Thank you for taking the time to fill out this issue report! Before we begin, we highly recommend reading through the [Open Source Guides](https://opensource.guide/), which will greatly improve our mutual efficiency.
      options:
        - label: I have searched for related issues in the [issues](https://github.com/halo-dev/halo/issues) list.
          required: true
        - label: "This is an issue with the Halo project itself. If it is not an issue with the project itself(For example: Installation and deployment issues.), it is recommended to submit it in the [Discussions](https://github.com/halo-dev/halo/discussions)."
          required: true
        - label: I have tried disabling all plugins to rule out plugins as the cause of the problem.
          required: true
        - label: If it is an issue with plugins and themes, please submit it in the respective plugin and theme repositories.
          required: true
  - type: markdown
    id: environment
    attributes:
      value: "## Environment"
  - type: textarea
    id: system-information
    attributes:
      label: "System information"
      description: "Access the actuator page of the Console, click the copy button in the upper right corner, and paste the information here."
      placeholder: |
        - External url: https://demo.halo.run
        - Start time: 2024-07-21 14:50
        - Version: 2.x.x
        - Build time: 2024-07-15 18:19
        - Git Commit: 6d4bedd
        - Java: IBM Semeru Runtime Open Edition / ...
        - Database: PostgreSQL / 16.3 ...
        - Operating system: Linux / 5.15.0-88 ...
        - Activated theme: ...
        - Enabled plugins:
            - ...
    validations:
      required: true
  - type: dropdown
    id: operation-method
    validations:
      required: true
    attributes:
      label: "What is the project operation method?"
      options:
        - Docker
        - Docker Compose
        - Fat Jar
        - Source Code
  - type: markdown
    id: details
    attributes:
      value: "## Details"
  - type: textarea
    id: what-happened
    attributes:
      label: "What happened?"
      description: "For ease of management, please do not report multiple unrelated issues under the same issue."
    validations:
      required: true
  - type: textarea
    id: reproduce-steps
    attributes:
      label: "Reproduce Steps"
      description: "If it can be consistently reproduced, please provide detailed steps."
      placeholder: |
        1. Open '...'
        2. Click '...'
  - type: textarea
    id: logs
    attributes:
      label: "Relevant log output"
      description: "Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks."
      render: shell
  - type: textarea
    id: additional-information
    attributes:
      label: "Additional information"
      description: "If you have other information to note, you can fill it in here (screenshots, videos, etc.)."


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.zh.yml
================================================
name: Bug 反馈
description: 提交 Bug 反馈
labels: [bug]
body:
  - type: checkboxes
    id: preface
    attributes:
      label: 前置条件
      description: 感谢你花时间填写此错误报告!在开始之前,我们非常推荐阅读一遍[《开源软件指南》](https://opensource.guide/zh-hans/),这会在很大程度上提高我们彼此的效率。
      options:
        - label: 已经在 [issues](https://github.com/halo-dev/halo/issues) 列表中搜索了相关问题。
          required: true
        - label: 这是 Halo 项目本身存在的问题,如果是非项目本身的问题(如:安装部署问题),建议在 [Discussions](https://github.com/halo-dev/halo/discussions) 提交。
          required: true
        - label: 已经尝试过停用所有的插件,排除是插件导致的问题。
          required: true
        - label: 如果是插件和主题的问题,请在对应的插件和主题仓库提交。
          required: true
  - type: markdown
    id: environment
    attributes:
      value: "## 环境信息"
  - type: textarea
    id: system-information
    attributes:
      label: "系统信息"
      description: "访问 Console 的概览页面,点击右上角的复制按钮,将信息粘贴到此处。"
      placeholder: |
        - 外部访问地址: https://demo.halo.run
        - 启动时间: 2024-07-21 14:50
        - 版本: 2.x.x
        - 构建时间: 2024-07-15 18:19
        - Git Commit: 6d4bedd
        - Java: IBM Semeru Runtime Open Edition / ...
        - 数据库: PostgreSQL / 16.3 ...
        - 操作系统: Linux / 5.15.0-88 ...
        - 已激活主题: ...
        - 已启动插件:
            - ...
    validations:
      required: true
  - type: dropdown
    id: operation-method
    validations:
      required: true
    attributes:
      label: "使用的哪种方式运行?"
      options:
        - Docker
        - Docker Compose
        - Fat Jar
        - Source Code
  - type: markdown
    id: details
    attributes:
      value: "## 详细信息"
  - type: textarea
    id: what-happened
    attributes:
      label: "发生了什么?"
      description: "为了方便我们管理,请不要在同一个 issue 下报告多个不相关的问题。"
    validations:
      required: true
  - type: textarea
    id: reproduce-steps
    attributes:
      label: "复现步骤"
      description: "如果可以稳定复现,请提供详细的步骤。"
      placeholder: |
        1. 打开 '...'
        2. 点击 '...'
  - type: textarea
    id: logs
    attributes:
      label: "相关日志输出"
      description: "请复制并粘贴任何相关的日志输出。这将自动格式化为代码,因此无需反引号。"
      render: shell
  - type: textarea
    id: additional-information
    attributes:
      label: "附加信息"
      description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
  - name: 商业产品反馈
    url: https://github.com/orgs/lxware-dev/discussions
    about: Halo 付费版以及应用市场商业应用的问题,建议优先在这里反馈。
  - name: 对 Halo 有其他问题
    url: https://bbs.halo.run
    about: 如果你对 Halo 有其他想要提问的,欢迎到官方社区进行提问。

================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.en.yml
================================================
name: Feature Request
description: File a feature request
body:
  - type: checkboxes
    id: preface
    attributes:
      label: Prerequisites
      description: Hello! Thank you for submitting a new feature suggestion for Halo. Before we begin, we highly recommend reading through the [Open Source Guides](https://opensource.guide/), which will greatly improve our mutual efficiency.
      options:
        - label: I have searched for related issues in the [Issues](https://github.com/halo-dev/halo/issues) list.
          required: true
        - label: This is a feature related to Halo. If it is not an issue with the project itself, it is recommended to submit it in the [Discussions](https://github.com/halo-dev/halo/discussions).
          required: true
        - label: If it is a feature suggestion for plugins and themes, please submit it in the respective plugin and theme repositories.
          required: true
  - type: markdown
    id: environment
    attributes:
      value: "## Environment"
  - type: input
    id: version
    attributes:
      label: "Your current Halo version"
  - type: markdown
    id: details
    attributes:
      value: "## Details"
  - type: textarea
    id: description
    attributes:
      label: "Describe this feature"
      description: "For ease of management, please do not submit multiple unrelated features under the same issue."
    validations:
      required: true
  - type: textarea
    id: additional-information
    attributes:
      label: "Additional information"
      description: "If you have other information to note, you can fill it in here (screenshots, videos, etc.)."

================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.zh.yml
================================================
name: 新特性建议
description: 提交新特性建议
body:
  - type: checkboxes
    id: preface
    attributes:
      label: 前置条件
      description: 你好!感谢你为 Halo 提交新特性建议。在开始之前,我们非常推荐阅读一遍[《开源软件指南》](https://opensource.guide/zh-hans/),这会在很大程度上提高我们彼此的效率。
      options:
        - label: 已经在 [Issues](https://github.com/halo-dev/halo/issues) 列表中搜索了相关问题。
          required: true
        - label: 这是和 Halo 相关的特性,如果是非项目本身的问题,建议在 [Discussions](https://github.com/halo-dev/halo/discussions) 提交。
          required: true
        - label: 如果是插件和主题特性建议,请在对应的插件和主题仓库提交。
          required: true
  - type: markdown
    id: environment
    attributes:
      value: "## 环境信息"
  - type: input
    id: version
    attributes:
      label: "你当前使用的版本"
  - type: markdown
    id: details
    attributes:
      value: "## 详细信息"
  - type: textarea
    id: description
    attributes:
      label: "描述一下此特性"
      description: "为了方便我们管理,请不要在同一个 issue 下提交多个没有相关性的特性。"
    validations:
      required: true
  - type: textarea
    id: additional-information
    attributes:
      label: "附加信息"
      description: "如果你还有其他需要提供的信息,可以在这里填写(可以提供截图、视频等)。"

================================================
FILE: .github/actions/docker-buildx-push/action.yaml
================================================
name: "Docker buildx and push"
description: "Buildx and push the Docker image."

inputs:
  ghcr-token:
    description: Token of current GitHub account in GitHub container registry.
    required: false
    default: ""
  dockerhub-user:
    description: "User name for the DockerHub account"
    required: false
    default: ""
  dockerhub-token:
    description: Token for the DockerHub account
    required: false
    default: ""
  f2c-registry-user:
    description: "User name of Fit2Cloud Docker Registry."
    required: false
    default: ""
  f2c-registry-token:
    description: "Token of Fit2Cloud Docker Registry."
    required: false
    default: ""
  push:
    description: Should push the docker image or not.
    required: false
    default: "false"
  platforms:
    description: Target platforms for building image
    required: false
    default: "linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x"
  image-name:
    description: The basic name of docker.
    required: false
    default: "halo"

runs:
  using: "composite"
  steps:
    - name: Docker meta for Halo
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: |
          ghcr.io/${{ github.repository_owner }}/${{ inputs.image-name }}
          halohub/${{ inputs.image-name }}
          registry.fit2cloud.com/halo/${{ inputs.image-name }}
        tags: |
          type=schedule,pattern=nightly-{{date 'YYYYMMDD'}},enabled=${{ github.event_name == 'schedule' }}
          type=ref,event=branch,enabled=${{ github.event_name == 'push' }}
          type=ref,event=pr,enabled=${{ github.event_name == 'pull_request' }}
          type=semver,pattern={{major}}
          type=semver,pattern={{major}}.{{minor}}
          type=semver,pattern={{ version }}
          type=sha,enabled=${{ github.event_name == 'push' }}
        flavor: |
          latest=false
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    - name: Login to GHCR
      uses: docker/login-action@v3
      if: inputs.ghcr-token != '' && github.event_name != 'pull_request'
      with:
        registry: ghcr.io
        username: ${{ github.repository_owner }}
        password: ${{ inputs.ghcr-token }}
    - name: Login to DockerHub
      if: inputs.dockerhub-token != '' && github.event_name != 'pull_request'
      uses: docker/login-action@v3
      with:
        username: ${{ inputs.dockerhub-user }}
        password: ${{ inputs.dockerhub-token }}
    - name: Login to Fit2Cloud Docker Registry
      if: inputs.f2c-registry-token != '' && github.event_name != 'pull_request'
      uses: docker/login-action@v3
      with:
        registry: registry.fit2cloud.com
        username: ${{ inputs.f2c-registry-user }}
        password: ${{ inputs.f2c-registry-token }}
    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        context: .
        file: ./Dockerfile
        platforms: ${{ inputs.platforms }}
        labels: ${{ steps.meta.outputs.labels }}
        tags: ${{ steps.meta.outputs.tags }}
        push: ${{ (inputs.ghcr-token != '' || inputs.dockerhub-token != '') && inputs.push == 'true' }}


================================================
FILE: .github/actions/setup-env/action.yaml
================================================
name: Setup Environment
description: Setup environment to check and build Halo, including console and core projects.

inputs:
  node-version:
    description: Node.js version.
    required: false
    default: "24"

  pnpm-version:
    description: pnpm version.
    required: false
    default: "10"

  java-version:
    description: Java version.
    required: false
    default: "21"

runs:
  using: "composite"
  steps:
    - uses: pnpm/action-setup@v3
      name: Setup pnpm
      with:
        version: ${{ inputs.pnpm-version }}

    - name: Set up Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        cache: "pnpm"
        cache-dependency-path: "ui/pnpm-lock.yaml"

    - name: Setup JDK
      uses: actions/setup-java@v4
      with:
        distribution: "temurin"
        cache: "gradle"
        java-version: ${{ inputs.java-version }}


================================================
FILE: .github/pull_request_template.md
================================================
<!--  Thanks for sending a pull request!  Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
4. 如果你的 PR 使用了 LLM 生成代码,请在 PR 中添加相应的说明,我们不反对使用 LLM 辅助开发,但希望你能够先对生成的代码进行审查。
5. If your PR uses LLM generated code, please add a corresponding description in the PR, we do not oppose using LLM to assist development, but we hope you can review the generated code first.
-->

#### What type of PR is this?

<!--
添加其中一个类别:
Add one of the following kinds:

/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind improvement

适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:

/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->

#### What this PR does / why we need it:

#### Which issue(s) this PR fixes:

<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.

用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?

<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->

```release-note
```


================================================
FILE: .github/workflows/halo.yaml
================================================
name: Halo Workflow

on:
  pull_request:
    branches:
      - main
      - release-*
    paths:
      - "**"
      - "!**.md"
  push:
    branches:
      - main
      - release-*
    paths:
      - "**"
      - "!**.md"
  release:
    types:
      - published

concurrency: 
  group: ${{github.workflow}} - ${{github.ref}}
  cancel-in-progress: true

jobs:
  test:
    if: github.event_name == 'pull_request' || github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Check Halo
        run: ./gradlew clean check --configuration-cache --configuration-cache-problems=warn
      - name: Upload coverage reports to Codecov
        if: github.repository == 'halo-dev/halo'
        uses: codecov/codecov-action@v4

  build:
    runs-on: ubuntu-latest
    if: always() && (needs.test.result == 'skipped' || needs.test.result == 'success')
    needs: test
    steps:
      - uses: actions/checkout@v4
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Reset version of Halo
        if: github.event_name == 'release'
        shell: bash
        run: |
          # Set the version with tag name when releasing
          version=${{ github.event.release.tag_name }}
          version=${version#v}
          sed -i "s/version=.*-SNAPSHOT$/version=$version/1" gradle.properties
      - name: Build Halo
        run: ./gradlew clean downloadPluginPresets build -x check --configuration-cache --configuration-cache-problems=warn
      - name: Upload Artifacts
        if: github.repository == 'halo-dev/halo'
        uses: actions/upload-artifact@v4
        with:
          name: halo-artifacts
          path: application/build/libs
          retention-days: 1

  github-release:
    runs-on: ubuntu-latest
    if: always() && needs.build.result == 'success' && github.event_name == 'release'
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Download Artifacts
        uses: actions/download-artifact@v4
        with:
          name: halo-artifacts
          path: application/build/libs
      - name: Upload Artifacts
        if: github.repository == 'halo-dev/halo'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh release upload ${{ github.event.release.tag_name }} application/build/libs/*

  build-and-publish-container-image-with-buildpacks:
    needs: build
    if: always() && needs.build.result == 'success' && (github.event_name == 'push' || github.event_name == 'release')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Reset version of Halo
        if: github.event_name == 'release'
        shell: bash
        run: |
          # Set the version with tag name when releasing
          version=${{ github.event.release.tag_name }}
          version=${version#v}
          sed -i "s/version=.*-SNAPSHOT$/version=$version/1" gradle.properties
      - name: Publish To Container Registries
        env:
          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
          DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }}
          F2C_USERNAME: ${{ secrets.F2C_REGISTRY_USER }}
          F2C_TOKEN: ${{ secrets.F2C_REGISTRY_TOKEN }}
          GHCR_USERNAME: ${{ github.repository_owner }}
          GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run:
          ./gradlew publishToAllRegistries -Prelease=${{ github.event_name == 'release' && 'true' || 'false' }}

  docker-build-and-push:
    if: always() && needs.build.result == 'success' && (github.event_name == 'push' || github.event_name == 'release')
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Download Artifacts
        uses: actions/download-artifact@v4
        with:
          name: halo-artifacts
          path: application/build/libs
      - name: Docker Buildx and Push
        uses: ./.github/actions/docker-buildx-push
        with:
          image-name: ${{ github.event_name == 'release' && 'halo' || 'halo-dev' }}
          ghcr-token: ${{ secrets.GITHUB_TOKEN }}
          dockerhub-user: ${{ secrets.DOCKER_USERNAME }}
          dockerhub-token: ${{ secrets.DOCKER_TOKEN }}
          f2c-registry-user: ${{ secrets.F2C_REGISTRY_USER }}
          f2c-registry-token: ${{ secrets.F2C_REGISTRY_TOKEN }}
          push: true
          platforms: linux/amd64,linux/arm64/v8,linux/ppc64le,linux/s390x

  e2e-test:
    if: always() && needs.build.result == 'success' && (github.event_name == 'pull_request' || github.event_name == 'push')
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/checkout@v4
      - name: Download Artifacts
        uses: actions/download-artifact@v4
        with:
          name: halo-artifacts
          path: application/build/libs
      - name: Docker Build
        uses: docker/build-push-action@v5
        with:
          tags: ghcr.io/halo-dev/halo-dev:main
          push: false
          context: .
      - name: E2E Testing
        continue-on-error: true
        run: |
          sudo curl -L https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
          sudo chmod u+x /usr/local/bin/docker-compose
          cd e2e && make all


================================================
FILE: .github/workflows/openapi-check.yaml
================================================
name: OpenAPI Check

on:
  pull_request:
    branches:
      - main
      - release-*
    paths:
      - 'application/src/**'
      - 'api/src/**'
      - 'api-docs/openapi/**'
      - 'ui/packages/api-client/**'
  push:
    branches:
      - main
      - release-*
    paths:
      - 'application/src/**'
      - 'api/src/**'
      - 'api-docs/openapi/**'
      - 'ui/packages/api-client/**'

concurrency:
  group: ${{github.workflow}} - ${{github.ref}}
  cancel-in-progress: true

jobs:
  openapi-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - name: Install UI dependencies
        run: ./gradlew pnpmInstall
      - name: Regenerate OpenAPI docs
        run: ./gradlew generateOpenApiDocs --no-configuration-cache
      - name: Regenerate api-client
        run: cd ui && pnpm run api-client:gen
      - name: Verify OpenAPI docs and api-client are in sync
        run: |
          if ! git diff --exit-code -- api-docs/openapi ui/packages/api-client/src; then
            echo "::error::OpenAPI docs or api-client generated code is out of sync with the current API. Run './gradlew generateOpenApiDocs --no-configuration-cache' and 'cd ui && pnpm run api-client:gen', then commit the changes under api-docs/openapi and ui/packages/api-client/src."
            git diff --stat api-docs/openapi ui/packages/api-client/src
            exit 1
          fi


================================================
FILE: .github/workflows/packages-preview-release.yaml
================================================
name: "Packages preview release"
on:
  push:
    paths:
      - "ui/packages/**"
    branches:
      - main
  pull_request:
    paths:
      - "ui/packages/**"
    branches:
      - main
jobs:
  packages-preview-release:
    runs-on: ubuntu-latest
    if: github.repository == 'halo-dev/halo'
    steps:
      - uses: actions/checkout@v4
      - name: Setup Environment
        uses: ./.github/actions/setup-env

      - name: Install Dependencies
        run: ./gradlew pnpmInstall

      - name: Build Packages
        run: cd ui && pnpm build:packages

      - name: Release
        run: cd ui && pnpx pkg-pr-new publish --compact --pnpm './packages/*'


================================================
FILE: .github/workflows/release-ui-packages.yaml
================================================
name: Release UI Packages

on:
  release:
    types:
      - published

permissions:
  contents: write
  id-token: write

jobs:
  release:
    runs-on: ubuntu-latest
    if: github.repository == 'halo-dev/halo' && github.event.release.prerelease == false
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Environment
        uses: ./.github/actions/setup-env
      - run: ./gradlew pnpmInstall
      - name: Publish to NPM
        run: cd ui && pnpm run publish:packages


================================================
FILE: .github/workflows/stale-issues.yaml
================================================
name: Close Stale Issues

on:
  schedule:
    - cron: "30 1 * * *"
  workflow_dispatch:

permissions:
  issues: write

jobs:
  stale:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/stale@v10
        with:
          stale-issue-message: |
            This issue has been automatically marked as stale because it has not had recent activity.
            It will be closed if no further activity occurs within the next 2 days.
            If you believe this issue is still relevant, please provide the requested information.
          close-issue-message: |
            This issue has been automatically closed due to inactivity.
            If you have the requested information, feel free to reopen it or create a new issue.
          days-before-issue-stale: 60
          days-before-issue-close: 2
          days-before-pr-stale: -1
          days-before-pr-close: -1
          stale-issue-label: "lifecycle/stale"
          any-of-issue-labels: "triage/needs-information,priority/awaiting-more-evidence,help wanted"
          operations-per-run: 100
          ascending: true


================================================
FILE: .gitignore
================================================
### Maven
target/
logs/
!.mvn/wrapper/maven-wrapper.jar

### Gradle
.gradle
build/
out/
!gradle/wrapper/gradle-wrapper.jar
bin/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
log/

### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/

### Mac
.DS_Store
*/.DS_Store

### VS Code ###
*.project
*.factorypath

### Compiled class file
*.class

### Log file
*.log

### BlueJ files
*.ctxt

### Mobile Tools for Java (J2ME)
.mtj.tmp/

### Package Files
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

### VSCode
.vscode
!.vscode/settings.json
!.vscode/extensions.json

### Local file
application-local.yml
application-local.yaml
application-local.properties

### Zip file for test
!application/src/test/resources/themes/*.zip
!application/src/main/resources/themes/*.zip
application/src/main/resources/console/
application/src/main/resources/uc/
application/src/main/resources/presets/

### Node
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

### Frontend
dist
coverage
*.local

### Cypress
/cypress/videos/
/cypress/screenshots/

### Frontend build
!src/build
storybook-static
tsconfig.tsbuildinfo
.tgz

================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our
community include:

* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
  and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
  overall community

Examples of unacceptable behavior include:

* The use of sexualized language or imagery, and sexual attention or
  advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
  address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
  professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
hi@halo.run.
All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series
of actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior,  harassment of an
individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.

Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).

[homepage]: https://www.contributor-covenant.org

For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guide

Thank you for your interest in contributing to Halo.

This document explains the recommended workflow for submitting high-quality contributions, including code, tests, and documentation updates.

## Before You Start

- For new features or major behavior changes, please open an issue first so we can align on scope and design.
- For clear bug fixes, you can submit a pull request directly.
- If your report is not about the core project itself (for example, deployment questions), please use Discussions instead of Issues.

## Development Environment

This repository mainly contains:

- Backend and platform modules built with Gradle.
- Frontend code in `ui`, managed with `pnpm` workspaces.

### Prerequisites

- Git
- JDK (version compatible with the project build)
- Node.js and `pnpm` (see `ui/package.json` for the current package manager)
- Docker / Docker Compose (required for e2e scenarios)

## Contribution Workflow

### 1. Fork and Clone

Fork this repository, then clone your fork:

```bash
git clone https://github.com/{YOUR_USERNAME}/{REPOSITORY}.git
cd {REPOSITORY}
```

### 2. Add Upstream Remote

```bash
git remote add upstream https://github.com/halo-dev/halo.git
git fetch upstream
```

### 3. Create a Branch

Use a focused branch name that reflects your change:

```bash
git checkout -b feat/short-description
```

### 4. Implement and Validate

Run relevant checks before opening a PR.

Backend and general checks:

```bash
./gradlew clean check
```

Frontend checks (in `ui`):

```bash
cd ui
pnpm install
pnpm build:packages
pnpm lint
pnpm typecheck
pnpm test:unit
```

### 5. Commit and Push

```bash
git push origin <your-branch>
```

### 6. Open a Pull Request

Open a PR from your branch to `main` and fill out the PR template carefully:

- Describe what changed and why.
- Link related issues (for example, `Fixes #123`).
- Add release note content or `NONE` when no user-facing change is introduced.
- Add proper `/kind` labels as requested in the template.

## AI-Assisted Contribution Policy

AI-assisted development is not prohibited, including code generation and refactoring support.

However, you are fully responsible for any code in your PR.

If you used AI tools, please follow these rules:

- Review all AI-generated content before submission.
- Verify correctness, security, performance, and maintainability.
- Ensure generated code follows project conventions and architecture.
- Remove low-quality or redundant generated code.
- Mention AI assistance in your PR description when AI materially contributed to the final changes.

In short: AI assistance is allowed, but unreviewed AI output is not acceptable.

## Testing Expectations

- Add or update tests whenever you change behavior.
- If you add or modify APIs, please include corresponding e2e test cases.
- See `e2e/README.md` for e2e workflow and local execution details.

## Coding Standards

- Follow the project coding style guide: <https://docs.halo.run/developer-guide/core/code-style>
- Keep changes focused and avoid unrelated refactors in the same PR.
- Run formatters and linters before pushing.

## Keep Your Fork Updated

Before starting new work, sync your branch with upstream:

```bash
git fetch upstream
git checkout main
git merge upstream/main
git push origin main
```

## Need Help?

- Open an issue for confirmed bugs and feature proposals.
- Use Discussions for general questions and usage/deployment topics.

Thanks again for helping improve Halo.


================================================
FILE: Dockerfile
================================================
FROM eclipse-temurin:21-jre as builder

WORKDIR application
ARG JAR_FILE=application/build/libs/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

################################

FROM ibm-semeru-runtimes:open-21-jre
LABEL maintainer="johnniang <johnniang@foxmail.com>"
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./

ENV JVM_OPTS="" \
    HALO_WORK_DIR="/root/.halo2" \
    SPRING_CONFIG_LOCATION="optional:classpath:/;optional:file:/root/.halo2/" \
    TZ=Asia/Shanghai

RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime \
    && echo $TZ > /etc/timezone

Expose 8090

ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} org.springframework.boot.loader.launch.JarLauncher ${0} ${@}"]


================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 3, 29 June 2007

 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The GNU General Public License is a free, copyleft license for
software and other kinds of works.

  The licenses for most software and other practical works are designed
to take away your freedom to share and change the works.  By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.  We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors.  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.

  To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights.  Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received.  You must make sure that they, too, receive
or can get the source code.  And you must show them these terms so they
know their rights.

  Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.

  For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software.  For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.

  Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so.  This is fundamentally incompatible with the aim of
protecting users' freedom to change the software.  The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable.  Therefore, we
have designed this version of the GPL to prohibit the practice for those
products.  If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.

  Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary.  To prevent this, the GPL assures that
patents cannot be used to render the program non-free.

  The precise terms and conditions for copying, distribution and
modification follow.

                       TERMS AND CONDITIONS

  0. Definitions.

  "This License" refers to version 3 of the GNU General Public License.

  "Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.

  "The Program" refers to any copyrightable work licensed under this
License.  Each licensee is addressed as "you".  "Licensees" and
"recipients" may be individuals or organizations.

  To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy.  The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.

  A "covered work" means either the unmodified Program or a work based
on the Program.

  To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy.  Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.

  To "convey" a work means any kind of propagation that enables other
parties to make or receive copies.  Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.

  An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License.  If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.

  1. Source Code.

  The "source code" for a work means the preferred form of the work
for making modifications to it.  "Object code" means any non-source
form of a work.

  A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.

  The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form.  A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.

  The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities.  However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work.  For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.

  The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.

  The Corresponding Source for a work in source code form is that
same work.

  2. Basic Permissions.

  All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met.  This License explicitly affirms your unlimited
permission to run the unmodified Program.  The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work.  This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.

  You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force.  You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright.  Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.

  Conveying under any other circumstances is permitted solely under
the conditions stated below.  Sublicensing is not allowed; section 10
makes it unnecessary.

  3. Protecting Users' Legal Rights From Anti-Circumvention Law.

  No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.

  When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.

  4. Conveying Verbatim Copies.

  You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.

  You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.

  5. Conveying Modified Source Versions.

  You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:

    a) The work must carry prominent notices stating that you modified
    it, and giving a relevant date.

    b) The work must carry prominent notices stating that it is
    released under this License and any conditions added under section
    7.  This requirement modifies the requirement in section 4 to
    "keep intact all notices".

    c) You must license the entire work, as a whole, under this
    License to anyone who comes into possession of a copy.  This
    License will therefore apply, along with any applicable section 7
    additional terms, to the whole of the work, and all its parts,
    regardless of how they are packaged.  This License gives no
    permission to license the work in any other way, but it does not
    invalidate such permission if you have separately received it.

    d) If the work has interactive user interfaces, each must display
    Appropriate Legal Notices; however, if the Program has interactive
    interfaces that do not display Appropriate Legal Notices, your
    work need not make them do so.

  A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit.  Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.

  6. Conveying Non-Source Forms.

  You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:

    a) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by the
    Corresponding Source fixed on a durable physical medium
    customarily used for software interchange.

    b) Convey the object code in, or embodied in, a physical product
    (including a physical distribution medium), accompanied by a
    written offer, valid for at least three years and valid for as
    long as you offer spare parts or customer support for that product
    model, to give anyone who possesses the object code either (1) a
    copy of the Corresponding Source for all the software in the
    product that is covered by this License, on a durable physical
    medium customarily used for software interchange, for a price no
    more than your reasonable cost of physically performing this
    conveying of source, or (2) access to copy the
    Corresponding Source from a network server at no charge.

    c) Convey individual copies of the object code with a copy of the
    written offer to provide the Corresponding Source.  This
    alternative is allowed only occasionally and noncommercially, and
    only if you received the object code with such an offer, in accord
    with subsection 6b.

    d) Convey the object code by offering access from a designated
    place (gratis or for a charge), and offer equivalent access to the
    Corresponding Source in the same way through the same place at no
    further charge.  You need not require recipients to copy the
    Corresponding Source along with the object code.  If the place to
    copy the object code is a network server, the Corresponding Source
    may be on a different server (operated by you or a third party)
    that supports equivalent copying facilities, provided you maintain
    clear directions next to the object code saying where to find the
    Corresponding Source.  Regardless of what server hosts the
    Corresponding Source, you remain obligated to ensure that it is
    available for as long as needed to satisfy these requirements.

    e) Convey the object code using peer-to-peer transmission, provided
    you inform other peers where the object code and Corresponding
    Source of the work are being offered to the general public at no
    charge under subsection 6d.

  A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.

  A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling.  In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage.  For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product.  A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.

  "Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source.  The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.

  If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information.  But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).

  The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed.  Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.

  Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.

  7. Additional Terms.

  "Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law.  If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.

  When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it.  (Additional permissions may be written to require their own
removal in certain cases when you modify the work.)  You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.

  Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:

    a) Disclaiming warranty or limiting liability differently from the
    terms of sections 15 and 16 of this License; or

    b) Requiring preservation of specified reasonable legal notices or
    author attributions in that material or in the Appropriate Legal
    Notices displayed by works containing it; or

    c) Prohibiting misrepresentation of the origin of that material, or
    requiring that modified versions of such material be marked in
    reasonable ways as different from the original version; or

    d) Limiting the use for publicity purposes of names of licensors or
    authors of the material; or

    e) Declining to grant rights under trademark law for use of some
    trade names, trademarks, or service marks; or

    f) Requiring indemnification of licensors and authors of that
    material by anyone who conveys the material (or modified versions of
    it) with contractual assumptions of liability to the recipient, for
    any liability that these contractual assumptions directly impose on
    those licensors and authors.

  All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10.  If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term.  If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.

  If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.

  Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.

  8. Termination.

  You may not propagate or modify a covered work except as expressly
provided under this License.  Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).

  However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.

  Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.

  Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License.  If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.

  9. Acceptance Not Required for Having Copies.

  You are not required to accept this License in order to receive or
run a copy of the Program.  Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance.  However,
nothing other than this License grants you permission to propagate or
modify any covered work.  These actions infringe copyright if you do
not accept this License.  Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.

  10. Automatic Licensing of Downstream Recipients.

  Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License.  You are not responsible
for enforcing compliance by third parties with this License.

  An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations.  If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.

  You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License.  For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.

  11. Patents.

  A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based.  The
work thus licensed is called the contributor's "contributor version".

  A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version.  For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.

  Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.

  In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement).  To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.

  If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients.  "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.

  If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.

  A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License.  You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.

  Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.

  12. No Surrender of Others' Freedom.

  If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all.  For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.

  13. Use with the GNU Affero General Public License.

  Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work.  The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.

  14. Revised Versions of this License.

  The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

  Each version is given a distinguishing version number.  If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation.  If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.

  If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.

  Later license versions may give you additional or different
permissions.  However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.

  15. Disclaimer of Warranty.

  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. Limitation of Liability.

  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.

  17. Interpretation of Sections 15 and 16.

  If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

  If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

    <program>  Copyright (C) <year>  <name of author>
    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".

  You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.

  The GNU General Public License does not permit incorporating your program
into proprietary programs.  If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.  But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


================================================
FILE: OWNERS
================================================
approvers:
- ruibaby
- guqing
- JohnNiang
- LIlGG


================================================
FILE: README.md
================================================
<p align="center">
    <a href="https://www.halo.run" target="_blank" rel="noopener noreferrer">
        <img width="100" src="https://www.halo.run/logo" alt="Halo logo" />
    </a>
</p>

<p align="center"><b>Halo</b> [ˈheɪloʊ],强大易用的开源建站工具。</p>
<p align="center">
<a href="https://github.com/halo-dev/halo/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/halo-dev/halo.svg?style=flat-square&include_prereleases" /></a>
<a href="https://hub.docker.com/r/halohub/halo"><img alt="Docker pulls" src="https://img.shields.io/docker/pulls/halohub/halo?style=flat-square" /></a>
<a href="https://github.com/halo-dev/halo/commits"><img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/halo-dev/halo.svg?style=flat-square" /></a>
<a href="https://github.com/halo-dev/halo/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/halo-dev/halo/halo.yaml?branch=main&style=flat-square" /></a>
<a href="https://codecov.io/gh/halo-dev/halo"><img alt="Codecov percentage" src="https://img.shields.io/codecov/c/github/halo-dev/halo/main?style=flat-square&token=YsRUg9fall"/></a>
<a href="https://gitcode.com/feizhiyun/Halo"><img src="https://gitcode.com/feizhiyun/Halo/star/badge.svg" alt="GitCode Stars"></a>
<a href="https://www.producthunt.com/posts/halo-6b401e75-bb58-4dff-9fe9-2ada3323c874?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-halo&#0045;6b401e75&#0045;bb58&#0045;4dff&#0045;9fe9&#0045;2ada3323c874" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=407442&theme=light" alt="Halo - Powerful&#0032;and&#0032;easy&#0045;to&#0045;use&#0032;Open&#0045;Source&#0032;website&#0032;building&#0032;tool | Product Hunt" style="height: 20px;" height="20px" /></a>
<br />
<a href="https://www.halo.run">官网</a>
<a href="https://docs.halo.run">文档</a>
<a href="https://bbs.halo.run">社区</a>
<a href="https://gitee.com/halo-dev">Gitee</a>
<a href="https://t.me/halo_dev">Telegram 频道</a>
</p>

[![Watch the video](https://www.halo.run/upload/halo-github-screenshot.png)](https://www.bilibili.com/video/BV15x4y1U7RU/?share_source=copy_web&vd_source=0ab6cf86ca512a363f04f18b86f55b86)

------------------------------

## 快速开始

如果你的设备有 Docker 环境,可以使用以下命令快速启动一个 Halo 的体验环境:

```bash
docker run -d --name halo -p 8090:8090 -v ~/.halo2:/root/.halo2 halohub/halo:2.22
```

或者点击下方按钮使用 [Gitpod](https://gitpod.io/) 或 [ClawCloud Run](https://template.us-west-1.run.claw.cloud/deploy?templateName=halo) 启动一个体验环境:

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/halo-sigs/gitpod-demo)

[![Run on ClawCloud](https://raw.githubusercontent.com/ClawCloud/Run-Template/refs/heads/main/Run-on-ClawCloud.svg)](https://template.us-west-1.run.claw.cloud/deploy?templateName=halo)

**以上方式仅作为体验使用,推荐使用开源 Linux 服务器运维管理面板 [1Panel](https://github.com/1Panel-dev/1Panel) 进行部署([查看文档](https://docs.halo.run/getting-started/install/1panel)),轻松搞定反向代理、SSL 证书及升级备份任务。更多部署方式,请[查看文档](https://docs.halo.run/category/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97)。**

## 在线体验

- 环境地址:<https://demo.halocms.site>
- 后台地址:<https://demo.halocms.site/console>
- 用户名:`demo`
- 密码:`P@ssw0rd123..`

## 付费版

相比于社区版,Halo 付费版为用户提供了大量增强功能及技术支持服务,增强功能包括商城、短信验证码注册登录、全站私有化、LDAP 登录、三方账号登录及自定义 Logo 等。 [点击查看付费版详细介绍](https://www.lxware.cn/halo)。

## 生态

可访问 [官方应用市场](https://www.halo.run/store/apps) 或 [awesome-halo 仓库](https://github.com/halo-sigs/awesome-halo) 查看适用于 Halo 2.x 的主题和插件。

## 许可证

[![license](https://img.shields.io/github/license/halo-dev/halo.svg?style=flat-square)](https://github.com/halo-dev/halo/blob/master/LICENSE)

Halo 使用 GPL-v3.0 协议开源,请遵守开源协议。

## 贡献

参考 [CONTRIBUTING](https://github.com/halo-dev/halo/blob/main/CONTRIBUTING.md)。

<a href="https://github.com/halo-dev/halo/graphs/contributors"><img src="https://opencollective.com/halo/contributors.svg?width=890&button=false" /></a>

## 状态

![Repobeats analytics](https://repobeats.axiom.co/api/embed/ad008b2151c22e7cf734d2688befaa795d593b95.svg "Repobeats analytics image")


================================================
FILE: SECURITY.md
================================================
# Security Policy

## Supported Versions

Halo currently supports the versions listed below, where as:

- :white_check_mark: indicates an active development roadmap, is therefore maintaining, and **will** receive Security
  Vulnerability Report.
- :x: indicates such version has already deprecated and **will not** be receiving Security Vulnerability Report.

| Version | Supported          |
| ------- | ------------------ |
| 0.x     | :x:                |
| 1.x     | :x:                |
| 2.x     | :white_check_mark: |

## Reporting a Vulnerability

We first appreciate and are very thankful that you've found a vulnerability issue in Halo! By disclosing such issue to
Halo development team you are helping Halo to become a much more safer project than before! ;)

To protect the existing users of Halo, we kindly ask you to not disclose the vulnerability to anyone except the Halo
development team before a fix has been rolled out.

To Report a Vulnerability, please complete the form below, and send such report by email to `hi@halo.run`.

```
Vulnerability has been observed in...
  - Docker? [n/y]: 
    if yes for the question above,
    - `docker -v`: 
    - `docker images halohub/halo`: 
  
  - by `java -jar halo.jar`? [n/y]: 
    if yes for the question above,
    - `uname -a`: 
    - `java -version`: 
 
- Affected by Halo version(s) [e.g. v2.4.0]: 
- Vulnerability self-scoring [1-10]: 
- Would you like to be attributed? (Whether you agree us to appreciate you by putting your name in the CHANGELOG of the next fix release) [n/y]: 
```


================================================
FILE: api/build.gradle
================================================
plugins {
    id 'checkstyle'
    id 'java-library'
    id 'halo.publish'
    id 'jacoco'
    alias(libs.plugins.lombok)
    alias(libs.plugins.versions)
}

group = 'run.halo.app'
description = 'API of halo project, connecting by other projects.'

tasks.withType(JavaCompile).configureEach {
    options.release = 21
    options.encoding = 'UTF-8'
}

tasks.withType(Javadoc).configureEach {
    options.encoding = 'UTF-8'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
    withJavadocJar()
    withSourcesJar()
}

checkstyle {
    toolVersion = libs.versions.checkstyle.get()
    showViolations = false
    ignoreFailures = false
}

jar {
    manifest {
        attributes(
                'Implementation-Title': project.name,
                'Implementation-Version': project.version,
                'Implementation-Vendor': 'Halo Project',
        )
    }
}

repositories {
    mavenCentral()
}

dependencies {
    api platform(project(':platform:application'))
    annotationProcessor platform(project(':platform:application'))

    api 'org.springframework.boot:spring-boot-starter-actuator'
    api 'org.springframework.boot:spring-boot-starter-mail'
    api 'org.springframework.boot:spring-boot-starter-thymeleaf'
    api 'org.springframework.boot:spring-boot-starter-webflux'
    api 'org.springframework.boot:spring-boot-starter-validation'
    api 'org.springframework.boot:spring-boot-starter-data-r2dbc'
    api 'org.springframework.session:spring-session-core'
    api 'org.springframework.boot:spring-boot-jackson2'
    api 'org.springframework.boot:spring-boot-integration'
    api 'org.springframework.boot:spring-boot-session'

    // Spring Security
    api 'org.springframework.boot:spring-boot-starter-security'
    api 'org.springframework.security:spring-security-oauth2-jose'
    api 'org.springframework.security:spring-security-oauth2-client'
    api 'org.springframework.security:spring-security-oauth2-resource-server'

    api 'io.micrometer:context-propagation'

    // Cache
    api "org.springframework.boot:spring-boot-starter-cache"
    api "com.github.ben-manes.caffeine:caffeine"

    api "org.springdoc:springdoc-openapi-starter-webflux-ui"
    api 'org.openapi4j:openapi-schema-validator'
    api "net.bytebuddy:byte-buddy"
    api "org.bouncycastle:bcpkix-jdk18on"

    // Apache Lucene
    api "org.apache.lucene:lucene-core"
    api "org.apache.lucene:lucene-queryparser"
    api "org.apache.lucene:lucene-highlighter"
    api "org.apache.lucene:lucene-backward-codecs"
    api 'org.apache.lucene:lucene-analysis-common'

    api "org.apache.commons:commons-lang3"
    api "io.seruco.encoding:base62"
    api "org.pf4j:pf4j"
    api "com.google.guava:guava"
    api "org.jsoup:jsoup"
    api "io.github.java-diff-utils:java-diff-utils"
    api "org.springframework.integration:spring-integration-core"
    api "com.github.java-json-tools:json-patch"
    api "org.thymeleaf.extras:thymeleaf-extras-springsecurity6"
    api 'org.apache.tika:tika-core'
    api 'net.coobird:thumbnailator'

    api "io.github.resilience4j:resilience4j-spring-boot3"
    api "io.github.resilience4j:resilience4j-reactor"

    api "com.j256.two-factor-auth:two-factor-auth"

    runtimeOnly 'io.r2dbc:r2dbc-h2'
    runtimeOnly 'org.postgresql:postgresql'
    runtimeOnly 'org.postgresql:r2dbc-postgresql'
    runtimeOnly 'org.mariadb:r2dbc-mariadb'
    runtimeOnly 'io.asyncer:r2dbc-mysql'
    runtimeOnly 'com.github.therapi:therapi-runtime-javadoc'

    annotationProcessor "com.github.therapi:therapi-runtime-javadoc-scribe"

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
    testImplementation 'io.projectreactor:reactor-test'

    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

publishing {
    publications.named('mavenJava', MavenPublication) {
        from components.java
        pom {
            name = 'API library'
            description = "$project.description"
        }
    }
}

tasks.named('test') {
    useJUnitPlatform()
    finalizedBy jacocoTestReport
}

tasks.named('jacocoTestReport') {
    reports {
        xml.required = true
        html.required = false
    }
}

tasks.named('uploadBundle') {
    mustRunAfter project(':platform:application').tasks.named('uploadBundle')
}


================================================
FILE: api/src/main/java/run/halo/app/content/ContentWrapper.java
================================================
package run.halo.app.content;

import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;
import run.halo.app.core.extension.content.Snapshot;

/**
 * @author guqing
 * @since 2.0.0
 */
@Data
@Builder
public class ContentWrapper {
    private String snapshotName;
    private String raw;
    private String content;
    private String rawType;

    public static ContentWrapper patchSnapshot(Snapshot patchSnapshot, Snapshot baseSnapshot) {
        Assert.notNull(baseSnapshot, "The baseSnapshot must not be null.");
        String baseSnapshotName = baseSnapshot.getMetadata().getName();
        if (StringUtils.equals(patchSnapshot.getMetadata().getName(), baseSnapshotName)) {
            return ContentWrapper.builder()
                .snapshotName(patchSnapshot.getMetadata().getName())
                .raw(patchSnapshot.getSpec().getRawPatch())
                .content(patchSnapshot.getSpec().getContentPatch())
                .rawType(patchSnapshot.getSpec().getRawType())
                .build();
        }
        String patchedContent = PatchUtils.applyPatch(baseSnapshot.getSpec().getContentPatch(),
            patchSnapshot.getSpec().getContentPatch());
        String patchedRaw = PatchUtils.applyPatch(baseSnapshot.getSpec().getRawPatch(),
            patchSnapshot.getSpec().getRawPatch());
        return ContentWrapper.builder()
            .snapshotName(patchSnapshot.getMetadata().getName())
            .raw(patchedRaw)
            .content(patchedContent)
            .rawType(patchSnapshot.getSpec().getRawType())
            .build();
    }
}


================================================
FILE: api/src/main/java/run/halo/app/content/ExcerptGenerator.java
================================================
package run.halo.app.content;

import java.util.Set;
import lombok.Data;
import lombok.experimental.Accessors;
import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;

public interface ExcerptGenerator extends ExtensionPoint {

    Mono<String> generate(ExcerptGenerator.Context context);

    @Data
    @Accessors(chain = true)
    class Context {
        private String raw;
        /**
         * html content.
         */
        private String content;

        private String rawType;
        /**
         * keywords in the content to help the excerpt generation more accurate.
         */
        private Set<String> keywords;
        /**
         * Max length of the generated excerpt.
         */
        private int maxLength;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/content/PatchUtils.java
================================================
package run.halo.app.content;

import com.fasterxml.jackson.core.type.TypeReference;
import com.github.difflib.DiffUtils;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
import com.google.common.base.Splitter;
import java.util.Collections;
import java.util.List;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import run.halo.app.infra.utils.JsonUtils;

/**
 * @author guqing
 * @since 2.0.0
 */
public class PatchUtils {
    private static final String DELIMITER = "\n";
    private static final Splitter lineSplitter = Splitter.on(DELIMITER);

    public static Patch<String> create(String deltasJson) {
        List<Delta> deltas = JsonUtils.jsonToObject(deltasJson, new TypeReference<>() {
        });
        Patch<String> patch = new Patch<>();
        for (Delta delta : deltas) {
            StringChunk sourceChunk = delta.getSource();
            StringChunk targetChunk = delta.getTarget();
            Chunk<String> orgChunk = new Chunk<>(sourceChunk.getPosition(), sourceChunk.getLines(),
                sourceChunk.getChangePosition());
            Chunk<String> revChunk = new Chunk<>(targetChunk.getPosition(), targetChunk.getLines(),
                targetChunk.getChangePosition());
            switch (delta.getType()) {
                case DELETE -> patch.addDelta(new DeleteDelta<>(orgChunk, revChunk));
                case INSERT -> patch.addDelta(new InsertDelta<>(orgChunk, revChunk));
                case CHANGE -> patch.addDelta(new ChangeDelta<>(orgChunk, revChunk));
                default -> throw new IllegalArgumentException("Unsupported delta type.");
            }
        }
        return patch;
    }

    public static String patchToJson(Patch<String> patch) {
        List<AbstractDelta<String>> deltas = patch.getDeltas();
        return JsonUtils.objectToJson(deltas);
    }

    public static String applyPatch(String original, String patchJson) {
        Patch<String> patch = PatchUtils.create(patchJson);
        try {
            return String.join(DELIMITER, patch.applyTo(breakLine(original)));
        } catch (PatchFailedException e) {
            throw new RuntimeException(e);
        }
    }

    public static String diffToJsonPatch(String original, String revised) {
        Patch<String> patch = DiffUtils.diff(breakLine(original), breakLine(revised));
        return PatchUtils.patchToJson(patch);
    }

    public static List<String> breakLine(String content) {
        if (StringUtils.isBlank(content)) {
            return Collections.emptyList();
        }
        return lineSplitter.splitToList(content);
    }

    @Data
    public static class Delta {
        private StringChunk source;
        private StringChunk target;
        private DeltaType type;
    }

    @Data
    public static class StringChunk {
        private int position;
        private List<String> lines;
        private List<Integer> changePosition;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/content/PostContentService.java
================================================
package run.halo.app.content;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface PostContentService {

    Mono<ContentWrapper> getHeadContent(String postName);

    Mono<ContentWrapper> getReleaseContent(String postName);

    Mono<ContentWrapper> getSpecifiedContent(String postName, String snapshotName);

    Flux<String> listSnapshots(String postName);
}


================================================
FILE: api/src/main/java/run/halo/app/content/comment/CommentSubject.java
================================================
package run.halo.app.content.comment;

import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;
import run.halo.app.extension.Extension;
import run.halo.app.extension.Ref;

/**
 * Comment subject.
 *
 * @author guqing
 * @since 2.0.0
 */
public interface CommentSubject<T extends Extension> extends ExtensionPoint {

    Mono<T> get(String name);

    default Mono<SubjectDisplay> getSubjectDisplay(String name) {
        return Mono.empty();
    }

    boolean supports(Ref ref);

    record SubjectDisplay(String title, String url, String kindName) {
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java
================================================
package run.halo.app.core.attachment;

import java.net.URI;
import java.net.URL;
import lombok.Builder;
import lombok.Data;
import org.pf4j.ExtensionPoint;
import reactor.core.publisher.Mono;
import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler;

/**
 * Thumbnail provider extension.
 *
 * @since 2.22.0
 * @deprecated Use {@link AttachmentHandler} instead. We are planing to remove this extension
 * point in future release.
 */
@Deprecated(forRemoval = true, since = "2.22.0")
public interface ThumbnailProvider extends ExtensionPoint {

    /**
     * Generate thumbnail URI for given image URL and size.
     *
     * @param context Thumbnail context including image URI and size
     * @return Generated thumbnail URI
     */
    Mono<URI> generate(ThumbnailContext context);

    /**
     * Delete thumbnail file for given image URL.
     *
     * @param imageUrl original image URL
     */
    Mono<Void> delete(URL imageUrl);

    /**
     * Whether the provider supports the given image URI.
     *
     * @return {@code true} if supports, {@code false} otherwise
     */
    Mono<Boolean> supports(ThumbnailContext context);

    @Data
    @Builder
    class ThumbnailContext {
        private final URL imageUrl;
        private final ThumbnailSize size;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java
================================================
package run.halo.app.core.attachment;

import java.util.Arrays;
import java.util.Optional;
import lombok.Getter;

@Getter
public enum ThumbnailSize {
    S(400),
    M(800),
    L(1200),
    XL(1600);

    private final int width;

    ThumbnailSize(int width) {
        this.width = width;
    }

    /**
     * Convert width string to {@link ThumbnailSize}.
     *
     * @param width width string
     */
    public static ThumbnailSize fromWidth(String width) {
        for (ThumbnailSize value : values()) {
            if (String.valueOf(value.getWidth()).equals(width)) {
                return value;
            }
        }
        return ThumbnailSize.M;
    }

    /**
     * Convert name to {@link ThumbnailSize}.
     */
    public static ThumbnailSize fromName(String name) {
        for (ThumbnailSize value : values()) {
            if (value.name().equalsIgnoreCase(name)) {
                return value;
            }
        }
        throw new IllegalArgumentException("No such thumbnail size: " + name);
    }

    public static Optional<ThumbnailSize> optionalValueOf(String name) {
        for (ThumbnailSize value : values()) {
            if (value.name().equalsIgnoreCase(name)) {
                return Optional.of(value);
            }
        }
        return Optional.empty();
    }

    public static Integer[] allowedWidths() {
        return Arrays.stream(ThumbnailSize.values())
            .map(ThumbnailSize::getWidth)
            .toArray(Integer[]::new);
    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java
================================================
package run.halo.app.core.endpoint;

import org.springframework.web.reactive.socket.WebSocketHandler;
import run.halo.app.extension.GroupVersion;

/**
 * Endpoint for WebSocket.
 *
 * @author johnniang
 */
public interface WebSocketEndpoint {

    /**
     * Path of the URL after group version.
     *
     * @return path of the URL.
     */
    String urlPath();

    /**
     * Group and version parts of the endpoint.
     *
     * @return GroupVersion.
     */
    GroupVersion groupVersion();

    /**
     * Real WebSocket handler for the endpoint.
     *
     * @return WebSocket handler.
     */
    WebSocketHandler handler();

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.AnnotationSetting.KIND;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupKind;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = KIND,
    plural = "annotationsettings", singular = "annotationsetting")
public class AnnotationSetting extends AbstractExtension {
    public static final String TARGET_REF_LABEL = "halo.run/target-ref";

    public static final String KIND = "AnnotationSetting";

    @Schema(requiredMode = REQUIRED)
    private AnnotationSettingSpec spec;

    @Data
    public static class AnnotationSettingSpec {
        @Schema(requiredMode = REQUIRED)
        private GroupKind targetRef;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private List<Object> formSchema;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/AuthProvider.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

/**
 * Auth provider extension.
 *
 * @author guqing
 * @since 2.4.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = "auth.halo.run", version = "v1alpha1", kind = "AuthProvider",
    singular = "authprovider", plural = "authproviders")
public class AuthProvider extends AbstractExtension {

    public static final String AUTH_BINDING_LABEL = "auth.halo.run/auth-binding";

    public static final String PRIVILEGED_LABEL = "auth.halo.run/privileged";

    @Schema(requiredMode = REQUIRED)
    private AuthProviderSpec spec;

    @Data
    @ToString
    public static class AuthProviderSpec {

        @Schema(requiredMode = REQUIRED, description = "Display name of the auth provider")
        private String displayName;

        private String description;

        private String logo;

        private String website;

        private String helpPage;

        @Schema(requiredMode = REQUIRED, description = "Authentication url of the auth provider")
        private String authenticationUrl;

        private String method = "GET";

        private boolean rememberMeSupport = false;

        /**
         * Auth type: form or oauth2.
         */
        @Getter(onMethod_ = @NonNull)
        @Schema(requiredMode = REQUIRED)
        private AuthType authType = AuthType.OAUTH2;

        private String bindingUrl;

        private String unbindUrl;

        @Schema(requiredMode = NOT_REQUIRED)
        private SettingRef settingRef;

        @Schema(requiredMode = NOT_REQUIRED)
        private ConfigMapRef configMapRef;

        public void setAuthType(AuthType authType) {
            this.authType = (authType == null ? AuthType.OAUTH2 : authType);
        }
    }

    @Data
    @ToString
    public static class SettingRef {
        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String name;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String group;
    }

    @Data
    @ToString
    public static class ConfigMapRef {
        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String name;
    }

    public enum AuthType {
        FORM,
        OAUTH2
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Counter.java
================================================
package run.halo.app.core.extension;

import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;

/**
 * A counter for number of requests by extension resource name.
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@GVK(group = "metrics.halo.run", version = "v1alpha1", kind = "Counter", plural = "counters",
    singular = "counter")
@EqualsAndHashCode(callSuper = true)
public class Counter extends AbstractExtension {

    private Integer visit;

    private Integer upvote;

    private Integer downvote;

    private Integer totalComment;

    private Integer approvedComment;

    public static Counter emptyCounter(String name) {
        Counter counter = new Counter();
        counter.setMetadata(new Metadata());
        counter.getMetadata().setName(name);
        counter.setUpvote(0);
        counter.setTotalComment(0);
        counter.setApprovedComment(0);
        counter.setVisit(0);
        return counter;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Device.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = Device.GROUP, version = Device.VERSION, kind = Device.KIND, plural = "devices",
    singular = "device")
public class Device extends AbstractExtension {
    public static final String GROUP = "security.halo.run";
    public static final String VERSION = "v1alpha1";
    public static final String KIND = "Device";

    @Schema(requiredMode = REQUIRED)
    private Spec spec;

    @Getter(onMethod_ = @NonNull)
    private Status status = new Status();

    public void setStatus(Status status) {
        this.status = (status == null ? new Status() : status);
    }

    @Data
    @Accessors(chain = true)
    @Schema(name = "DeviceSpec")
    public static class Spec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String sessionId;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String principalName;

        @Schema(requiredMode = REQUIRED, maxLength = 129)
        private String ipAddress;

        @Schema(maxLength = 500)
        private String userAgent;

        private String rememberMeSeriesId;

        private Instant lastAccessedTime;

        private Instant lastAuthenticatedTime;
    }

    @Data
    @Accessors(chain = true)
    @Schema(name = "DeviceStatus")
    public static class Status {
        private String browser;
        private String os;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Menu.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.LinkedHashSet;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = "Menu", plural = "menus", singular = "menu")
public class Menu extends AbstractExtension {

    @Schema(description = "The spec of menu.", requiredMode = REQUIRED)
    private Spec spec;

    @Data
    @Schema(name = "MenuSpec")
    public static class Spec {

        @Schema(description = "The display name of the menu.", requiredMode = REQUIRED)
        private String displayName;

        @ArraySchema(
            uniqueItems = true,
            arraySchema = @Schema(description = "Menu items of this menu."),
            schema = @Schema(description = "Name of menu item.")
        )
        private LinkedHashSet<String> menuItems;

    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/MenuItem.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.LinkedHashSet;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = "MenuItem",
    plural = "menuitems", singular = "menuitem")
public class MenuItem extends AbstractExtension {

    @Schema(description = "The spec of menu item.", requiredMode = REQUIRED)
    private MenuItemSpec spec;

    @Schema(description = "The status of menu item.")
    private MenuItemStatus status;

    public enum Target {
        BLANK("_blank"),
        SELF("_self"),
        PARENT("_parent"),
        TOP("_top");

        private final String value;

        @JsonCreator
        Target(String value) {
            this.value = value;
        }

        @JsonValue
        public String getValue() {
            return value;
        }
    }

    @Data
    public static class MenuItemSpec {

        @Schema(description = "The display name of menu item.")
        private String displayName;

        @Schema(description = "The href of this menu item.")
        private String href;

        @Schema(description = "The <a> target attribute of this menu item.")
        private Target target;

        @Schema(description = "The priority is for ordering.")
        private Integer priority;

        @ArraySchema(
            uniqueItems = true,
            arraySchema = @Schema(description = "Children of this menu item"),
            schema = @Schema(description = "The name of menu item child"))
        private LinkedHashSet<String> children;

        @Schema(description = "Target reference. Like Category, Tag, Post or SinglePage")
        private Ref targetRef;

    }

    @Data
    public static class MenuItemStatus {

        @Schema(description = "Calculated Display name of menu item.")
        private String displayName;

        @Schema(description = "Calculated href of manu item.")
        private String href;

    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Plugin.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.net.URI;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.pf4j.PluginState;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.infra.ConditionList;

/**
 * A custom resource for Plugin.
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = "plugin.halo.run", version = "v1alpha1", kind = "Plugin", plural = "plugins",
    singular = "plugin")
@EqualsAndHashCode(callSuper = true)
public class Plugin extends AbstractExtension {

    public static final String SYSTEM_RESERVED_LABEL_KEY = "plugin.halo.run/system-reserved";

    public static final String BUILT_IN_KEEPER_FINALIZER = "plugin.halo.run/built-in-keeper";

    @Schema(requiredMode = REQUIRED)
    private PluginSpec spec;

    private PluginStatus status;

    /**
     * Gets plugin status.
     *
     * @return empty object if status is null.
     */
    @NonNull
    @JsonIgnore
    public PluginStatus statusNonNull() {
        if (this.status == null) {
            this.status = new PluginStatus();
        }
        return status;
    }

    @Data
    public static class PluginSpec {

        private String displayName;

        /**
         * plugin version.
         *
         * @see <a href="semver.org">semantic version</a>
         */
        @Schema(requiredMode = REQUIRED,
            pattern = "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-("
                + "(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\."
                + "(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\"
                + ".[0-9a-zA-Z-]+)*))?$")
        private String version;

        private PluginAuthor author;

        private String logo;

        private Map<String, String> pluginDependencies = new HashMap<>(4);

        private String homepage;

        private String repo;

        private String issues;

        private String description;

        private List<License> license;

        /**
         * SemVer format.
         */
        private String requires = "*";

        private Boolean enabled = false;

        private String settingName;

        private String configMapName;
    }

    /**
     * In the future, we may consider using {@link run.halo.app.infra.model.License} instead of it.
     * But now, replace it will lead to incompatibility with downstream.
     */
    @Data
    public static class License {
        private String name;
        private String url;
    }

    @Data
    public static class PluginStatus {

        private Phase phase;

        private ConditionList conditions;

        private Instant lastStartTime;

        private PluginState lastProbeState;

        private String entry;

        private String stylesheet;

        private String logo;

        @Schema(description = "Load location of the plugin, often a path.")
        private URI loadLocation;

        public static ConditionList nullSafeConditions(@NonNull PluginStatus status) {
            Assert.notNull(status, "The status must not be null.");
            if (status.getConditions() == null) {
                status.setConditions(new ConditionList());
            }
            return status.getConditions();
        }
    }

    public enum Phase {
        PENDING,
        STARTING,
        CREATED,
        DISABLING,
        DISABLED,
        RESOLVED,
        STARTED,
        STOPPED,
        FAILED,
        UNKNOWN,
        ;
    }

    @Data
    @ToString
    public static class PluginAuthor {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String name;

        private String website;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/RememberMeToken.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "security.halo.run", version = "v1alpha1", kind = "RememberMeToken", plural =
    "remembermetokens", singular = "remembermetoken")
public class RememberMeToken extends AbstractExtension {

    @Schema(requiredMode = REQUIRED)
    private Spec spec;

    @Data
    @Accessors(chain = true)
    @Schema(name = "RememberMeTokenSpec")
    public static class Spec {
        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String username;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String series;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String tokenValue;

        private Instant lastUsed;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/ReverseProxy.java
================================================
package run.halo.app.core.extension;

import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

/**
 * <p>The reverse proxy custom resource is used to configure a path to proxy it to a directory or
 * file.</p>
 * <p>HTTP proxy may be added in the future.</p>
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "plugin.halo.run", kind = "ReverseProxy", version = "v1alpha1",
    plural = "reverseproxies", singular = "reverseproxy")
public class ReverseProxy extends AbstractExtension {
    private List<ReverseProxyRule> rules;

    public record ReverseProxyRule(String path, FileReverseProxyProvider file) {
    }

    public record FileReverseProxyProvider(String directory, String filename) {
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Role.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static java.util.Arrays.compare;
import static run.halo.app.core.extension.Role.GROUP;
import static run.halo.app.core.extension.Role.KIND;
import static run.halo.app.core.extension.Role.VERSION;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

/**
 * @author guqing
 * @since 2.0.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = GROUP,
    version = VERSION,
    kind = KIND,
    plural = "roles",
    singular = "role")
public class Role extends AbstractExtension {
    public static final String ROLE_DEPENDENCY_RULES =
        "rbac.authorization.halo.run/dependency-rules";
    public static final String ROLE_AGGREGATE_LABEL_PREFIX =
        "rbac.authorization.halo.run/aggregate-to-";
    public static final String ROLE_DEPENDENCIES_ANNO = "rbac.authorization.halo.run/dependencies";
    public static final String UI_PERMISSIONS_ANNO = "rbac.authorization.halo.run/ui-permissions";

    public static final String SYSTEM_RESERVED_LABELS =
        "rbac.authorization.halo.run/system-reserved";
    public static final String HIDDEN_LABEL_NAME = "halo.run/hidden";
    public static final String TEMPLATE_LABEL_NAME = "halo.run/role-template";
    public static final String UI_PERMISSIONS_AGGREGATED_ANNO =
        "rbac.authorization.halo.run/ui-permissions-aggregated";

    public static final String GROUP = "";
    public static final String VERSION = "v1alpha1";
    public static final String KIND = "Role";

    @Schema(requiredMode = REQUIRED)
    List<PolicyRule> rules;

    /**
     * PolicyRule holds information that describes a policy rule, but does not contain information
     * about whom the rule applies to or which namespace the rule applies to.
     *
     * @author guqing
     * @since 2.0.0
     */
    @Getter
    @EqualsAndHashCode
    public static class PolicyRule implements Comparable<PolicyRule> {
        /**
         * APIGroups is the name of the APIGroup that contains the resources.
         * If multiple API groups are specified, any action requested against one of the enumerated
         * resources in any API group will be allowed.
         */
        final String[] apiGroups;

        /**
         * Resources is a list of resources this rule applies to.  '*' represents all resources in
         * the specified apiGroups.
         * '*&#47;foo' represents the subresource 'foo' for all resources in the specified
         * apiGroups.
         */
        final String[] resources;

        /**
         * ResourceNames is an optional white list of names that the rule applies to.  An empty set
         * means that everything is allowed.
         */
        final String[] resourceNames;

        /**
         * NonResourceURLs is a set of partial urls that a user should have access to.
         * *s are allowed, but only as the full, final step in the path
         * If an action is not a resource API request, then the URL is split on '/' and is checked
         * against the NonResourceURLs to look for a match.
         * Since non-resource URLs are not namespaced, this field is only applicable for
         * ClusterRoles referenced from a ClusterRoleBinding.
         * Rules can either apply to API resources (such as "pods" or "secrets") or non-resource
         * URL paths (such as "/api"),  but not both.
         */
        final String[] nonResourceURLs;

        /**
         * about who the rule applies to or which namespace the rule applies to.
         */
        final String[] verbs;

        public PolicyRule() {
            this(null, null, null, null, null);
        }

        public PolicyRule(String[] apiGroups, String[] resources,
            String[] resourceNames,
            String[] nonResourceURLs, String[] verbs) {
            this.apiGroups = nullElseEmpty(apiGroups);
            this.resources = nullElseEmpty(resources);
            this.resourceNames = nullElseEmpty(resourceNames);
            this.nonResourceURLs = nullElseEmpty(nonResourceURLs);
            this.verbs = nullElseEmpty(verbs);
        }

        String[] nullElseEmpty(String... items) {
            if (items == null) {
                return new String[] {};
            }
            return items;
        }

        @Override
        public int compareTo(@NonNull PolicyRule other) {
            int result = compare(apiGroups, other.apiGroups);
            if (result != 0) {
                return result;
            }
            result = compare(resources, other.resources);
            if (result != 0) {
                return result;
            }
            result = compare(resourceNames, other.resourceNames);
            if (result != 0) {
                return result;
            }
            result = compare(nonResourceURLs, other.nonResourceURLs);
            if (result != 0) {
                return result;
            }
            result = compare(verbs, other.verbs);
            return result;
        }

        public static class Builder {
            String[] apiGroups;

            String[] resources;

            String[] resourceNames;

            String[] nonResourceURLs;

            String[] verbs;

            public Builder apiGroups(String... apiGroups) {
                this.apiGroups = apiGroups;
                return this;
            }

            public Builder resources(String... resources) {
                this.resources = resources;
                return this;
            }

            public Builder resourceNames(String... resourceNames) {
                this.resourceNames = resourceNames;
                return this;
            }

            public Builder nonResourceURLs(String... nonResourceURLs) {
                this.nonResourceURLs = nonResourceURLs;
                return this;
            }

            public Builder verbs(String... verbs) {
                this.verbs = verbs;
                return this;
            }

            public PolicyRule build() {
                return new PolicyRule(apiGroups, resources, resourceNames,
                    nonResourceURLs,
                    verbs);
            }
        }
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/RoleBinding.java
================================================
package run.halo.app.core.extension;

import static run.halo.app.core.extension.RoleBinding.GROUP;
import static run.halo.app.core.extension.RoleBinding.KIND;
import static run.halo.app.core.extension.RoleBinding.VERSION;

import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.util.StringUtils;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.ExtensionOperator;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;

/**
 * RoleBinding references a role, but does not contain it.
 * It can reference a Role in the global.
 * It adds who information via Subjects.
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@GVK(group = GROUP,
    version = VERSION,
    kind = KIND,
    plural = "rolebindings",
    singular = "rolebinding")
public class RoleBinding extends AbstractExtension {

    public static final String GROUP = "";

    public static final String VERSION = "v1alpha1";

    public static final String KIND = "RoleBinding";

    /**
     * Subjects holds references to the objects the role applies to.
     */
    List<Subject> subjects;

    /**
     * RoleRef can reference a Role in the current namespace or a ClusterRole in the global
     * namespace.
     * If the RoleRef cannot be resolved, the Authorizer must return an error.
     */
    RoleRef roleRef;

    /**
     * RoleRef contains information that points to the role being used.
     *
     * @author guqing
     * @since 2.0.0
     */
    @Data
    public static class RoleRef {

        /**
         * Kind is the type of resource being referenced.
         */
        String kind;

        /**
         * Name is the name of resource being referenced.
         */
        String name;

        /**
         * APIGroup is the group for the resource being referenced.
         */
        String apiGroup;
    }

    /**
     * @author guqing
     * @since 2.0.0
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Subject {
        /**
         * Kind of object being referenced. Values defined by this API group are "User", "Group",
         * and "ServiceAccount".
         * If the Authorizer does not recognize the kind value, the Authorizer should report
         * an error.
         */
        String kind;

        /**
         * Name of the object being referenced.
         */
        String name;

        /**
         * APIGroup holds the API group of the referenced subject.
         * Defaults to "" for ServiceAccount subjects.
         * Defaults to "rbac.authorization.halo.run" for User and Group subjects.
         */
        String apiGroup;

        public static Predicate<Subject> isUser(String username) {
            return subject -> User.KIND.equals(subject.getKind())
                && User.GROUP.equals(subject.getApiGroup())
                && username.equals(subject.getName());
        }

        public static Predicate<Subject> containsUser(Set<String> usernames) {
            return subject -> User.KIND.equals(subject.getKind())
                && User.GROUP.equals(subject.apiGroup)
                && usernames.contains(subject.getName());
        }

        @Override
        public String toString() {
            if (StringUtils.hasText(apiGroup)) {
                return apiGroup + "/" + kind + "/" + name;
            }
            return kind + "/" + name;
        }
    }

    public static RoleBinding create(String username, String roleName) {
        var metadata = new Metadata();
        metadata.setName(String.join("-", username, roleName, "binding"));

        var roleRef = new RoleRef();
        roleRef.setKind(Role.KIND);
        roleRef.setName(roleName);
        roleRef.setApiGroup(Role.GROUP);

        var subject = new Subject();
        subject.setKind(User.KIND);
        subject.setName(username);
        subject.setApiGroup(User.GROUP);

        var binding = new RoleBinding();
        binding.setMetadata(metadata);
        binding.setRoleRef(roleRef);

        // keep the subjects mutable
        var subjects = new LinkedList<Subject>();
        subjects.add(subject);

        binding.setSubjects(subjects);
        return binding;
    }

    public static Predicate<RoleBinding> containsUser(String username) {
        return ExtensionOperator.<RoleBinding>isNotDeleted().and(
            binding -> binding.getSubjects().stream()
                .anyMatch(Subject.isUser(username)));
    }

    public static Predicate<RoleBinding> containsUser(Set<String> usernames) {
        return ExtensionOperator.<RoleBinding>isNotDeleted()
            .and(binding -> binding.getSubjects().stream()
                .anyMatch(Subject.containsUser(usernames)));
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Setting.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.extension.GroupVersionKind.fromExtension;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;

/**
 * {@link Setting} is a custom extension to generate forms based on configuration.
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "", version = "v1alpha1", kind = Setting.KIND,
    plural = "settings", singular = "setting")
public class Setting extends AbstractExtension {

    public static final String KIND = "Setting";

    public static final GroupVersionKind GVK = fromExtension(Setting.class);

    @Schema(requiredMode = REQUIRED)
    private SettingSpec spec;

    @Data
    public static class SettingSpec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private List<SettingForm> forms;
    }

    @Data
    public static class SettingForm {

        @Schema(requiredMode = REQUIRED)
        private String group;

        private String label;

        @Schema(requiredMode = REQUIRED)
        private List<Object> formSchema;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/Theme.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import java.util.Objects;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.infra.ConditionList;
import run.halo.app.infra.model.License;

/**
 * <p>Theme extension.</p>
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = "theme.halo.run", version = "v1alpha1", kind = Theme.KIND,
    plural = "themes", singular = "theme")
public class Theme extends AbstractExtension {

    public static final String KIND = "Theme";

    public static final String THEME_NAME_LABEL = "theme.halo.run/theme-name";

    @Schema(requiredMode = REQUIRED)
    private ThemeSpec spec;

    private ThemeStatus status;

    @Data
    @ToString
    public static class ThemeSpec {
        private static final String WILDCARD = "*";

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String displayName;

        @Schema(requiredMode = REQUIRED)
        private Author author;

        private String description;

        private String logo;

        private String homepage;

        private String repo;

        private String issues;

        private String version = WILDCARD;

        @Schema(requiredMode = NOT_REQUIRED)
        private String requires = WILDCARD;

        private String settingName;

        private String configMapName;

        private List<License> license;

        @Schema
        private CustomTemplates customTemplates;

    }

    @Data
    public static class ThemeStatus {
        private ThemePhase phase;
        private ConditionList conditions;
        private String location;
    }

    /**
     * Null-safe get {@link ConditionList} from theme status.
     *
     * @param theme theme must not be null
     * @return condition list
     */
    public static ConditionList nullSafeConditionList(Theme theme) {
        Assert.notNull(theme, "The theme must not be null");
        var status = Objects.requireNonNullElseGet(theme.getStatus(), ThemeStatus::new);
        theme.setStatus(status);

        var conditions = Objects.requireNonNullElseGet(status.getConditions(), ConditionList::new);
        status.setConditions(conditions);
        return conditions;
    }

    public enum ThemePhase {
        READY,
        FAILED,
        UNKNOWN,
    }

    @Data
    @ToString
    public static class Author {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String name;

        private String website;
    }

    @Data
    public static class CustomTemplates {
        private List<TemplateDescriptor> post;
        private List<TemplateDescriptor> category;
        private List<TemplateDescriptor> page;
    }

    /**
     * Type used to describe custom template page.
     *
     * @author guqing
     * @since 2.0.0
     */
    @Data
    public static class TemplateDescriptor {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String name;

        private String description;

        private String screenshot;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String file;
    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/User.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.User.GROUP;
import static run.halo.app.core.extension.User.KIND;
import static run.halo.app.core.extension.User.VERSION;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

/**
 * The extension represents user details of Halo.
 *
 * @author johnniang
 */
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = GROUP,
    version = VERSION,
    kind = KIND,
    singular = "user",
    plural = "users")
public class User extends AbstractExtension {

    public static final String GROUP = "";
    public static final String VERSION = "v1alpha1";
    public static final String KIND = "User";

    public static final String USER_RELATED_ROLES_INDEX = "roles";

    public static final String ROLE_NAMES_ANNO = "rbac.authorization.halo.run/role-names";

    public static final String EMAIL_TO_VERIFY = "halo.run/email-to-verify";

    public static final String LAST_AVATAR_ATTACHMENT_NAME_ANNO =
        "halo.run/last-avatar-attachment-name";

    public static final String AVATAR_ATTACHMENT_NAME_ANNO = "halo.run/avatar-attachment-name";

    public static final String HIDDEN_USER_LABEL = "halo.run/hidden-user";

    public static final String REQUEST_TO_UPDATE = "halo.run/request-to-update";

    @Schema(requiredMode = REQUIRED)
    private UserSpec spec = new UserSpec();

    private UserStatus status = new UserStatus();

    @Data
    public static class UserSpec {

        @Schema(requiredMode = REQUIRED)
        private String displayName;

        private String avatar;

        @Schema(requiredMode = REQUIRED)
        private String email;

        private boolean emailVerified;

        private String phone;

        private String password;

        private String bio;

        private Instant registeredAt;

        private Boolean twoFactorAuthEnabled;

        private String totpEncryptedSecret;

        private Boolean disabled;

        private Integer loginHistoryLimit;

    }

    @Data
    public static class UserStatus {

        private String permalink;

    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/UserConnection.java
================================================
package run.halo.app.core.extension;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Metadata;

/**
 * User connection extension.
 *
 * @author guqing
 * @since 2.4.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
@GVK(group = "auth.halo.run", version = "v1alpha1", kind = "UserConnection",
    singular = "userconnection", plural = "userconnections")
public class UserConnection extends AbstractExtension {

    @Schema(requiredMode = REQUIRED)
    private UserConnectionSpec spec;

    @Data
    public static class UserConnectionSpec {

        /**
         * The name of the OAuth provider (e.g. Google, Facebook, Twitter).
         */
        @Schema(requiredMode = REQUIRED)
        private String registrationId;

        /**
         * The {@link Metadata#getName()} of the user associated with the OAuth connection.
         */
        @Schema(requiredMode = REQUIRED)
        private String username;

        /**
         * The unique identifier for the user's connection to the OAuth provider.
         * for example, the user's GitHub id.
         */
        @Schema(requiredMode = REQUIRED)
        private String providerUserId;

        /**
         * The time when the user connection was last updated.
         */
        private Instant updatedAt;

    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java
================================================
package run.halo.app.core.extension.attachment;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Attachment.KIND;

import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Map;
import java.util.Set;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.jspecify.annotations.Nullable;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
    plural = "attachments", singular = "attachment")
public class Attachment extends AbstractExtension {

    public static final String KIND = "Attachment";

    @Schema(requiredMode = REQUIRED)
    private AttachmentSpec spec;

    private AttachmentStatus status;

    @Data
    public static class AttachmentSpec {

        @Schema(description = "Display name of attachment")
        private String displayName;

        @Schema(description = "Group name")
        private String groupName;

        @Schema(description = "Policy name")
        private String policyName;

        @Schema(description = "Name of User who uploads the attachment")
        private String ownerName;

        @Schema(description = "Media type of attachment")
        @Nullable
        private String mediaType;

        @Schema(description = "Size of attachment. Unit is Byte", minimum = "0")
        private Long size;

        @ArraySchema(
            arraySchema = @Schema(description = "Tags of attachment"),
            schema = @Schema(description = "Tag name"))
        private Set<String> tags;

    }

    @Data
    public static class AttachmentStatus {

        @Schema(description = """
            Permalink of attachment.
            If it is in local storage, the public URL will be set.
            If it is in s3 storage, the Object URL will be set.
            """)
        private String permalink;

        private Map<String, String> thumbnails;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Constant.java
================================================
package run.halo.app.core.extension.attachment;

import run.halo.app.core.extension.attachment.endpoint.AttachmentHandler;

public enum Constant {
    ;

    public static final String GROUP = "storage.halo.run";
    public static final String VERSION = "v1alpha1";
    /**
     * The relative path starting from attachments folder is for deletion.
     */
    public static final String LOCAL_REL_PATH_ANNO_KEY = GROUP + "/local-relative-path";
    /**
     * The encoded URI is for building external url.
     */
    public static final String URI_ANNO_KEY = GROUP + "/uri";

    /**
     * Do not use this key to set external link. You could implement
     * {@link AttachmentHandler#getPermalink} by your self.
     * <p>
     */
    public static final String EXTERNAL_LINK_ANNO_KEY = GROUP + "/external-link";

    public static final String FINALIZER_NAME = "attachment-manager";

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Group.java
================================================
package run.halo.app.core.extension.attachment;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Group.KIND;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
    plural = "groups", singular = "group")
public class Group extends AbstractExtension {

    public static final String KIND = "Group";
    public static final String HIDDEN_LABEL = "halo.run/hidden";

    @Schema(requiredMode = REQUIRED)
    private GroupSpec spec;

    private GroupStatus status;

    @Data
    public static class GroupSpec {

        @Schema(requiredMode = REQUIRED, description = "Display name of group")
        private String displayName;

    }

    @Data
    public static class GroupStatus {

        @Schema(description = "Update timestamp of the group")
        private Instant updateTimestamp;

        @Schema(description = "Total of attachments under the current group", minimum = "0")
        private Long totalAttachments;

    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/Policy.java
================================================
package run.halo.app.core.extension.attachment;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.Policy.KIND;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
    plural = "policies", singular = "policy")
public class Policy extends AbstractExtension {
    public static final String POLICY_OWNER_LABEL = "storage.halo.run/policy-owner";

    public static final String KIND = "Policy";

    @Schema(requiredMode = REQUIRED)
    private PolicySpec spec;

    @Data
    public static class PolicySpec {

        @Schema(requiredMode = REQUIRED, description = "Display name of policy")
        private String displayName;

        @Schema(requiredMode = REQUIRED, description = "Reference name of PolicyTemplate")
        private String templateName;

        @Schema(description = "Reference name of ConfigMap extension")
        private String configMapName;

    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java
================================================
package run.halo.app.core.extension.attachment;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.attachment.PolicyTemplate.KIND;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = KIND,
    plural = "policytemplates", singular = "policytemplate")
public class PolicyTemplate extends AbstractExtension {

    public static final String KIND = "PolicyTemplate";

    private PolicyTemplateSpec spec;

    @Data
    public static class PolicyTemplateSpec {

        private String displayName;

        @Schema(requiredMode = REQUIRED)
        private String settingName;

    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java
================================================
package run.halo.app.core.extension.attachment.endpoint;

import java.net.URI;
import java.time.Duration;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.pf4j.ExtensionPoint;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Mono;
import run.halo.app.core.attachment.ThumbnailSize;
import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;

public interface AttachmentHandler extends ExtensionPoint {

    Mono<Attachment> upload(UploadContext context);

    Mono<Attachment> delete(DeleteContext context);

    /**
     * Gets a shared URL which could be accessed publicly.
     * 1. If the attachment is in local storage, the permalink will be returned.
     * 2. If the attachment is in s3 storage, the Presigned URL will be returned.
     * <p>
     * Please note that the default implementation is only for back compatibility.
     *
     * @param attachment contains detail of attachment.
     * @param policy is storage policy.
     * @param configMap contains configuration needed by handler.
     * @param ttl indicates how long the URL is alive.
     * @return shared URL which could be accessed publicly. Might be relative URL.
     */
    default Mono<URI> getSharedURL(Attachment attachment,
        Policy policy,
        ConfigMap configMap,
        Duration ttl) {
        return Mono.empty();
    }

    /**
     * Gets a permalink representing a unique attachment.
     * If the attachment is in local storage, the permalink will be returned.
     * If the attachment is in s3 storage, the Object URL will be returned.
     * <p>
     * Please note that the default implementation is only for back compatibility.
     *
     * @param attachment contains detail of attachment.
     * @param policy is storage policy.
     * @param configMap contains configuration needed by handler.
     * @return permalink representing a unique attachment. Might be relative URL.
     */
    default Mono<URI> getPermalink(Attachment attachment,
        Policy policy,
        ConfigMap configMap) {
        return Mono.empty();
    }

    /**
     * Gets thumbnail links for given attachment.
     *
     * @param attachment the attachment
     * @param policy the policy
     * @param configMap the config map
     * @return a map of thumbnail sizes to their respective URIs
     */
    default Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment attachment,
        Policy policy,
        ConfigMap configMap) {
        return Mono.empty();
    }

    interface UploadContext {

        FilePart file();

        Policy policy();

        ConfigMap configMap();

        /**
         * Gets the group info if available.
         *
         * @return the group info, or null if not available
         */
        @Nullable
        default Group group() {
            return null;
        }

    }

    interface DeleteContext {
        Attachment attachment();

        Policy policy();

        ConfigMap configMap();
    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/DeleteOption.java
================================================
package run.halo.app.core.extension.attachment.endpoint;

import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;

public record DeleteOption(Attachment attachment, Policy policy, ConfigMap configMap)
    implements AttachmentHandler.DeleteContext {
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java
================================================
package run.halo.app.core.extension.attachment.endpoint;

import java.nio.file.Path;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

/**
 * SimpleFilePart is an adapter of simple data for uploading.
 *
 * @param filename is name of the attachment file.
 * @param content is binary data of the attachment file.
 * @param mediaType is media type of the attachment file.
 */
public record SimpleFilePart(
    String filename,
    Flux<DataBuffer> content,
    MediaType mediaType
) implements FilePart {
    @Override
    public Mono<Void> transferTo(Path dest) {
        return DataBufferUtils.write(content(), dest);
    }

    @Override
    public String name() {
        return filename();
    }

    @Override
    public HttpHeaders headers() {
        var headers = new HttpHeaders();
        headers.setContentType(mediaType);
        return HttpHeaders.readOnlyHttpHeaders(headers);
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java
================================================
package run.halo.app.core.extension.attachment.endpoint;

import lombok.Builder;
import org.jspecify.annotations.Nullable;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.codec.multipart.FilePart;
import reactor.core.publisher.Flux;
import run.halo.app.core.extension.attachment.Group;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;

@Builder
public record UploadOption(FilePart file,
                           Policy policy,
                           ConfigMap configMap,
                           @Nullable Group group) implements AttachmentHandler.UploadContext {

    public static UploadOption from(String filename,
        Flux<DataBuffer> content,
        MediaType mediaType,
        Policy policy,
        ConfigMap configMap) {
        var filePart = new SimpleFilePart(filename, content, mediaType);
        return new UploadOption(filePart, policy, configMap, null);
    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Category.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static run.halo.app.core.extension.content.Category.KIND;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;

/**
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION,
    kind = KIND, plural = "categories", singular = "category")
@EqualsAndHashCode(callSuper = true)
public class Category extends AbstractExtension {

    public static final String KIND = "Category";
    public static final String LAST_HIDDEN_STATE_ANNO = "content.halo.run/last-hidden-state";

    public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Category.class);

    @Schema(requiredMode = REQUIRED)
    private CategorySpec spec;

    @Schema
    private CategoryStatus status;

    @JsonIgnore
    public boolean isDeleted() {
        return getMetadata().getDeletionTimestamp() != null;
    }

    @Data
    public static class CategorySpec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String displayName;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String slug;

        private String description;

        private String cover;

        @Schema(requiredMode = NOT_REQUIRED, maxLength = 255)
        private String template;

        /**
         * <p>Used to specify the template for the posts associated with the category.</p>
         * <p>The priority is not as high as that of the post.</p>
         * <p>If the post also specifies a template, the post's template will prevail.</p>
         */
        @Schema(requiredMode = NOT_REQUIRED, maxLength = 255)
        private String postTemplate;

        @Schema(requiredMode = REQUIRED, defaultValue = "0")
        private Integer priority;

        private List<String> children;

        /**
         * <p>if a category is queried for related posts, the default behavior is to
         * query all posts under the category including its subcategories, but if this field is
         * set to true, cascade query behavior will be terminated here.</p>
         * <p>For example, if a category has subcategories A and B, and A has subcategories C and
         * D and C marked this field as true, when querying posts under A category,all posts under A
         * and B will be queried, but C and D will not be queried.</p>
         */
        private boolean preventParentPostCascadeQuery;

        /**
         * <p>Whether to hide the category from the category list.</p>
         * <p>When set to true, the category including its subcategories and related posts will
         * not be displayed in the category list, but it can still be accessed by permalink.</p>
         * <p>Limitation: It only takes effect on the theme-side categorized list and it only
         * allows to be set to true on the first level(root node) of categories.</p>
         */
        private boolean hideFromList;
    }

    @JsonIgnore
    public CategoryStatus getStatusOrDefault() {
        if (this.status == null) {
            this.status = new CategoryStatus();
        }
        return this.status;
    }

    @Data
    public static class CategoryStatus {

        private String permalink;

        /**
         * 包括当前和其下所有层级的文章数量 (depth=max).
         */
        public Integer postCount;

        /**
         * 包括当前和其下所有层级的已发布且公开的文章数量 (depth=max).
         */
        public Integer visiblePostCount;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Comment.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;

/**
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Comment.KIND,
    plural = "comments", singular = "comment")
@EqualsAndHashCode(callSuper = true)
public class Comment extends AbstractExtension {

    public static final String KIND = "Comment";

    public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";

    @Schema(requiredMode = REQUIRED)
    private CommentSpec spec;

    @Schema
    private CommentStatus status;

    @JsonIgnore
    public CommentStatus getStatusOrDefault() {
        if (this.status == null) {
            this.status = new CommentStatus();
        }
        return this.status;
    }

    @Data
    @ToString(callSuper = true)
    @EqualsAndHashCode(callSuper = true)
    public static class CommentSpec extends BaseCommentSpec {

        @Schema(requiredMode = REQUIRED)
        private Ref subjectRef;

        private Instant lastReadTime;
    }

    @Data
    public static class BaseCommentSpec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String raw;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String content;

        @Schema(requiredMode = REQUIRED)
        private CommentOwner owner;

        private String userAgent;

        private String ipAddress;

        private Instant approvedTime;

        /**
         * The user-defined creation time default is <code>metadata.creationTimestamp</code>.
         */
        private Instant creationTime;

        @Schema(requiredMode = REQUIRED, defaultValue = "0")
        private Integer priority;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean top;

        @Schema(requiredMode = REQUIRED, defaultValue = "true")
        private Boolean allowNotification;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean approved;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean hidden;
    }

    @Data
    public static class CommentOwner {
        public static final String KIND_EMAIL = "Email";
        public static final String AVATAR_ANNO = "avatar";
        public static final String WEBSITE_ANNO = "website";
        public static final String EMAIL_HASH_ANNO = "email-hash";

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String kind;

        @Schema(requiredMode = REQUIRED, maxLength = 64)
        private String name;

        private String displayName;

        private Map<String, String> annotations;

        @Nullable
        @JsonIgnore
        public String getAnnotation(String key) {
            return annotations == null ? null : annotations.get(key);
        }

        public static String ownerIdentity(String kind, String name) {
            return kind + "#" + name;
        }
    }

    @Data
    public static class CommentStatus {

        private Instant lastReplyTime;

        private Integer replyCount;

        private Integer visibleReplyCount;

        private Integer unreadReplyCount;

        private Boolean hasNewReply;

        private Long observedVersion;
    }

    public static String toSubjectRefKey(Ref subjectRef) {
        return subjectRef.getGroup() + "/" + subjectRef.getKind() + "/" + subjectRef.getName();
    }

    public static int getUnreadReplyCount(List<Reply> replies, Instant lastReadTime) {
        if (CollectionUtils.isEmpty(replies)) {
            return 0;
        }
        long unreadReplyCount = replies.stream()
            .filter(existingReply -> {
                if (lastReadTime == null) {
                    return true;
                }
                Instant creationTime = defaultIfNull(existingReply.getSpec().getCreationTime(),
                    existingReply.getMetadata().getCreationTimestamp());
                return creationTime.isAfter(lastReadTime);
            })
            .count();
        return (int) unreadReplyCount;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Constant.java
================================================
package run.halo.app.core.extension.content;

public enum Constant {
    ;

    public static final String GROUP = "content.halo.run";
    public static final String VERSION = "v1alpha1";

    public static final String LAST_READ_TIME_ANNO = "content.halo.run/last-read-time";
    public static final String PERMALINK_PATTERN_ANNO = "content.halo.run/permalink-pattern";

    public static final String CHECKSUM_CONFIG_ANNO = "checksum/config";

    public static final String CONTENT_CHECKSUM_ANNO = "checksum/content";
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Post.java
================================================
package run.halo.app.core.extension.content;

import static java.lang.Boolean.parseBoolean;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.Schema.RequiredMode;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.MetadataOperator;
import run.halo.app.infra.ConditionList;

/**
 * <p>Post extension.</p>
 *
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Post.KIND,
    plural = "posts", singular = "post")
@EqualsAndHashCode(callSuper = true)
public class Post extends AbstractExtension {

    public static final String KIND = "Post";

    public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";

    public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Post.class);

    public static final String CATEGORIES_ANNO = "content.halo.run/categories";
    public static final String LAST_RELEASED_SNAPSHOT_ANNO =
        "content.halo.run/last-released-snapshot";
    public static final String LAST_ASSOCIATED_TAGS_ANNO = "content.halo.run/last-associated-tags";
    public static final String LAST_ASSOCIATED_CATEGORIES_ANNO =
        "content.halo.run/last-associated-categories";

    public static final String STATS_ANNO = "content.halo.run/stats";

    /**
     * <p>The key of the label that indicates that the post is scheduled to be published.</p>
     * <p>Can be used to query posts that are scheduled to be published.</p>
     */
    public static final String SCHEDULING_PUBLISH_LABEL = "content.halo.run/scheduling-publish";

    public static final String DELETED_LABEL = "content.halo.run/deleted";
    public static final String PUBLISHED_LABEL = "content.halo.run/published";
    public static final String OWNER_LABEL = "content.halo.run/owner";
    public static final String VISIBLE_LABEL = "content.halo.run/visible";

    public static final String ARCHIVE_YEAR_LABEL = "content.halo.run/archive-year";

    public static final String ARCHIVE_MONTH_LABEL = "content.halo.run/archive-month";
    public static final String ARCHIVE_DAY_LABEL = "content.halo.run/archive-day";

    @Schema(requiredMode = RequiredMode.REQUIRED)
    private PostSpec spec;

    @Schema
    private PostStatus status;

    @JsonIgnore
    public PostStatus getStatusOrDefault() {
        if (this.status == null) {
            this.status = new PostStatus();
        }
        return status;
    }

    @JsonIgnore
    public boolean isDeleted() {
        return Objects.equals(true, spec.getDeleted())
            || getMetadata().getDeletionTimestamp() != null;
    }

    @JsonIgnore
    public boolean isPublished() {
        return isPublished(this.getMetadata());
    }

    public static boolean isPublished(MetadataOperator metadata) {
        var labels = metadata.getLabels();
        return labels != null && parseBoolean(labels.getOrDefault(PUBLISHED_LABEL, "false"));
    }

    public static boolean isRecycled(MetadataOperator metadata) {
        var labels = metadata.getLabels();
        return labels != null && parseBoolean(labels.getOrDefault(DELETED_LABEL, "false"));
    }

    public static boolean isPublic(PostSpec spec) {
        return spec.getVisible() == null || VisibleEnum.PUBLIC.equals(spec.getVisible());
    }

    @Data
    public static class PostSpec {
        @Schema(requiredMode = RequiredMode.REQUIRED, minLength = 1)
        private String title;

        @Schema(requiredMode = RequiredMode.REQUIRED, minLength = 1)
        private String slug;

        /**
         * 文章引用到的已发布的内容,用于主题端显示.
         */
        private String releaseSnapshot;

        private String headSnapshot;

        private String baseSnapshot;

        private String owner;

        private String template;

        private String cover;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
        private Boolean deleted;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
        private Boolean publish;

        private Instant publishTime;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "false")
        private Boolean pinned;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "true")
        private Boolean allowComment;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "PUBLIC")
        private VisibleEnum visible;

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "0")
        private Integer priority;

        @Schema(requiredMode = RequiredMode.REQUIRED)
        private Excerpt excerpt;

        private List<String> categories;

        private List<String> tags;

        private List<Map<String, String>> htmlMetas;
    }

    @Data
    public static class PostStatus {
        private String phase;

        @Schema
        private ConditionList conditions;

        private String permalink;

        private String excerpt;

        private Boolean inProgress;

        private Integer commentsCount;

        private List<String> contributors;

        /**
         * see {@link Category.CategorySpec#isHideFromList()}.
         */
        private Boolean hideFromList;

        private Instant lastModifyTime;

        private Long observedVersion;

        @JsonIgnore
        public ConditionList getConditionsOrDefault() {
            if (this.conditions == null) {
                this.conditions = new ConditionList();
            }
            return conditions;
        }
    }

    @Data
    public static class Excerpt {

        @Schema(requiredMode = RequiredMode.REQUIRED, defaultValue = "true")
        private Boolean autoGenerate;

        private String raw;
    }

    public enum PostPhase {
        DRAFT,
        PENDING_APPROVAL,
        PUBLISHED,
        FAILED;

        /**
         * Convert string value to {@link PostPhase}.
         *
         * @param value enum value string
         * @return {@link PostPhase} if found, otherwise null
         */
        public static PostPhase from(String value) {
            for (PostPhase phase : PostPhase.values()) {
                if (phase.name().equalsIgnoreCase(value)) {
                    return phase;
                }
            }
            return null;
        }
    }

    public enum VisibleEnum {
        PUBLIC,
        INTERNAL,
        PRIVATE;

        /**
         * Convert value string to {@link VisibleEnum}.
         *
         * @param value enum value string
         * @return {@link VisibleEnum} if found, otherwise null
         */
        public static VisibleEnum from(String value) {
            for (VisibleEnum visible : VisibleEnum.values()) {
                if (visible.name().equalsIgnoreCase(value)) {
                    return visible;
                }
            }
            return null;
        }
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Reply.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import org.springframework.lang.NonNull;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;

/**
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Reply.KIND,
    plural = "replies", singular = "reply")
@EqualsAndHashCode(callSuper = true)
public class Reply extends AbstractExtension {

    public static final String KIND = "Reply";

    public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";

    @Schema(requiredMode = REQUIRED)
    private ReplySpec spec;

    @Schema
    @Getter(onMethod_ = @NonNull)
    private Status status = new Status();

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class ReplySpec extends Comment.BaseCommentSpec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String commentName;

        private String quoteReply;
    }

    @Data
    @Schema(name = "ReplyStatus")
    public static class Status {
        private Long observedVersion;
    }

    public void setStatus(Status status) {
        this.status = status == null ? new Status() : status;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/SinglePage.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;
import run.halo.app.extension.MetadataUtil;

/**
 * <p>Single page extension.</p>
 *
 * @author guqing
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = SinglePage.KIND,
    plural = "singlepages", singular = "singlepage")
@EqualsAndHashCode(callSuper = true)
public class SinglePage extends AbstractExtension {

    public static final String KIND = "SinglePage";

    public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(SinglePage.class);
    public static final String DELETED_LABEL = "content.halo.run/deleted";
    public static final String PUBLISHED_LABEL = "content.halo.run/published";
    public static final String LAST_RELEASED_SNAPSHOT_ANNO =
        "content.halo.run/last-released-snapshot";
    public static final String OWNER_LABEL = "content.halo.run/owner";
    public static final String VISIBLE_LABEL = "content.halo.run/visible";

    @Schema(requiredMode = REQUIRED)
    private SinglePageSpec spec;

    @Schema
    private SinglePageStatus status;

    @JsonIgnore
    public SinglePageStatus getStatusOrDefault() {
        if (this.status == null) {
            this.status = new SinglePageStatus();
        }
        return this.status;
    }

    @JsonIgnore
    public boolean isPublished() {
        Map<String, String> labels = getMetadata().getLabels();
        return labels != null && labels.getOrDefault(PUBLISHED_LABEL, "false").equals("true");
    }

    @Data
    public static class SinglePageSpec {
        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String title;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String slug;

        /**
         * 引用到的已发布的内容,用于主题端显示.
         */
        private String releaseSnapshot;

        private String headSnapshot;

        private String baseSnapshot;

        private String owner;

        private String template;

        private String cover;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean deleted;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean publish;

        private Instant publishTime;

        @Schema(requiredMode = REQUIRED, defaultValue = "false")
        private Boolean pinned;

        @Schema(requiredMode = REQUIRED, defaultValue = "true")
        private Boolean allowComment;

        @Schema(requiredMode = REQUIRED, defaultValue = "PUBLIC")
        private Post.VisibleEnum visible;

        @Schema(requiredMode = REQUIRED, defaultValue = "0")
        private Integer priority;

        @Schema(requiredMode = REQUIRED)
        private Post.Excerpt excerpt;

        private List<Map<String, String>> htmlMetas;
    }

    @Data
    @EqualsAndHashCode(callSuper = true)
    public static class SinglePageStatus extends Post.PostStatus {

    }

    public static void changePublishedState(SinglePage page, boolean value) {
        Map<String, String> labels = MetadataUtil.nullSafeLabels(page);
        labels.put(PUBLISHED_LABEL, String.valueOf(value));
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Snapshot.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.util.LinkedHashSet;
import java.util.Set;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.Ref;

/**
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION, kind = Snapshot.KIND,
    plural = "snapshots", singular = "snapshot")
@EqualsAndHashCode(callSuper = true)
public class Snapshot extends AbstractExtension {
    public static final String KIND = "Snapshot";
    public static final String KEEP_RAW_ANNO = "content.halo.run/keep-raw";
    public static final String PATCHED_CONTENT_ANNO = "content.halo.run/patched-content";
    public static final String PATCHED_RAW_ANNO = "content.halo.run/patched-raw";

    @Schema(requiredMode = REQUIRED)
    private SnapShotSpec spec;

    @Data
    public static class SnapShotSpec {

        @Schema(requiredMode = REQUIRED)
        private Ref subjectRef;

        /**
         * such as: markdown | html | json | asciidoc | latex.
         */
        @Schema(requiredMode = REQUIRED, minLength = 1, maxLength = 50)
        private String rawType;

        private String rawPatch;

        private String contentPatch;

        private String parentSnapshotName;

        private Instant lastModifyTime;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String owner;

        private Set<String> contributors;
    }

    public static void addContributor(Snapshot snapshot, String name) {
        Assert.notNull(name, "The username must not be null.");
        Set<String> contributors = snapshot.getSpec().getContributors();
        if (contributors == null) {
            contributors = new LinkedHashSet<>();
            snapshot.getSpec().setContributors(contributors);
        }
        contributors.add(name);
    }

    /**
     * Check if the given snapshot is a base snapshot.
     *
     * @param snapshot must not be null.
     * @return true if the given snapshot is a base snapshot; false otherwise.
     */
    public static boolean isBaseSnapshot(@NonNull Snapshot snapshot) {
        var annotations = snapshot.getMetadata().getAnnotations();
        if (annotations == null) {
            return false;
        }
        return Boolean.parseBoolean(annotations.get(Snapshot.KEEP_RAW_ANNO));
    }

    public static String toSubjectRefKey(Ref subjectRef) {
        return subjectRef.getGroup() + "/" + subjectRef.getKind() + "/" + subjectRef.getName();
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/content/Tag.java
================================================
package run.halo.app.core.extension.content;

import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import run.halo.app.extension.AbstractExtension;
import run.halo.app.extension.GVK;
import run.halo.app.extension.GroupVersionKind;

/**
 * @author guqing
 * @see <a href="https://github.com/halo-dev/halo/issues/2322">issue#2322</a>
 * @since 2.0.0
 */
@Data
@ToString(callSuper = true)
@GVK(group = Constant.GROUP, version = Constant.VERSION,
    kind = Tag.KIND, plural = "tags", singular = "tag")
@EqualsAndHashCode(callSuper = true)
public class Tag extends AbstractExtension {

    public static final String KIND = "Tag";

    public static final GroupVersionKind GVK = GroupVersionKind.fromExtension(Tag.class);

    public static final String REQUIRE_SYNC_ON_STARTUP_INDEX_NAME = "requireSyncOnStartup";

    @Schema(requiredMode = REQUIRED)
    private TagSpec spec;

    @Schema
    private TagStatus status;

    @Data
    public static class TagSpec {

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String displayName;

        @Schema(requiredMode = REQUIRED, minLength = 1)
        private String slug;

        private String description;

        /**
         * Color regex explanation.
         * <pre>
         * ^                 # start of the line
         * #                 # start with a number sign `#`
         * (                 # start of (group 1)
         *   [a-fA-F0-9]{6}  # support z-f, A-F and 0-9, with a length of 6
         *   |               # or
         *   [a-fA-F0-9]{3}  # support z-f, A-F and 0-9, with a length of 3
         * )                 # end of (group 1)
         * $                 # end of the line
         * </pre>
         */
        @Schema(pattern = "^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$")
        private String color;

        private String cover;
    }

    @JsonIgnore
    public TagStatus getStatusOrDefault() {
        if (this.status == null) {
            this.status = new TagStatus();
        }
        return this.status;
    }

    @Data
    public static class TagStatus {

        private String permalink;

        public Integer visiblePostCount;

        public Integer postCount;

        private Long observedVersion;
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java
================================================
package run.halo.app.core.extension.endpoint;

import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerResponse;
import run.halo.app.extension.GroupVersion;

/**
 * RouterFunction provider for custom endpoints.
 *
 * @author johnniang
 */
public interface CustomEndpoint {

    RouterFunction<ServerResponse> endpoint();

    default GroupVersion groupVersion() {
        return GroupVersion.parseAPIVersion("api.console.halo.run/v1alpha1");
    }

}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java
================================================
package run.halo.app.core.extension.endpoint;

import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.ReactiveSortHandlerMethodArgumentResolver;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ServerWebExchange;

public interface SortResolver {

    SortResolver defaultInstance = new DefaultSortResolver();

    @NonNull
    Sort resolve(@NonNull ServerWebExchange exchange);

    class DefaultSortResolver extends ReactiveSortHandlerMethodArgumentResolver
        implements SortResolver {

        @Override
        @NonNull
        protected Sort getDefaultFromAnnotationOrFallback(@Nullable MethodParameter parameter) {
            return Sort.unsorted();
        }

        @Override
        public Sort resolve(ServerWebExchange exchange) {
            return resolveArgumentValue(null, null, exchange);
        }
    }
}


================================================
FILE: api/src/main/java/run/halo/app/core/extension/n
Download .txt
gitextract_qe2hhq1p/

├── .dockerignore
├── .editorconfig
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.en.yml
│   │   ├── bug_report.zh.yml
│   │   ├── config.yml
│   │   ├── feature_request.en.yml
│   │   └── feature_request.zh.yml
│   ├── actions/
│   │   ├── docker-buildx-push/
│   │   │   └── action.yaml
│   │   └── setup-env/
│   │       └── action.yaml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── halo.yaml
│       ├── openapi-check.yaml
│       ├── packages-preview-release.yaml
│       ├── release-ui-packages.yaml
│       └── stale-issues.yaml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── OWNERS
├── README.md
├── SECURITY.md
├── api/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── run/
│       │           └── halo/
│       │               └── app/
│       │                   ├── content/
│       │                   │   ├── ContentWrapper.java
│       │                   │   ├── ExcerptGenerator.java
│       │                   │   ├── PatchUtils.java
│       │                   │   ├── PostContentService.java
│       │                   │   └── comment/
│       │                   │       └── CommentSubject.java
│       │                   ├── core/
│       │                   │   ├── attachment/
│       │                   │   │   ├── ThumbnailProvider.java
│       │                   │   │   └── ThumbnailSize.java
│       │                   │   ├── endpoint/
│       │                   │   │   └── WebSocketEndpoint.java
│       │                   │   ├── extension/
│       │                   │   │   ├── AnnotationSetting.java
│       │                   │   │   ├── AuthProvider.java
│       │                   │   │   ├── Counter.java
│       │                   │   │   ├── Device.java
│       │                   │   │   ├── Menu.java
│       │                   │   │   ├── MenuItem.java
│       │                   │   │   ├── Plugin.java
│       │                   │   │   ├── RememberMeToken.java
│       │                   │   │   ├── ReverseProxy.java
│       │                   │   │   ├── Role.java
│       │                   │   │   ├── RoleBinding.java
│       │                   │   │   ├── Setting.java
│       │                   │   │   ├── Theme.java
│       │                   │   │   ├── User.java
│       │                   │   │   ├── UserConnection.java
│       │                   │   │   ├── attachment/
│       │                   │   │   │   ├── Attachment.java
│       │                   │   │   │   ├── Constant.java
│       │                   │   │   │   ├── Group.java
│       │                   │   │   │   ├── Policy.java
│       │                   │   │   │   ├── PolicyTemplate.java
│       │                   │   │   │   └── endpoint/
│       │                   │   │   │       ├── AttachmentHandler.java
│       │                   │   │   │       ├── DeleteOption.java
│       │                   │   │   │       ├── SimpleFilePart.java
│       │                   │   │   │       └── UploadOption.java
│       │                   │   │   ├── content/
│       │                   │   │   │   ├── Category.java
│       │                   │   │   │   ├── Comment.java
│       │                   │   │   │   ├── Constant.java
│       │                   │   │   │   ├── Post.java
│       │                   │   │   │   ├── Reply.java
│       │                   │   │   │   ├── SinglePage.java
│       │                   │   │   │   ├── Snapshot.java
│       │                   │   │   │   └── Tag.java
│       │                   │   │   ├── endpoint/
│       │                   │   │   │   ├── CustomEndpoint.java
│       │                   │   │   │   └── SortResolver.java
│       │                   │   │   ├── notification/
│       │                   │   │   │   ├── Notification.java
│       │                   │   │   │   ├── NotificationTemplate.java
│       │                   │   │   │   ├── NotifierDescriptor.java
│       │                   │   │   │   ├── Reason.java
│       │                   │   │   │   ├── ReasonType.java
│       │                   │   │   │   └── Subscription.java
│       │                   │   │   └── service/
│       │                   │   │       └── AttachmentService.java
│       │                   │   └── user/
│       │                   │       └── service/
│       │                   │           ├── RoleService.java
│       │                   │           ├── SignUpData.java
│       │                   │           ├── UserPostCreatingHandler.java
│       │                   │           ├── UserPreCreatingHandler.java
│       │                   │           └── UserService.java
│       │                   ├── event/
│       │                   │   ├── post/
│       │                   │   │   ├── PostDeletedEvent.java
│       │                   │   │   ├── PostEvent.java
│       │                   │   │   ├── PostPublishedEvent.java
│       │                   │   │   ├── PostUnpublishedEvent.java
│       │                   │   │   ├── PostUpdatedEvent.java
│       │                   │   │   └── PostVisibleChangedEvent.java
│       │                   │   └── user/
│       │                   │       ├── UserConnectionDisconnectedEvent.java
│       │                   │       ├── UserLoginEvent.java
│       │                   │       └── UserLogoutEvent.java
│       │                   ├── extension/
│       │                   │   ├── AbstractExtension.java
│       │                   │   ├── Comparators.java
│       │                   │   ├── ConfigMap.java
│       │                   │   ├── DefaultExtensionMatcher.java
│       │                   │   ├── Extension.java
│       │                   │   ├── ExtensionClient.java
│       │                   │   ├── ExtensionMatcher.java
│       │                   │   ├── ExtensionOperator.java
│       │                   │   ├── ExtensionUtil.java
│       │                   │   ├── GVK.java
│       │                   │   ├── GroupKind.java
│       │                   │   ├── GroupVersion.java
│       │                   │   ├── GroupVersionKind.java
│       │                   │   ├── JsonExtension.java
│       │                   │   ├── ListOptions.java
│       │                   │   ├── ListResult.java
│       │                   │   ├── Metadata.java
│       │                   │   ├── MetadataOperator.java
│       │                   │   ├── MetadataUtil.java
│       │                   │   ├── PageRequest.java
│       │                   │   ├── PageRequestImpl.java
│       │                   │   ├── ReactiveExtensionClient.java
│       │                   │   ├── Ref.java
│       │                   │   ├── Scheme.java
│       │                   │   ├── SchemeManager.java
│       │                   │   ├── Secret.java
│       │                   │   ├── Unstructured.java
│       │                   │   ├── Watcher.java
│       │                   │   ├── WatcherExtensionMatchers.java
│       │                   │   ├── WatcherPredicates.java
│       │                   │   ├── controller/
│       │                   │   │   ├── Controller.java
│       │                   │   │   ├── ControllerBuilder.java
│       │                   │   │   ├── DefaultController.java
│       │                   │   │   ├── DefaultQueue.java
│       │                   │   │   ├── ExtensionWatcher.java
│       │                   │   │   ├── Reconciler.java
│       │                   │   │   ├── RequestQueue.java
│       │                   │   │   ├── RequestSynchronizer.java
│       │                   │   │   ├── RequeueException.java
│       │                   │   │   └── Synchronizer.java
│       │                   │   ├── exception/
│       │                   │   │   ├── ExtensionException.java
│       │                   │   │   ├── NotImplementedException.java
│       │                   │   │   └── SchemeNotFoundException.java
│       │                   │   ├── index/
│       │                   │   │   ├── AbstractValueIndexSpecBuilder.java
│       │                   │   │   ├── DefaultIndexAttribute.java
│       │                   │   │   ├── IndexAttribute.java
│       │                   │   │   ├── IndexAttributeFactory.java
│       │                   │   │   ├── IndexSpec.java
│       │                   │   │   ├── IndexSpecBuilder.java
│       │                   │   │   ├── IndexSpecs.java
│       │                   │   │   ├── IndexedQueryEngine.java
│       │                   │   │   ├── KeyComparator.java
│       │                   │   │   ├── MultiValueBuilder.java
│       │                   │   │   ├── MultiValueIndexSpec.java
│       │                   │   │   ├── MultiValueIndexSpecBuilder.java
│       │                   │   │   ├── SingleValueBuilder.java
│       │                   │   │   ├── SingleValueIndexSpec.java
│       │                   │   │   ├── SingleValueIndexSpecBuilder.java
│       │                   │   │   ├── UnknownKey.java
│       │                   │   │   ├── ValueIndexSpec.java
│       │                   │   │   └── query/
│       │                   │   │       ├── AllCondition.java
│       │                   │   │       ├── And.java
│       │                   │   │       ├── AndCondition.java
│       │                   │   │       ├── BetweenCondition.java
│       │                   │   │       ├── Condition.java
│       │                   │   │       ├── EmptyCondition.java
│       │                   │   │       ├── EqualCondition.java
│       │                   │   │       ├── GreaterThanCondition.java
│       │                   │   │       ├── InCondition.java
│       │                   │   │       ├── IndexCondition.java
│       │                   │   │       ├── IsNotNullCondition.java
│       │                   │   │       ├── IsNullCondition.java
│       │                   │   │       ├── LabelCondition.java
│       │                   │   │       ├── LabelEqualsCondition.java
│       │                   │   │       ├── LabelExistsCondition.java
│       │                   │   │       ├── LabelInCondition.java
│       │                   │   │       ├── LabelNotEqualsCondition.java
│       │                   │   │       ├── LabelNotExistsCondition.java
│       │                   │   │       ├── LabelNotInCondition.java
│       │                   │   │       ├── LessThanCondition.java
│       │                   │   │       ├── NoneCondition.java
│       │                   │   │       ├── NotBetweenCondition.java
│       │                   │   │       ├── NotCondition.java
│       │                   │   │       ├── NotEqualCondition.java
│       │                   │   │       ├── NotInCondition.java
│       │                   │   │       ├── OrCondition.java
│       │                   │   │       ├── Queries.java
│       │                   │   │       ├── Query.java
│       │                   │   │       ├── QueryFactory.java
│       │                   │   │       ├── StringContainsCondition.java
│       │                   │   │       ├── StringEndsWithCondition.java
│       │                   │   │       ├── StringNotContainsCondition.java
│       │                   │   │       ├── StringNotEndsWithCondition.java
│       │                   │   │       ├── StringNotStartsWithCondition.java
│       │                   │   │       └── StringStartsWithCondition.java
│       │                   │   └── router/
│       │                   │       ├── IListRequest.java
│       │                   │       ├── QueryParamBuildUtil.java
│       │                   │       ├── SortableRequest.java
│       │                   │       └── selector/
│       │                   │           ├── FieldSelector.java
│       │                   │           ├── FieldSelectorConverter.java
│       │                   │           ├── LabelSelector.java
│       │                   │           ├── LabelSelectorConverter.java
│       │                   │           ├── Operator.java
│       │                   │           ├── SelectorConverter.java
│       │                   │           ├── SelectorCriteria.java
│       │                   │           └── SelectorUtil.java
│       │                   ├── infra/
│       │                   │   ├── AnonymousUserConst.java
│       │                   │   ├── BackupRootGetter.java
│       │                   │   ├── Condition.java
│       │                   │   ├── ConditionList.java
│       │                   │   ├── ConditionStatus.java
│       │                   │   ├── ExternalLinkProcessor.java
│       │                   │   ├── ExternalUrlSupplier.java
│       │                   │   ├── FileCategoryMatcher.java
│       │                   │   ├── SystemInfo.java
│       │                   │   ├── SystemInfoGetter.java
│       │                   │   ├── SystemSetting.java
│       │                   │   ├── SystemVersionSupplier.java
│       │                   │   ├── ValidationUtils.java
│       │                   │   ├── model/
│       │                   │   │   └── License.java
│       │                   │   └── utils/
│       │                   │       ├── FileTypeDetectUtils.java
│       │                   │       ├── GenericClassUtils.java
│       │                   │       ├── JsonParseException.java
│       │                   │       ├── JsonUtils.java
│       │                   │       └── PathUtils.java
│       │                   ├── migration/
│       │                   │   ├── Backup.java
│       │                   │   └── Constant.java
│       │                   ├── notification/
│       │                   │   ├── NotificationCenter.java
│       │                   │   ├── NotificationContext.java
│       │                   │   ├── NotificationReasonEmitter.java
│       │                   │   ├── ReactiveNotifier.java
│       │                   │   ├── ReasonAttributes.java
│       │                   │   ├── ReasonPayload.java
│       │                   │   └── UserIdentity.java
│       │                   ├── plugin/
│       │                   │   ├── ApiVersion.java
│       │                   │   ├── BasePlugin.java
│       │                   │   ├── PluginConfigUpdatedEvent.java
│       │                   │   ├── PluginContext.java
│       │                   │   ├── PluginsRootGetter.java
│       │                   │   ├── ReactiveSettingFetcher.java
│       │                   │   ├── SettingFetcher.java
│       │                   │   ├── SharedEvent.java
│       │                   │   ├── event/
│       │                   │   │   └── PluginStartedEvent.java
│       │                   │   └── extensionpoint/
│       │                   │       └── ExtensionGetter.java
│       │                   ├── search/
│       │                   │   ├── HaloDocument.java
│       │                   │   ├── HaloDocumentsProvider.java
│       │                   │   ├── SearchEngine.java
│       │                   │   ├── SearchOption.java
│       │                   │   ├── SearchResult.java
│       │                   │   ├── SearchService.java
│       │                   │   └── event/
│       │                   │       ├── HaloDocumentAddRequestEvent.java
│       │                   │       ├── HaloDocumentDeleteRequestEvent.java
│       │                   │       └── HaloDocumentRebuildRequestEvent.java
│       │                   ├── security/
│       │                   │   ├── AdditionalWebFilter.java
│       │                   │   ├── AfterSecurityWebFilter.java
│       │                   │   ├── AnonymousAuthenticationSecurityWebFilter.java
│       │                   │   ├── AuthenticationSecurityWebFilter.java
│       │                   │   ├── BeforeSecurityWebFilter.java
│       │                   │   ├── FormLoginSecurityWebFilter.java
│       │                   │   ├── HttpBasicSecurityWebFilter.java
│       │                   │   ├── LoginHandlerEnhancer.java
│       │                   │   ├── OAuth2AuthorizationCodeSecurityWebFilter.java
│       │                   │   ├── PersonalAccessToken.java
│       │                   │   ├── authentication/
│       │                   │   │   ├── CryptoService.java
│       │                   │   │   ├── login/
│       │                   │   │   │   └── UsernamePasswordAuthenticationManager.java
│       │                   │   │   └── oauth2/
│       │                   │   │       └── HaloOAuth2AuthenticationToken.java
│       │                   │   └── device/
│       │                   │       └── DeviceService.java
│       │                   └── theme/
│       │                       ├── Constant.java
│       │                       ├── ReactivePostContentHandler.java
│       │                       ├── ReactiveSinglePageContentHandler.java
│       │                       ├── TemplateNameResolver.java
│       │                       ├── dialect/
│       │                       │   ├── CommentWidget.java
│       │                       │   ├── ElementTagPostProcessor.java
│       │                       │   ├── TemplateFooterProcessor.java
│       │                       │   └── TemplateHeadProcessor.java
│       │                       ├── finders/
│       │                       │   ├── Finder.java
│       │                       │   └── vo/
│       │                       │       └── ExtensionVoOperator.java
│       │                       └── router/
│       │                           ├── ModelConst.java
│       │                           ├── PageUrlUtils.java
│       │                           └── UrlContextListResult.java
│       └── test/
│           └── java/
│               └── run/
│                   └── halo/
│                       └── app/
│                           ├── core/
│                           │   └── extension/
│                           │       ├── content/
│                           │       │   └── PostTest.java
│                           │       └── notification/
│                           │           └── SubscriptionTest.java
│                           ├── extension/
│                           │   ├── ExtensionUtilTest.java
│                           │   ├── FakeExtension.java
│                           │   ├── ListOptionsTest.java
│                           │   ├── PageRequestImplTest.java
│                           │   ├── SecretTest.java
│                           │   ├── controller/
│                           │   │   ├── ControllerBuilderTest.java
│                           │   │   ├── DefaultControllerTest.java
│                           │   │   ├── DefaultDelayQueueTest.java
│                           │   │   ├── DelayedEntryTest.java
│                           │   │   ├── ExtensionWatcherTest.java
│                           │   │   └── RequestSynchronizerTest.java
│                           │   ├── index/
│                           │   │   ├── IndexAttributeFactoryTest.java
│                           │   │   ├── IndexSpecTest.java
│                           │   │   ├── KeyComparatorTest.java
│                           │   │   ├── MultiValueBuilderTest.java
│                           │   │   ├── SingleValueBuilderTest.java
│                           │   │   ├── UnknownKeyTest.java
│                           │   │   └── query/
│                           │   │       └── QueriesTest.java
│                           │   ├── indexer/
│                           │   │   ├── DefaultIndexEngineTest.java
│                           │   │   └── LabelIndexImplTest.java
│                           │   └── router/
│                           │       └── selector/
│                           │           ├── LabelSelectorTest.java
│                           │           ├── OperatorTest.java
│                           │           └── SelectorConverterTest.java
│                           └── infra/
│                               └── utils/
│                                   ├── GenericClassUtilsTest.java
│                                   ├── JsonUtilsTest.java
│                                   └── PathUtilsTest.java
├── api-docs/
│   └── openapi/
│       └── v3_0/
│           ├── aggregated.json
│           ├── apis_console.api_v1alpha1.json
│           ├── apis_extension.api_v1alpha1.json
│           ├── apis_public.api_v1alpha1.json
│           └── apis_uc.api_v1alpha1.json
├── application/
│   ├── build.gradle
│   ├── libs/
│   │   ├── thymeleaf-3.1.3.RELEASE.jar
│   │   └── thymeleaf-spring6-3.1.3.RELEASE.jar
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── run/
│       │   │       └── halo/
│       │   │           └── app/
│       │   │               ├── Application.java
│       │   │               ├── content/
│       │   │               │   ├── AbstractContentService.java
│       │   │               │   ├── AbstractEventReconciler.java
│       │   │               │   ├── CategoryPostCountUpdater.java
│       │   │               │   ├── CategoryService.java
│       │   │               │   ├── Content.java
│       │   │               │   ├── ContentRequest.java
│       │   │               │   ├── ContentUpdateParam.java
│       │   │               │   ├── Contributor.java
│       │   │               │   ├── ListedPost.java
│       │   │               │   ├── ListedSinglePage.java
│       │   │               │   ├── ListedSnapshotDto.java
│       │   │               │   ├── NotificationReasonConst.java
│       │   │               │   ├── PostContentServiceImpl.java
│       │   │               │   ├── PostHideFromListStateUpdater.java
│       │   │               │   ├── PostQuery.java
│       │   │               │   ├── PostRequest.java
│       │   │               │   ├── PostService.java
│       │   │               │   ├── PostSorter.java
│       │   │               │   ├── SinglePageQuery.java
│       │   │               │   ├── SinglePageRequest.java
│       │   │               │   ├── SinglePageService.java
│       │   │               │   ├── SnapshotService.java
│       │   │               │   ├── Stats.java
│       │   │               │   ├── comment/
│       │   │               │   │   ├── AbstractCommentService.java
│       │   │               │   │   ├── CommentEmailOwner.java
│       │   │               │   │   ├── CommentNotificationReasonPublisher.java
│       │   │               │   │   ├── CommentQuery.java
│       │   │               │   │   ├── CommentRequest.java
│       │   │               │   │   ├── CommentService.java
│       │   │               │   │   ├── CommentServiceImpl.java
│       │   │               │   │   ├── CommentStats.java
│       │   │               │   │   ├── ListedComment.java
│       │   │               │   │   ├── ListedReply.java
│       │   │               │   │   ├── OwnerInfo.java
│       │   │               │   │   ├── PostCommentSubject.java
│       │   │               │   │   ├── ReplyNotificationSubscriptionHelper.java
│       │   │               │   │   ├── ReplyQuery.java
│       │   │               │   │   ├── ReplyRequest.java
│       │   │               │   │   ├── ReplyService.java
│       │   │               │   │   ├── ReplyServiceImpl.java
│       │   │               │   │   └── SinglePageCommentSubject.java
│       │   │               │   ├── impl/
│       │   │               │   │   ├── CategoryServiceImpl.java
│       │   │               │   │   ├── PostServiceImpl.java
│       │   │               │   │   ├── SinglePageServiceImpl.java
│       │   │               │   │   └── SnapshotServiceImpl.java
│       │   │               │   ├── permalinks/
│       │   │               │   │   ├── CategoryPermalinkPolicy.java
│       │   │               │   │   ├── ExtensionLocator.java
│       │   │               │   │   ├── PermalinkPolicy.java
│       │   │               │   │   ├── PostPermalinkPolicy.java
│       │   │               │   │   └── TagPermalinkPolicy.java
│       │   │               │   └── stats/
│       │   │               │       ├── PostStatsUpdater.java
│       │   │               │       ├── ReplyEventReconciler.java
│       │   │               │       ├── TagPostCountUpdater.java
│       │   │               │       ├── VisitedEventReconciler.java
│       │   │               │       └── VotedEventReconciler.java
│       │   │               ├── core/
│       │   │               │   ├── attachment/
│       │   │               │   │   ├── AttachmentChangedEvent.java
│       │   │               │   │   ├── AttachmentLister.java
│       │   │               │   │   ├── AttachmentRootGetter.java
│       │   │               │   │   ├── PolicyConfigChangeDetector.java
│       │   │               │   │   ├── SearchRequest.java
│       │   │               │   │   ├── endpoint/
│       │   │               │   │   │   ├── AttachmentEndpoint.java
│       │   │               │   │   │   ├── LocalAttachmentUploadHandler.java
│       │   │               │   │   │   └── PolicyEndpoint.java
│       │   │               │   │   ├── extension/
│       │   │               │   │   │   ├── LocalThumbnail.java
│       │   │               │   │   │   └── Thumbnail.java
│       │   │               │   │   ├── impl/
│       │   │               │   │   │   ├── AttachmentListerImpl.java
│       │   │               │   │   │   └── AttachmentRootGetterImpl.java
│       │   │               │   │   ├── reconciler/
│       │   │               │   │   │   ├── AttachmentReconciler.java
│       │   │               │   │   │   ├── LocalThumbnailsReconciler.java
│       │   │               │   │   │   ├── PolicyReconciler.java
│       │   │               │   │   │   └── ThumbnailReconciler.java
│       │   │               │   │   └── thumbnail/
│       │   │               │   │       ├── DefaultLocalThumbnailService.java
│       │   │               │   │       ├── DefaultThumbnailService.java
│       │   │               │   │       ├── LocalThumbnailService.java
│       │   │               │   │       ├── ThumbnailImgTagPostProcessor.java
│       │   │               │   │       ├── ThumbnailResourceTransformer.java
│       │   │               │   │       ├── ThumbnailService.java
│       │   │               │   │       └── ThumbnailUtils.java
│       │   │               │   ├── counter/
│       │   │               │   │   ├── CounterService.java
│       │   │               │   │   ├── CounterServiceImpl.java
│       │   │               │   │   └── MeterUtils.java
│       │   │               │   ├── endpoint/
│       │   │               │   │   ├── AttachmentHandler.java
│       │   │               │   │   ├── WebSocketEndpointManager.java
│       │   │               │   │   ├── WebSocketHandlerMapping.java
│       │   │               │   │   ├── console/
│       │   │               │   │   │   ├── AttachmentConsoleEndpoint.java
│       │   │               │   │   │   ├── AuthProviderEndpoint.java
│       │   │               │   │   │   ├── CommentEndpoint.java
│       │   │               │   │   │   ├── ConsoleUserEndpoint.java
│       │   │               │   │   │   ├── CustomEndpointsBuilder.java
│       │   │               │   │   │   ├── PluginEndpoint.java
│       │   │               │   │   │   ├── PostEndpoint.java
│       │   │               │   │   │   ├── ReplyEndpoint.java
│       │   │               │   │   │   ├── SinglePageEndpoint.java
│       │   │               │   │   │   ├── StatsEndpoint.java
│       │   │               │   │   │   ├── SystemConfigEndpoint.java
│       │   │               │   │   │   ├── TagEndpoint.java
│       │   │               │   │   │   ├── TrackerEndpoint.java
│       │   │               │   │   │   └── UserEndpoint.java
│       │   │               │   │   ├── theme/
│       │   │               │   │   │   ├── CategoryQueryEndpoint.java
│       │   │               │   │   │   ├── CommentFinderEndpoint.java
│       │   │               │   │   │   ├── MenuQueryEndpoint.java
│       │   │               │   │   │   ├── PluginQueryEndpoint.java
│       │   │               │   │   │   ├── PostPublicQuery.java
│       │   │               │   │   │   ├── PostQueryEndpoint.java
│       │   │               │   │   │   ├── PublicApiUtils.java
│       │   │               │   │   │   ├── SinglePageQueryEndpoint.java
│       │   │               │   │   │   ├── SiteStatsQueryEndpoint.java
│       │   │               │   │   │   ├── TagQueryEndpoint.java
│       │   │               │   │   │   └── ThumbnailEndpoint.java
│       │   │               │   │   └── uc/
│       │   │               │   │       ├── AnnotationSettingEndpoint.java
│       │   │               │   │       ├── AttachmentUcEndpoint.java
│       │   │               │   │       ├── UcPostEndpoint.java
│       │   │               │   │       ├── UcSnapshotEndpoint.java
│       │   │               │   │       ├── UcUserPreferenceEndpoint.java
│       │   │               │   │       └── UserConnectionEndpoint.java
│       │   │               │   ├── reconciler/
│       │   │               │   │   ├── AnnotationSettingReconciler.java
│       │   │               │   │   ├── AuthProviderReconciler.java
│       │   │               │   │   ├── CategoryReconciler.java
│       │   │               │   │   ├── CommentReconciler.java
│       │   │               │   │   ├── MenuItemReconciler.java
│       │   │               │   │   ├── PluginReconciler.java
│       │   │               │   │   ├── PostCounterReconciler.java
│       │   │               │   │   ├── PostReconciler.java
│       │   │               │   │   ├── ReplyReconciler.java
│       │   │               │   │   ├── ReverseProxyReconciler.java
│       │   │               │   │   ├── RoleReconciler.java
│       │   │               │   │   ├── SinglePageReconciler.java
│       │   │               │   │   ├── SystemConfigReconciler.java
│       │   │               │   │   ├── TagReconciler.java
│       │   │               │   │   ├── ThemeReconciler.java
│       │   │               │   │   └── UserReconciler.java
│       │   │               │   └── user/
│       │   │               │       └── service/
│       │   │               │           ├── DefaultRoleService.java
│       │   │               │           ├── EmailPasswordRecoveryService.java
│       │   │               │           ├── EmailVerificationService.java
│       │   │               │           ├── InMemoryResetTokenRepository.java
│       │   │               │           ├── InvalidResetTokenException.java
│       │   │               │           ├── PatService.java
│       │   │               │           ├── ResetToken.java
│       │   │               │           ├── ResetTokenRepository.java
│       │   │               │           ├── SettingConfigService.java
│       │   │               │           ├── UserConnectionService.java
│       │   │               │           ├── UserLoginOrLogoutProcessing.java
│       │   │               │           └── impl/
│       │   │               │               ├── DefaultAttachmentService.java
│       │   │               │               ├── EmailPasswordRecoveryServiceImpl.java
│       │   │               │               ├── EmailVerificationServiceImpl.java
│       │   │               │               ├── PatServiceImpl.java
│       │   │               │               ├── SettingConfigServiceImpl.java
│       │   │               │               ├── UserConnectionServiceImpl.java
│       │   │               │               └── UserServiceImpl.java
│       │   │               ├── event/
│       │   │               │   ├── post/
│       │   │               │   │   ├── CategoryHiddenStateChangeEvent.java
│       │   │               │   │   ├── CommentCreatedEvent.java
│       │   │               │   │   ├── CommentUnreadReplyCountChangedEvent.java
│       │   │               │   │   ├── DownvotedEvent.java
│       │   │               │   │   ├── PostStatsChangedEvent.java
│       │   │               │   │   ├── ReplyChangedEvent.java
│       │   │               │   │   ├── ReplyCreatedEvent.java
│       │   │               │   │   ├── ReplyDeletedEvent.java
│       │   │               │   │   ├── ReplyEvent.java
│       │   │               │   │   ├── UpvotedEvent.java
│       │   │               │   │   ├── VisitedEvent.java
│       │   │               │   │   └── VotedEvent.java
│       │   │               │   └── user/
│       │   │               │       └── PasswordChangedEvent.java
│       │   │               ├── extension/
│       │   │               │   ├── DefaultSchemeManager.java
│       │   │               │   ├── DelegateExtensionClient.java
│       │   │               │   ├── ExtensionConverter.java
│       │   │               │   ├── ExtensionStoreUtil.java
│       │   │               │   ├── JSONExtensionConverter.java
│       │   │               │   ├── ReactiveExtensionClientImpl.java
│       │   │               │   ├── availability/
│       │   │               │   │   └── IndexBuildState.java
│       │   │               │   ├── controller/
│       │   │               │   │   └── DefaultControllerManager.java
│       │   │               │   ├── event/
│       │   │               │   │   ├── IndexerBuiltEvent.java
│       │   │               │   │   ├── SchemeAddedEvent.java
│       │   │               │   │   └── SchemeRemovedEvent.java
│       │   │               │   ├── exception/
│       │   │               │   │   ├── ExtensionConvertException.java
│       │   │               │   │   ├── ExtensionNotFoundException.java
│       │   │               │   │   └── SchemaViolationException.java
│       │   │               │   ├── gc/
│       │   │               │   │   ├── GcControllerInitializer.java
│       │   │               │   │   ├── GcReconciler.java
│       │   │               │   │   ├── GcRequest.java
│       │   │               │   │   ├── GcSynchronizer.java
│       │   │               │   │   └── GcWatcher.java
│       │   │               │   ├── index/
│       │   │               │   │   ├── DefaultIndexEngine.java
│       │   │               │   │   ├── DefaultIndices.java
│       │   │               │   │   ├── DefaultIndicesManager.java
│       │   │               │   │   ├── Index.java
│       │   │               │   │   ├── IndexEngine.java
│       │   │               │   │   ├── Indices.java
│       │   │               │   │   ├── IndicesInitializer.java
│       │   │               │   │   ├── IndicesManager.java
│       │   │               │   │   ├── LabelIndex.java
│       │   │               │   │   ├── LabelIndexQuery.java
│       │   │               │   │   ├── MultiValueIndex.java
│       │   │               │   │   ├── SingleValueIndex.java
│       │   │               │   │   ├── StringUnknownKeyConverter.java
│       │   │               │   │   ├── TransactionalOperation.java
│       │   │               │   │   ├── ValueIndexQuery.java
│       │   │               │   │   └── query/
│       │   │               │   │       └── QueryVisitor.java
│       │   │               │   ├── indexer/
│       │   │               │   │   └── DefaultIndicesInitializer.java
│       │   │               │   ├── router/
│       │   │               │   │   ├── ExtensionCompositeRouterFunction.java
│       │   │               │   │   ├── ExtensionCreateHandler.java
│       │   │               │   │   ├── ExtensionDeleteHandler.java
│       │   │               │   │   ├── ExtensionGetHandler.java
│       │   │               │   │   ├── ExtensionListHandler.java
│       │   │               │   │   ├── ExtensionPatchHandler.java
│       │   │               │   │   ├── ExtensionRouterFunctionFactory.java
│       │   │               │   │   ├── ExtensionUpdateHandler.java
│       │   │               │   │   └── JsonPatch.java
│       │   │               │   └── store/
│       │   │               │       ├── ExtensionStore.java
│       │   │               │       ├── ExtensionStoreClient.java
│       │   │               │       ├── ExtensionStoreClientJPAImpl.java
│       │   │               │       ├── ExtensionStoreRepository.java
│       │   │               │       ├── ReactiveExtensionStoreClient.java
│       │   │               │       └── ReactiveExtensionStoreClientImpl.java
│       │   │               ├── infra/
│       │   │               │   ├── DefaultBackupRootGetter.java
│       │   │               │   ├── DefaultExternalLinkProcessor.java
│       │   │               │   ├── DefaultInitializationStateGetter.java
│       │   │               │   ├── DefaultReactiveUrlDataBufferFetcher.java
│       │   │               │   ├── DefaultSystemConfigFetcher.java
│       │   │               │   ├── DefaultSystemVersionSupplier.java
│       │   │               │   ├── DefaultThemeRootGetter.java
│       │   │               │   ├── ExtensionInitializedEvent.java
│       │   │               │   ├── ExtensionResourceInitializer.java
│       │   │               │   ├── ExternalUrlChangedEvent.java
│       │   │               │   ├── InitializationPhase.java
│       │   │               │   ├── InitializationStateGetter.java
│       │   │               │   ├── ReactiveExtensionPaginatedOperator.java
│       │   │               │   ├── ReactiveExtensionPaginatedOperatorImpl.java
│       │   │               │   ├── ReactiveUrlDataBufferFetcher.java
│       │   │               │   ├── SchemeInitializer.java
│       │   │               │   ├── SecureRequestMappingHandlerAdapter.java
│       │   │               │   ├── SecureServerRequest.java
│       │   │               │   ├── SecureServerWebExchange.java
│       │   │               │   ├── SystemConfigChangedEvent.java
│       │   │               │   ├── SystemConfigFetcher.java
│       │   │               │   ├── SystemConfigFirstExternalUrlSupplier.java
│       │   │               │   ├── SystemConfigInitializer.java
│       │   │               │   ├── SystemInfoGetterImpl.java
│       │   │               │   ├── SystemState.java
│       │   │               │   ├── ThemeRootGetter.java
│       │   │               │   ├── actuator/
│       │   │               │   │   ├── DatabaseInfoContributor.java
│       │   │               │   │   ├── GlobalInfo.java
│       │   │               │   │   ├── GlobalInfoEndpoint.java
│       │   │               │   │   ├── GlobalInfoService.java
│       │   │               │   │   ├── GlobalInfoServiceImpl.java
│       │   │               │   │   └── RestartEndpoint.java
│       │   │               │   ├── config/
│       │   │               │   │   ├── ExtensionConfiguration.java
│       │   │               │   │   ├── HaloConfiguration.java
│       │   │               │   │   ├── JacksonAdapterModule.java
│       │   │               │   │   ├── R2dbcConfiguration.java
│       │   │               │   │   ├── SessionConfiguration.java
│       │   │               │   │   ├── SwaggerConfig.java
│       │   │               │   │   ├── WebFluxConfig.java
│       │   │               │   │   └── WebServerSecurityConfig.java
│       │   │               │   ├── exception/
│       │   │               │   │   ├── AccessDeniedException.java
│       │   │               │   │   ├── AttachmentAlreadyExistsException.java
│       │   │               │   │   ├── DuplicateNameException.java
│       │   │               │   │   ├── EmailAlreadyTakenException.java
│       │   │               │   │   ├── EmailVerificationFailed.java
│       │   │               │   │   ├── Exceptions.java
│       │   │               │   │   ├── FileSizeExceededException.java
│       │   │               │   │   ├── FileTypeNotAllowedException.java
│       │   │               │   │   ├── NotFoundException.java
│       │   │               │   │   ├── OAuth2UserAlreadyBoundException.java
│       │   │               │   │   ├── PluginAlreadyExistsException.java
│       │   │               │   │   ├── PluginDependenciesNotEnabledException.java
│       │   │               │   │   ├── PluginDependencyException.java
│       │   │               │   │   ├── PluginDependentsNotDisabledException.java
│       │   │               │   │   ├── PluginInstallationException.java
│       │   │               │   │   ├── PluginRuntimeIncompatibleException.java
│       │   │               │   │   ├── RateLimitExceededException.java
│       │   │               │   │   ├── RequestBodyValidationException.java
│       │   │               │   │   ├── RequestRestrictedException.java
│       │   │               │   │   ├── RestrictedNameException.java
│       │   │               │   │   ├── ThemeAlreadyExistsException.java
│       │   │               │   │   ├── ThemeInstallationException.java
│       │   │               │   │   ├── ThemeUninstallException.java
│       │   │               │   │   ├── ThemeUpgradeException.java
│       │   │               │   │   ├── UnsatisfiedAttributeValueException.java
│       │   │               │   │   ├── UserNotFoundException.java
│       │   │               │   │   └── handlers/
│       │   │               │   │       ├── HaloErrorConfiguration.java
│       │   │               │   │       ├── HaloErrorWebExceptionHandler.java
│       │   │               │   │       └── ProblemDetailErrorAttributes.java
│       │   │               │   ├── properties/
│       │   │               │   │   ├── AttachmentProperties.java
│       │   │               │   │   ├── CacheProperties.java
│       │   │               │   │   ├── ExtensionProperties.java
│       │   │               │   │   ├── HaloProperties.java
│       │   │               │   │   ├── JwtProperties.java
│       │   │               │   │   ├── ProxyProperties.java
│       │   │               │   │   ├── SecurityProperties.java
│       │   │               │   │   ├── ThemeProperties.java
│       │   │               │   │   └── UiProperties.java
│       │   │               │   ├── ui/
│       │   │               │   │   ├── ProxyFilter.java
│       │   │               │   │   ├── WebSocketRequestPredicate.java
│       │   │               │   │   ├── WebSocketServerWebExchangeMatcher.java
│       │   │               │   │   └── WebSocketUtils.java
│       │   │               │   ├── utils/
│       │   │               │   │   ├── Base62Utils.java
│       │   │               │   │   ├── FileNameUtils.java
│       │   │               │   │   ├── FileUtils.java
│       │   │               │   │   ├── HaloUtils.java
│       │   │               │   │   ├── IpAddressUtils.java
│       │   │               │   │   ├── ReactiveUtils.java
│       │   │               │   │   ├── SettingUtils.java
│       │   │               │   │   ├── SortUtils.java
│       │   │               │   │   ├── SystemConfigUtils.java
│       │   │               │   │   ├── VersionUtils.java
│       │   │               │   │   └── YamlUnstructuredLoader.java
│       │   │               │   └── webfilter/
│       │   │               │       ├── AdditionalWebFilterChainProxy.java
│       │   │               │       └── LocaleChangeWebFilter.java
│       │   │               ├── migration/
│       │   │               │   ├── BackupFile.java
│       │   │               │   ├── BackupReconciler.java
│       │   │               │   ├── MigrationEndpoint.java
│       │   │               │   ├── MigrationService.java
│       │   │               │   └── impl/
│       │   │               │       └── MigrationServiceImpl.java
│       │   │               ├── notification/
│       │   │               │   ├── DefaultNotificationCenter.java
│       │   │               │   ├── DefaultNotificationReasonEmitter.java
│       │   │               │   ├── DefaultNotificationSender.java
│       │   │               │   ├── DefaultNotificationService.java
│       │   │               │   ├── DefaultNotificationTemplateRender.java
│       │   │               │   ├── DefaultNotifierConfigStore.java
│       │   │               │   ├── DefaultSubscriberEmailResolver.java
│       │   │               │   ├── EmailNotifier.java
│       │   │               │   ├── EmailSenderHelper.java
│       │   │               │   ├── EmailSenderHelperImpl.java
│       │   │               │   ├── LanguageUtils.java
│       │   │               │   ├── NotificationSender.java
│       │   │               │   ├── NotificationTemplateRender.java
│       │   │               │   ├── NotificationTrigger.java
│       │   │               │   ├── NotifierConfigStore.java
│       │   │               │   ├── ReasonNotificationTemplateSelector.java
│       │   │               │   ├── ReasonNotificationTemplateSelectorImpl.java
│       │   │               │   ├── RecipientResolver.java
│       │   │               │   ├── RecipientResolverImpl.java
│       │   │               │   ├── Subscriber.java
│       │   │               │   ├── SubscriberEmailResolver.java
│       │   │               │   ├── SubscriptionService.java
│       │   │               │   ├── SubscriptionServiceImpl.java
│       │   │               │   ├── UserNotificationPreference.java
│       │   │               │   ├── UserNotificationPreferenceService.java
│       │   │               │   ├── UserNotificationPreferenceServiceImpl.java
│       │   │               │   ├── UserNotificationQuery.java
│       │   │               │   ├── UserNotificationService.java
│       │   │               │   └── endpoint/
│       │   │               │       ├── ConsoleNotifierEndpoint.java
│       │   │               │       ├── EmailConfigValidationEndpoint.java
│       │   │               │       ├── SubscriptionRouter.java
│       │   │               │       ├── UserNotificationEndpoint.java
│       │   │               │       ├── UserNotificationPreferencesEndpoint.java
│       │   │               │       └── UserNotifierEndpoint.java
│       │   │               ├── plugin/
│       │   │               │   ├── AggregatedRouterFunction.java
│       │   │               │   ├── BuiltInPluginsInitializer.java
│       │   │               │   ├── DefaultDevelopmentPluginRepository.java
│       │   │               │   ├── DefaultPluginApplicationContextFactory.java
│       │   │               │   ├── DefaultPluginGetter.java
│       │   │               │   ├── DefaultPluginRouterFunctionRegistry.java
│       │   │               │   ├── DefaultReactiveSettingFetcher.java
│       │   │               │   ├── DefaultSettingFetcher.java
│       │   │               │   ├── DefaultSpringPlugin.java
│       │   │               │   ├── DevPluginLoader.java
│       │   │               │   ├── HaloPluginManager.java
│       │   │               │   ├── HaloSharedEventDelegator.java
│       │   │               │   ├── OptionalDependentResolver.java
│       │   │               │   ├── PluginApplicationContext.java
│       │   │               │   ├── PluginApplicationContextFactory.java
│       │   │               │   ├── PluginAutoConfiguration.java
│       │   │               │   ├── PluginBeforeStopSyncListener.java
│       │   │               │   ├── PluginConst.java
│       │   │               │   ├── PluginControllerManager.java
│       │   │               │   ├── PluginDevelopmentInitializer.java
│       │   │               │   ├── PluginExtensionLoaderUtils.java
│       │   │               │   ├── PluginFinder.java
│       │   │               │   ├── PluginGetter.java
│       │   │               │   ├── PluginNotFoundException.java
│       │   │               │   ├── PluginProperties.java
│       │   │               │   ├── PluginRequestMappingHandlerMapping.java
│       │   │               │   ├── PluginRouterFunctionRegistry.java
│       │   │               │   ├── PluginService.java
│       │   │               │   ├── PluginServiceImpl.java
│       │   │               │   ├── PluginSharedEventDelegator.java
│       │   │               │   ├── PluginStartedListener.java
│       │   │               │   ├── PluginUtils.java
│       │   │               │   ├── PluginsRootGetterImpl.java
│       │   │               │   ├── PropertyPluginStatusProvider.java
│       │   │               │   ├── SharedApplicationContextFactory.java
│       │   │               │   ├── SharedEventDispatcher.java
│       │   │               │   ├── SpringComponentsFinder.java
│       │   │               │   ├── SpringExtensionFactory.java
│       │   │               │   ├── SpringPlugin.java
│       │   │               │   ├── SpringPluginFactory.java
│       │   │               │   ├── SpringPluginManager.java
│       │   │               │   ├── YamlPluginDescriptorFinder.java
│       │   │               │   ├── YamlPluginFinder.java
│       │   │               │   ├── event/
│       │   │               │   │   ├── HaloPluginBeforeStopEvent.java
│       │   │               │   │   ├── HaloPluginStartedEvent.java
│       │   │               │   │   ├── HaloPluginStoppedEvent.java
│       │   │               │   │   ├── SpringPluginStartedEvent.java
│       │   │               │   │   ├── SpringPluginStartingEvent.java
│       │   │               │   │   ├── SpringPluginStoppedEvent.java
│       │   │               │   │   └── SpringPluginStoppingEvent.java
│       │   │               │   ├── extensionpoint/
│       │   │               │   │   ├── AbstractDefinitionGetter.java
│       │   │               │   │   ├── DefaultExtensionGetter.java
│       │   │               │   │   ├── ExtensionDefinition.java
│       │   │               │   │   ├── ExtensionDefinitionGetter.java
│       │   │               │   │   ├── ExtensionDefinitionGetterImpl.java
│       │   │               │   │   ├── ExtensionPointDefinition.java
│       │   │               │   │   ├── ExtensionPointDefinitionGetter.java
│       │   │               │   │   └── ExtensionPointDefinitionGetterImpl.java
│       │   │               │   └── resources/
│       │   │               │       ├── BundleResourceUtils.java
│       │   │               │       ├── ReverseProxyRouterFunctionFactory.java
│       │   │               │       └── ReverseProxyRouterFunctionRegistry.java
│       │   │               ├── search/
│       │   │               │   ├── HaloDocumentEventsListener.java
│       │   │               │   ├── IndexEndpoint.java
│       │   │               │   ├── IndicesEndpoint.java
│       │   │               │   ├── SearchEngineUnavailableException.java
│       │   │               │   ├── SearchServiceImpl.java
│       │   │               │   ├── lucene/
│       │   │               │   │   └── LuceneSearchEngine.java
│       │   │               │   └── post/
│       │   │               │       ├── PostEventsListener.java
│       │   │               │       └── PostHaloDocumentsProvider.java
│       │   │               ├── security/
│       │   │               │   ├── AuthProviderService.java
│       │   │               │   ├── AuthProviderServiceImpl.java
│       │   │               │   ├── CorsConfigurer.java
│       │   │               │   ├── CsrfConfigurer.java
│       │   │               │   ├── DefaultServerAuthenticationEntryPoint.java
│       │   │               │   ├── DefaultSuperAdminInitializer.java
│       │   │               │   ├── DefaultUserDetailService.java
│       │   │               │   ├── ExceptionSecurityConfigurer.java
│       │   │               │   ├── HaloRedirectAuthenticationSuccessHandler.java
│       │   │               │   ├── HaloServerRequestCache.java
│       │   │               │   ├── HaloUserDetails.java
│       │   │               │   ├── InitializeRedirectionWebFilter.java
│       │   │               │   ├── ListedAuthProvider.java
│       │   │               │   ├── LoginHandlerEnhancerImpl.java
│       │   │               │   ├── LogoutSecurityConfigurer.java
│       │   │               │   ├── RedirectAccessDeniedHandler.java
│       │   │               │   ├── SecurityWebFiltersConfigurer.java
│       │   │               │   ├── SuperAdminInitializer.java
│       │   │               │   ├── authentication/
│       │   │               │   │   ├── SecurityConfigurer.java
│       │   │               │   │   ├── WebExchangeMatchers.java
│       │   │               │   │   ├── exception/
│       │   │               │   │   │   ├── TooManyRequestsException.java
│       │   │               │   │   │   └── TwoFactorAuthException.java
│       │   │               │   │   ├── impl/
│       │   │               │   │   │   └── RsaKeyService.java
│       │   │               │   │   ├── login/
│       │   │               │   │   │   ├── HaloUser.java
│       │   │               │   │   │   ├── InvalidEncryptedMessageException.java
│       │   │               │   │   │   ├── LoginAuthenticationConverter.java
│       │   │               │   │   │   ├── LoginSecurityConfigurer.java
│       │   │               │   │   │   ├── PublicKeyRouteBuilder.java
│       │   │               │   │   │   ├── UsernamePasswordDelegatingAuthenticationManager.java
│       │   │               │   │   │   └── UsernamePasswordHandler.java
│       │   │               │   │   ├── oauth2/
│       │   │               │   │   │   ├── DefaultOAuth2LoginHandlerEnhancer.java
│       │   │               │   │   │   ├── MapOAuth2AuthenticationFilter.java
│       │   │               │   │   │   ├── OAuth2AuthenticationTokenCache.java
│       │   │               │   │   │   ├── OAuth2LoginHandlerEnhancer.java
│       │   │               │   │   │   ├── OAuth2SecurityConfigurer.java
│       │   │               │   │   │   └── WebSessionOAuth2AuthenticationTokenCache.java
│       │   │               │   │   ├── pat/
│       │   │               │   │   │   ├── PatAuthenticationConverter.java
│       │   │               │   │   │   ├── PatAuthenticationManager.java
│       │   │               │   │   │   ├── PatEndpoint.java
│       │   │               │   │   │   ├── PatSecurityConfigurer.java
│       │   │               │   │   │   ├── UserScopedPatHandler.java
│       │   │               │   │   │   └── UserScopedPatHandlerImpl.java
│       │   │               │   │   ├── rememberme/
│       │   │               │   │   │   ├── CookieSignatureKeyResolver.java
│       │   │               │   │   │   ├── DefaultCookieSignatureKeyResolver.java
│       │   │               │   │   │   ├── PersistentRememberMeTokenRepository.java
│       │   │               │   │   │   ├── PersistentRememberMeTokenRepositoryImpl.java
│       │   │               │   │   │   ├── PersistentTokenBasedRememberMeServices.java
│       │   │               │   │   │   ├── RememberMeAuthenticationManager.java
│       │   │               │   │   │   ├── RememberMeConfigurer.java
│       │   │               │   │   │   ├── RememberMeCookieResolver.java
│       │   │               │   │   │   ├── RememberMeCookieResolverImpl.java
│       │   │               │   │   │   ├── RememberMeRequestCache.java
│       │   │               │   │   │   ├── RememberMeServices.java
│       │   │               │   │   │   ├── RememberMeTokenRevoker.java
│       │   │               │   │   │   ├── RememberTokenCleaner.java
│       │   │               │   │   │   ├── TokenBasedRememberMeServices.java
│       │   │               │   │   │   └── WebSessionRememberMeRequestCache.java
│       │   │               │   │   └── twofactor/
│       │   │               │   │       ├── TotpAuthenticationSuccessHandler.java
│       │   │               │   │       ├── TwoFactorAuthEndpoint.java
│       │   │               │   │       ├── TwoFactorAuthRequiredException.java
│       │   │               │   │       ├── TwoFactorAuthSecurityConfigurer.java
│       │   │               │   │       ├── TwoFactorAuthSettings.java
│       │   │               │   │       ├── TwoFactorAuthentication.java
│       │   │               │   │       ├── TwoFactorAuthenticationEntryPoint.java
│       │   │               │   │       ├── TwoFactorUtils.java
│       │   │               │   │       └── totp/
│       │   │               │   │           ├── DefaultTotpAuthService.java
│       │   │               │   │           ├── TotpAuthService.java
│       │   │               │   │           ├── TotpAuthenticationManager.java
│       │   │               │   │           ├── TotpAuthenticationToken.java
│       │   │               │   │           └── TotpCodeAuthenticationConverter.java
│       │   │               │   ├── authorization/
│       │   │               │   │   ├── Attributes.java
│       │   │               │   │   ├── AttributesRecord.java
│       │   │               │   │   ├── AuthorityUtils.java
│       │   │               │   │   ├── AuthorizationExchangeConfigurers.java
│       │   │               │   │   ├── AuthorizationRuleResolver.java
│       │   │               │   │   ├── AuthorizingVisitor.java
│       │   │               │   │   ├── DefaultRuleResolver.java
│       │   │               │   │   ├── PolicyRuleList.java
│       │   │               │   │   ├── RbacRequestEvaluation.java
│       │   │               │   │   ├── RequestInfo.java
│       │   │               │   │   ├── RequestInfoAuthorizationManager.java
│       │   │               │   │   ├── RequestInfoFactory.java
│       │   │               │   │   └── RuleAccumulator.java
│       │   │               │   ├── device/
│       │   │               │   │   ├── DeviceCookieResolver.java
│       │   │               │   │   ├── DeviceCookieResolverImpl.java
│       │   │               │   │   ├── DeviceEndpoint.java
│       │   │               │   │   ├── DeviceReconciler.java
│       │   │               │   │   ├── DeviceSecurityConfigurer.java
│       │   │               │   │   ├── DeviceServiceImpl.java
│       │   │               │   │   ├── DeviceSessionFilter.java
│       │   │               │   │   ├── NewDeviceLoginEvent.java
│       │   │               │   │   └── NewDeviceLoginListener.java
│       │   │               │   ├── jackson2/
│       │   │               │   │   ├── HaloOAuth2AuthenticationTokenMixin.java
│       │   │               │   │   ├── HaloSecurityJackson2Module.java
│       │   │               │   │   ├── HaloUserMixin.java
│       │   │               │   │   ├── SwitchUserGrantedAuthorityMixIn.java
│       │   │               │   │   └── TwoFactorAuthenticationMixin.java
│       │   │               │   ├── preauth/
│       │   │               │   │   ├── DefaultPasswordResetAvailabilityProviders.java
│       │   │               │   │   ├── EmailPasswordResetAvailabilityProvider.java
│       │   │               │   │   ├── PasswordResetAvailabilityProvider.java
│       │   │               │   │   ├── PasswordResetAvailabilityProviders.java
│       │   │               │   │   ├── PreAuthEmailPasswordResetEndpoint.java
│       │   │               │   │   ├── PreAuthLoginEndpoint.java
│       │   │               │   │   ├── PreAuthSignUpEndpoint.java
│       │   │               │   │   ├── PreAuthTwoFactorEndpoint.java
│       │   │               │   │   └── SystemSetupEndpoint.java
│       │   │               │   ├── session/
│       │   │               │   │   ├── InMemoryReactiveIndexedSessionRepository.java
│       │   │               │   │   ├── ReactiveIndexedSessionRepository.java
│       │   │               │   │   └── SessionInvalidationListener.java
│       │   │               │   └── switchuser/
│       │   │               │       └── SwitchUserConfigurer.java
│       │   │               └── theme/
│       │   │                   ├── CompositeTemplateResolver.java
│       │   │                   ├── DefaultTemplateEnum.java
│       │   │                   ├── DefaultTemplateNameResolver.java
│       │   │                   ├── DefaultViewNameResolver.java
│       │   │                   ├── HaloViewResolver.java
│       │   │                   ├── ReactiveSpelVariableExpressionEvaluator.java
│       │   │                   ├── SiteSettingVariablesAcquirer.java
│       │   │                   ├── TemplateEngineManager.java
│       │   │                   ├── ThemeContext.java
│       │   │                   ├── ThemeContextBasedVariablesAcquirer.java
│       │   │                   ├── ThemeLinkBuilder.java
│       │   │                   ├── ThemeLocaleContextResolver.java
│       │   │                   ├── ThemeResolver.java
│       │   │                   ├── UserLocaleRequestAttributeWriteFilter.java
│       │   │                   ├── ViewContextBasedVariablesAcquirer.java
│       │   │                   ├── ViewNameResolver.java
│       │   │                   ├── config/
│       │   │                   │   ├── ThemeConfiguration.java
│       │   │                   │   └── ThemeWebFluxConfigurer.java
│       │   │                   ├── dialect/
│       │   │                   │   ├── CommentElementTagProcessor.java
│       │   │                   │   ├── CommentEnabledVariableProcessor.java
│       │   │                   │   ├── ContentTemplateHeadProcessor.java
│       │   │                   │   ├── DefaultFaviconHeadProcessor.java
│       │   │                   │   ├── DefaultLinkExpressionFactory.java
│       │   │                   │   ├── DuplicateMetaTagProcessor.java
│       │   │                   │   ├── EvaluationContextEnhancer.java
│       │   │                   │   ├── GeneratorMetaProcessor.java
│       │   │                   │   ├── GlobalHeadInjectionProcessor.java
│       │   │                   │   ├── GlobalSeoProcessor.java
│       │   │                   │   ├── HaloExpressionObjectFactory.java
│       │   │                   │   ├── HaloPostTemplateHandler.java
│       │   │                   │   ├── HaloProcessorDialect.java
│       │   │                   │   ├── HaloSpringSecurityDialect.java
│       │   │                   │   ├── HaloTrackerProcessor.java
│       │   │                   │   ├── IndexSeoProcessor.java
│       │   │                   │   ├── InjectionExcluderProcessor.java
│       │   │                   │   ├── LinkExpressionObjectDialect.java
│       │   │                   │   ├── SecureTemplateContext.java
│       │   │                   │   ├── SecureTemplateContextWrapper.java
│       │   │                   │   ├── SecureTemplateWebContext.java
│       │   │                   │   ├── TemplateFooterElementTagProcessor.java
│       │   │                   │   ├── TemplateGlobalHeadProcessor.java
│       │   │                   │   └── expression/
│       │   │                   │       └── Annotations.java
│       │   │                   ├── endpoint/
│       │   │                   │   └── ThemeEndpoint.java
│       │   │                   ├── engine/
│       │   │                   │   ├── DefaultThemeTemplateAvailabilityProvider.java
│       │   │                   │   ├── HaloTemplateEngine.java
│       │   │                   │   ├── PluginClassloaderTemplateResolver.java
│       │   │                   │   └── ThemeTemplateAvailabilityProvider.java
│       │   │                   ├── finders/
│       │   │                   │   ├── CategoryFinder.java
│       │   │                   │   ├── CommentFinder.java
│       │   │                   │   ├── CommentPublicQueryService.java
│       │   │                   │   ├── ContributorFinder.java
│       │   │                   │   ├── DefaultFinderRegistry.java
│       │   │                   │   ├── FinderRegistry.java
│       │   │                   │   ├── MenuFinder.java
│       │   │                   │   ├── PluginFinder.java
│       │   │                   │   ├── PostFinder.java
│       │   │                   │   ├── PostPublicQueryService.java
│       │   │                   │   ├── SinglePageConversionService.java
│       │   │                   │   ├── SinglePageFinder.java
│       │   │                   │   ├── SiteStatsFinder.java
│       │   │                   │   ├── TagFinder.java
│       │   │                   │   ├── ThemeFinder.java
│       │   │                   │   ├── ThumbnailFinder.java
│       │   │                   │   ├── impl/
│       │   │                   │   │   ├── CategoryFinderImpl.java
│       │   │                   │   │   ├── CommentFinderImpl.java
│       │   │                   │   │   ├── CommentPublicQueryServiceImpl.java
│       │   │                   │   │   ├── ContributorFinderImpl.java
│       │   │                   │   │   ├── MenuFinderImpl.java
│       │   │                   │   │   ├── PluginFinderImpl.java
│       │   │                   │   │   ├── PostFinderImpl.java
│       │   │                   │   │   ├── PostPublicQueryServiceImpl.java
│       │   │                   │   │   ├── SinglePageConversionServiceImpl.java
│       │   │                   │   │   ├── SinglePageFinderImpl.java
│       │   │                   │   │   ├── SiteStatsFinderImpl.java
│       │   │                   │   │   ├── TagFinderImpl.java
│       │   │                   │   │   ├── ThemeFinderImpl.java
│       │   │                   │   │   └── ThumbnailFinderImpl.java
│       │   │                   │   └── vo/
│       │   │                   │       ├── CategoryTreeVo.java
│       │   │                   │       ├── CategoryVo.java
│       │   │                   │       ├── CommentStatsVo.java
│       │   │                   │       ├── CommentVo.java
│       │   │                   │       ├── CommentWithReplyVo.java
│       │   │                   │       ├── ContentVo.java
│       │   │                   │       ├── ContributorVo.java
│       │   │                   │       ├── ListedPostVo.java
│       │   │                   │       ├── ListedSinglePageVo.java
│       │   │                   │       ├── MenuItemVo.java
│       │   │                   │       ├── MenuVo.java
│       │   │                   │       ├── NavigationPostVo.java
│       │   │                   │       ├── PostArchiveVo.java
│       │   │                   │       ├── PostArchiveYearMonthVo.java
│       │   │                   │       ├── PostVo.java
│       │   │                   │       ├── ReplyVo.java
│       │   │                   │       ├── SinglePageVo.java
│       │   │                   │       ├── SiteSettingVo.java
│       │   │                   │       ├── SiteStatsVo.java
│       │   │                   │       ├── StatsVo.java
│       │   │                   │       ├── TagVo.java
│       │   │                   │       ├── ThemeVo.java
│       │   │                   │       ├── UserVo.java
│       │   │                   │       └── VisualizableTreeNode.java
│       │   │                   ├── message/
│       │   │                   │   ├── ThemeMessageResolutionUtils.java
│       │   │                   │   └── ThemeMessageResolver.java
│       │   │                   ├── router/
│       │   │                   │   ├── DefaultQueryPostPredicateResolver.java
│       │   │                   │   ├── ExtensionPermalinkPatternUpdater.java
│       │   │                   │   ├── ModelMapUtils.java
│       │   │                   │   ├── PermalinkRuleChangedEvent.java
│       │   │                   │   ├── PreviewRouterFunction.java
│       │   │                   │   ├── ReactiveQueryPostPredicateResolver.java
│       │   │                   │   ├── SinglePageRoute.java
│       │   │                   │   ├── ThemeCompositeRouterFunction.java
│       │   │                   │   ├── TitleVisibilityIdentifyCalculator.java
│       │   │                   │   └── factories/
│       │   │                   │       ├── ArchiveRouteFactory.java
│       │   │                   │       ├── AuthorPostsRouteFactory.java
│       │   │                   │       ├── CategoriesRouteFactory.java
│       │   │                   │       ├── CategoryPostRouteFactory.java
│       │   │                   │       ├── IndexRouteFactory.java
│       │   │                   │       ├── PostRouteFactory.java
│       │   │                   │       ├── RouteFactory.java
│       │   │                   │       ├── TagPostRouteFactory.java
│       │   │                   │       └── TagsRouteFactory.java
│       │   │                   ├── service/
│       │   │                   │   ├── ThemeService.java
│       │   │                   │   ├── ThemeServiceImpl.java
│       │   │                   │   └── ThemeUtils.java
│       │   │                   └── utils/
│       │   │                       └── PatternUtils.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── spring-devtools.properties
│       │       ├── application-dev.yaml
│       │       ├── application-doc.yaml
│       │       ├── application-mariadb.yaml
│       │       ├── application-mysql.yaml
│       │       ├── application-postgresql.yaml
│       │       ├── application-win.yaml
│       │       ├── application.yaml
│       │       ├── banner.txt
│       │       ├── config/
│       │       │   └── i18n/
│       │       │       ├── messages.properties
│       │       │       ├── messages_es.properties
│       │       │       └── messages_zh.properties
│       │       ├── db/
│       │       │   └── migration/
│       │       │       ├── h2/
│       │       │       │   └── .gitkeep
│       │       │       ├── mariadb/
│       │       │       │   └── .gitkeep
│       │       │       ├── mysql/
│       │       │       │   └── .gitkeep
│       │       │       └── postgresql/
│       │       │           └── .gitkeep
│       │       ├── extensions/
│       │       │   ├── attachment-local-policy.yaml
│       │       │   ├── authproviders.yaml
│       │       │   ├── extension-definitions.yaml
│       │       │   ├── extensionpoint-definitions.yaml
│       │       │   ├── notification-templates.yaml
│       │       │   ├── notification.yaml
│       │       │   ├── role-template-actuator.yaml
│       │       │   ├── role-template-anonymous.yaml
│       │       │   ├── role-template-attachment.yaml
│       │       │   ├── role-template-authenticated.yaml
│       │       │   ├── role-template-cache.yaml
│       │       │   ├── role-template-category.yaml
│       │       │   ├── role-template-comment.yaml
│       │       │   ├── role-template-configmap.yaml
│       │       │   ├── role-template-menu.yaml
│       │       │   ├── role-template-migration.yaml
│       │       │   ├── role-template-notification.yaml
│       │       │   ├── role-template-permissions.yaml
│       │       │   ├── role-template-plugin.yaml
│       │       │   ├── role-template-post.yaml
│       │       │   ├── role-template-role.yaml
│       │       │   ├── role-template-setting.yaml
│       │       │   ├── role-template-singlepage.yaml
│       │       │   ├── role-template-snapshot.yaml
│       │       │   ├── role-template-tag.yaml
│       │       │   ├── role-template-theme.yaml
│       │       │   ├── role-template-uc-attachment.yaml
│       │       │   ├── role-template-uc-content.yaml
│       │       │   ├── role-template-user.yaml
│       │       │   ├── system-configurable-configmap.yaml
│       │       │   ├── system-default-role.yaml
│       │       │   ├── system-setting.yaml
│       │       │   └── user.yaml
│       │       ├── initial-data.yaml
│       │       ├── schema-h2.sql
│       │       ├── schema-mariadb.sql
│       │       ├── schema-mysql.sql
│       │       ├── schema-postgresql.sql
│       │       ├── static/
│       │       │   ├── halo-tracker.js
│       │       │   ├── js/
│       │       │   │   └── main.js
│       │       │   └── styles/
│       │       │       └── main.css
│       │       ├── templates/
│       │       │   ├── challenges/
│       │       │   │   └── two-factor/
│       │       │   │       ├── totp.html
│       │       │   │       ├── totp.properties
│       │       │   │       ├── totp_en.properties
│       │       │   │       ├── totp_es.properties
│       │       │   │       └── totp_zh_TW.properties
│       │       │   ├── error/
│       │       │   │   └── error.html
│       │       │   ├── gateway_fragments/
│       │       │   │   ├── common.html
│       │       │   │   ├── common.properties
│       │       │   │   ├── common_en.properties
│       │       │   │   ├── common_es.properties
│       │       │   │   ├── common_zh_TW.properties
│       │       │   │   ├── input.html
│       │       │   │   ├── layout.html
│       │       │   │   ├── login.html
│       │       │   │   ├── login.properties
│       │       │   │   ├── login_en.properties
│       │       │   │   ├── login_es.properties
│       │       │   │   ├── login_zh_TW.properties
│       │       │   │   ├── logout.html
│       │       │   │   ├── logout.properties
│       │       │   │   ├── logout_en.properties
│       │       │   │   ├── logout_es.properties
│       │       │   │   ├── logout_zh_TW.properties
│       │       │   │   ├── password_reset_email_reset.html
│       │       │   │   ├── password_reset_email_reset.properties
│       │       │   │   ├── password_reset_email_reset_en.properties
│       │       │   │   ├── password_reset_email_reset_es.properties
│       │       │   │   ├── password_reset_email_reset_zh_TW.properties
│       │       │   │   ├── password_reset_email_send.html
│       │       │   │   ├── password_reset_email_send.properties
│       │       │   │   ├── password_reset_email_send_en.properties
│       │       │   │   ├── password_reset_email_send_es.properties
│       │       │   │   ├── password_reset_email_send_zh_TW.properties
│       │       │   │   ├── signup.html
│       │       │   │   ├── signup.properties
│       │       │   │   ├── signup_en.properties
│       │       │   │   ├── signup_es.properties
│       │       │   │   ├── signup_zh_TW.properties
│       │       │   │   ├── totp.html
│       │       │   │   ├── totp.properties
│       │       │   │   ├── totp_en.properties
│       │       │   │   ├── totp_es.properties
│       │       │   │   └── totp_zh_TW.properties
│       │       │   ├── login.html
│       │       │   ├── login.properties
│       │       │   ├── login_en.properties
│       │       │   ├── login_es.properties
│       │       │   ├── login_local.html
│       │       │   ├── login_local.properties
│       │       │   ├── login_local_en.properties
│       │       │   ├── login_local_es.properties
│       │       │   ├── login_local_zh_TW.properties
│       │       │   ├── login_zh_TW.properties
│       │       │   ├── logout.html
│       │       │   ├── logout.properties
│       │       │   ├── logout_en.properties
│       │       │   ├── logout_es.properties
│       │       │   ├── logout_zh_TW.properties
│       │       │   ├── password-reset/
│       │       │   │   └── email/
│       │       │   │       ├── reset.html
│       │       │   │       ├── reset.properties
│       │       │   │       ├── reset_en.properties
│       │       │   │       ├── reset_es.properties
│       │       │   │       ├── reset_zh_TW.properties
│       │       │   │       ├── send.html
│       │       │   │       ├── send.properties
│       │       │   │       ├── send_en.properties
│       │       │   │       ├── send_es.properties
│       │       │   │       └── send_zh_TW.properties
│       │       │   ├── setup.html
│       │       │   ├── setup.properties
│       │       │   ├── setup_en.properties
│       │       │   ├── setup_es.properties
│       │       │   ├── setup_zh_TW.properties
│       │       │   ├── signup.html
│       │       │   ├── signup.properties
│       │       │   ├── signup_en.properties
│       │       │   ├── signup_es.properties
│       │       │   └── signup_zh_TW.properties
│       │       └── thumbnailator.properties
│       └── test/
│           ├── java/
│           │   └── run/
│           │       └── halo/
│           │           └── app/
│           │               ├── ApplicationTests.java
│           │               ├── PathPrefixPredicateTest.java
│           │               ├── XForwardHeaderTest.java
│           │               ├── config/
│           │               │   ├── CorsTest.java
│           │               │   ├── ExtensionConfigurationTest.java
│           │               │   ├── HaloConfigurationTest.java
│           │               │   ├── SecurityConfigTest.java
│           │               │   ├── ServerCodecTest.java
│           │               │   └── WebFluxConfigTest.java
│           │               ├── content/
│           │               │   ├── CategoryPostCountUpdaterTest.java
│           │               │   ├── ContentRequestTest.java
│           │               │   ├── PostIntegrationTests.java
│           │               │   ├── TestPost.java
│           │               │   ├── comment/
│           │               │   │   ├── CommentEmailOwnerTest.java
│           │               │   │   ├── CommentNotificationReasonPublisherTest.java
│           │               │   │   ├── CommentRequestTest.java
│           │               │   │   ├── CommentServiceImplIntegrationTest.java
│           │               │   │   ├── CommentServiceImplTest.java
│           │               │   │   ├── PostCommentSubjectTest.java
│           │               │   │   ├── ReplyNotificationSubscriptionHelperTest.java
│           │               │   │   ├── ReplyServiceImplIntegrationTest.java
│           │               │   │   └── SinglePageCommentSubjectTest.java
│           │               │   └── permalinks/
│           │               │       ├── CategoryPermalinkPolicyTest.java
│           │               │       ├── PostPermalinkPolicyTest.java
│           │               │       └── TagPermalinkPolicyTest.java
│           │               ├── core/
│           │               │   ├── attachment/
│           │               │   │   ├── PolicyConfigChangeDetectorTest.java
│           │               │   │   ├── endpoint/
│           │               │   │   │   ├── LocalAttachmentUploadHandlerTest.java
│           │               │   │   │   └── PolicyEndpointTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   └── AttachmentRootGetterImplTest.java
│           │               │   │   └── thumbnail/
│           │               │   │       ├── DefaultLocalThumbnailServiceTest.java
│           │               │   │       ├── DefaultThumbnailServiceTest.java
│           │               │   │       ├── ThumbnailImgTagPostProcessorTest.java
│           │               │   │       ├── ThumbnailResourceTransformerTest.java
│           │               │   │       └── ThumbnailUtilsTest.java
│           │               │   ├── counter/
│           │               │   │   └── MeterUtilsTest.java
│           │               │   ├── endpoint/
│           │               │   │   ├── WebSocketHandlerMappingTest.java
│           │               │   │   ├── console/
│           │               │   │   │   ├── EmailVerificationCodeTest.java
│           │               │   │   │   ├── PluginEndpointTest.java
│           │               │   │   │   ├── PostEndpointTest.java
│           │               │   │   │   ├── SinglePageEndpointTest.java
│           │               │   │   │   ├── TagEndpointTest.java
│           │               │   │   │   ├── UserEndpointIntegrationTest.java
│           │               │   │   │   └── UserEndpointTest.java
│           │               │   │   ├── theme/
│           │               │   │   │   ├── CategoryQueryEndpointTest.java
│           │               │   │   │   ├── CommentFinderEndpointTest.java
│           │               │   │   │   ├── MenuQueryEndpointTest.java
│           │               │   │   │   ├── PluginQueryEndpointTest.java
│           │               │   │   │   ├── PostQueryEndpointTest.java
│           │               │   │   │   ├── PublicApiUtilsTest.java
│           │               │   │   │   ├── SinglePageQueryEndpointTest.java
│           │               │   │   │   └── ThumbnailEndpointTest.java
│           │               │   │   └── uc/
│           │               │   │       ├── AnnotationSettingEndpointTest.java
│           │               │   │       └── UcUserPreferenceEndpointTest.java
│           │               │   ├── extension/
│           │               │   │   ├── PostTest.java
│           │               │   │   ├── RoleBindingTest.java
│           │               │   │   ├── SettingTest.java
│           │               │   │   ├── TestRole.java
│           │               │   │   ├── ThemeTest.java
│           │               │   │   └── attachment/
│           │               │   │       └── endpoint/
│           │               │   │           └── AttachmentEndpointTest.java
│           │               │   ├── reconciler/
│           │               │   │   ├── CommentReconcilerTest.java
│           │               │   │   ├── MenuItemReconcilerTest.java
│           │               │   │   ├── PluginReconcilerTest.java
│           │               │   │   ├── PostReconcilerTest.java
│           │               │   │   ├── ReverseProxyReconcilerTest.java
│           │               │   │   ├── SinglePageReconcilerTest.java
│           │               │   │   ├── SystemConfigReconcilerTest.java
│           │               │   │   ├── TagReconcilerTest.java
│           │               │   │   ├── ThemeReconcilerTest.java
│           │               │   │   └── UserReconcilerTest.java
│           │               │   └── user/
│           │               │       └── service/
│           │               │           ├── DefaultRoleServiceTest.java
│           │               │           └── impl/
│           │               │               ├── EmailPasswordRecoveryServiceImplTest.java
│           │               │               ├── EmailVerificationServiceImplTest.java
│           │               │               └── UserServiceImplTest.java
│           │               ├── extension/
│           │               │   ├── AbstractExtensionTest.java
│           │               │   ├── ComparatorsTest.java
│           │               │   ├── ConfigMapTest.java
│           │               │   ├── DefaultSchemeManagerTest.java
│           │               │   ├── ExtensionOperatorTest.java
│           │               │   ├── ExtensionStoreUtilTest.java
│           │               │   ├── FakeExtension.java
│           │               │   ├── GroupVersionKindTest.java
│           │               │   ├── GroupVersionTest.java
│           │               │   ├── JsonExtensionConverterTest.java
│           │               │   ├── JsonExtensionTest.java
│           │               │   ├── ListResultTest.java
│           │               │   ├── MetadataOperatorTest.java
│           │               │   ├── ReactiveExtensionClientTest.java
│           │               │   ├── RefTest.java
│           │               │   ├── SchemeTest.java
│           │               │   ├── UnstructuredTest.java
│           │               │   ├── gc/
│           │               │   │   ├── GcReconcilerTest.java
│           │               │   │   ├── GcSynchronizerTest.java
│           │               │   │   └── GcWatcherTest.java
│           │               │   ├── index/
│           │               │   │   ├── DefaultIndexEngineTest.java
│           │               │   │   ├── DefaultIndicesManagerTest.java
│           │               │   │   ├── DefaultIndicesTest.java
│           │               │   │   ├── Fake.java
│           │               │   │   ├── LabelIndexTest.java
│           │               │   │   ├── MultiValueIndexTest.java
│           │               │   │   ├── SingleValueIndexTest.java
│           │               │   │   └── query/
│           │               │   │       └── QueryVisitorTest.java
│           │               │   ├── router/
│           │               │   │   ├── ExtensionCompositeRouterFunctionTest.java
│           │               │   │   ├── ExtensionCreateHandlerTest.java
│           │               │   │   ├── ExtensionDeleteHandlerTest.java
│           │               │   │   ├── ExtensionGetHandlerTest.java
│           │               │   │   ├── ExtensionListHandlerTest.java
│           │               │   │   ├── ExtensionRouterFunctionFactoryTest.java
│           │               │   │   ├── ExtensionUpdateHandlerTest.java
│           │               │   │   └── PathPatternGeneratorTest.java
│           │               │   └── store/
│           │               │       └── ReactiveExtensionStoreClientImplTest.java
│           │               ├── infra/
│           │               │   ├── ConditionListTest.java
│           │               │   ├── DefaultBackupRootGetterTest.java
│           │               │   ├── DefaultExternalLinkProcessorTest.java
│           │               │   ├── DefaultSystemConfigFetcherTest.java
│           │               │   ├── DefaultSystemVersionSupplierTest.java
│           │               │   ├── ExtensionResourceInitializerTest.java
│           │               │   ├── InitializationStateGetterTest.java
│           │               │   ├── ReactiveExtensionPaginatedOperatorImplTest.java
│           │               │   ├── SystemConfigFirstExternalUrlSupplierTest.java
│           │               │   ├── SystemSettingTest.java
│           │               │   ├── SystemStateTest.java
│           │               │   ├── ValidationUtilsTest.java
│           │               │   ├── config/
│           │               │   │   └── SessionConfigurationTest.java
│           │               │   ├── exception/
│           │               │   │   └── handlers/
│           │               │   │       └── I18nExceptionTest.java
│           │               │   ├── properties/
│           │               │   │   └── HaloPropertiesTest.java
│           │               │   └── utils/
│           │               │       ├── Base62UtilsTest.java
│           │               │       ├── FileNameUtilsTest.java
│           │               │       ├── FileTypeDetectUtilsTest.java
│           │               │       ├── FileUtilsTest.java
│           │               │       ├── HaloUtilsTest.java
│           │               │       ├── IpAddressUtilsTest.java
│           │               │       ├── SettingUtilsTest.java
│           │               │       ├── SortUtilsTest.java
│           │               │       ├── SystemConfigUtilsTest.java
│           │               │       ├── VersionUtilsTest.java
│           │               │       └── YamlUnstructuredLoaderTest.java
│           │               ├── migration/
│           │               │   ├── BackupReconcilerTest.java
│           │               │   └── impl/
│           │               │       └── MigrationServiceImplTest.java
│           │               ├── notification/
│           │               │   ├── DefaultNotificationCenterTest.java
│           │               │   ├── DefaultNotificationReasonEmitterTest.java
│           │               │   ├── DefaultNotificationSenderTest.java
│           │               │   ├── DefaultNotificationTemplateRenderTest.java
│           │               │   ├── DefaultNotifierConfigStoreTest.java
│           │               │   ├── DefaultSubscriberEmailResolverTest.java
│           │               │   ├── LanguageUtilsTest.java
│           │               │   ├── NotificationContextTest.java
│           │               │   ├── NotificationTriggerTest.java
│           │               │   ├── ReasonNotificationTemplateSelectorImplTest.java
│           │               │   ├── ReasonPayloadTest.java
│           │               │   ├── RecipientResolverImplTest.java
│           │               │   ├── SubscriptionServiceImplTest.java
│           │               │   ├── UserIdentityTest.java
│           │               │   ├── UserNotificationPreferenceServiceImplTest.java
│           │               │   ├── UserNotificationPreferenceTest.java
│           │               │   └── endpoint/
│           │               │       ├── SubscriptionRouterTest.java
│           │               │       └── UserNotificationPreferencesEndpointTest.java
│           │               ├── plugin/
│           │               │   ├── BuiltInPluginsInitializerTest.java
│           │               │   ├── DefaultDevelopmentPluginRepositoryTest.java
│           │               │   ├── DefaultPluginApplicationContextFactoryTest.java
│           │               │   ├── DefaultPluginRouterFunctionRegistryTest.java
│           │               │   ├── DefaultSettingFetcherTest.java
│           │               │   ├── HaloPluginManagerTest.java
│           │               │   ├── OptionalDependentResolverTest.java
│           │               │   ├── PluginExtensionLoaderUtilsTest.java
│           │               │   ├── PluginRequestMappingHandlerMappingTest.java
│           │               │   ├── PluginServiceImplTest.java
│           │               │   ├── PluginsRootGetterImplTest.java
│           │               │   ├── SharedApplicationContextFactoryTest.java
│           │               │   ├── SharedEventDispatcherTest.java
│           │               │   ├── SpringComponentsFinderTest.java
│           │               │   ├── YamlPluginDescriptorFinderTest.java
│           │               │   ├── YamlPluginFinderTest.java
│           │               │   ├── extensionpoint/
│           │               │   │   └── DefaultExtensionGetterTest.java
│           │               │   └── resources/
│           │               │       ├── BundleResourceUtilsTest.java
│           │               │       ├── ReverseProxyRouterFunctionFactoryTest.java
│           │               │       └── ReverseProxyRouterFunctionRegistryTest.java
│           │               ├── search/
│           │               │   ├── HaloDocumentEventsListenerTest.java
│           │               │   ├── IndexEndpointTest.java
│           │               │   ├── IndicesEndpointTest.java
│           │               │   ├── SearchServiceImplTest.java
│           │               │   ├── lucene/
│           │               │   │   ├── LuceneSearchEngineIntegrationTest.java
│           │               │   │   └── LuceneSearchEngineTest.java
│           │               │   └── post/
│           │               │       ├── PostEventsListenerTest.java
│           │               │       └── PostHaloDocumentsProviderTest.java
│           │               ├── security/
│           │               │   ├── AuthProviderServiceImplTest.java
│           │               │   ├── CsrfSecurityTest.java
│           │               │   ├── DefaultServerAuthenticationEntryPointTest.java
│           │               │   ├── DefaultSuperAdminInitializerTest.java
│           │               │   ├── DefaultUserDetailServiceTest.java
│           │               │   ├── HaloServerRequestCacheTest.java
│           │               │   ├── InitializeRedirectionWebFilterTest.java
│           │               │   ├── ResponseMap.java
│           │               │   ├── authentication/
│           │               │   │   ├── WebExchangeMatchersTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   └── RsaKeyServiceTest.java
│           │               │   │   ├── login/
│           │               │   │   │   ├── LoginAuthenticationConverterTest.java
│           │               │   │   │   └── PublicKeyRouteBuilderTest.java
│           │               │   │   ├── pat/
│           │               │   │   │   └── PatTest.java
│           │               │   │   ├── rememberme/
│           │               │   │   │   ├── PersistentTokenBasedRememberMeServicesTest.java
│           │               │   │   │   ├── RememberTokenCleanerTest.java
│           │               │   │   │   └── TokenBasedRememberMeServicesTest.java
│           │               │   │   └── twofactor/
│           │               │   │       └── TwoFactorAuthSettingsTest.java
│           │               │   ├── authorization/
│           │               │   │   ├── AuthorityUtilsTest.java
│           │               │   │   ├── AuthorizationTest.java
│           │               │   │   ├── DefaultRuleResolverTest.java
│           │               │   │   ├── PolicyRuleTest.java
│           │               │   │   ├── RbacRequestEvaluationTest.java
│           │               │   │   └── RequestInfoResolverTest.java
│           │               │   ├── device/
│           │               │   │   └── DeviceServiceImplTest.java
│           │               │   ├── jackson2/
│           │               │   │   └── HaloSecurityJacksonModuleTest.java
│           │               │   ├── preauth/
│           │               │   │   └── SystemSetupEndpointTest.java
│           │               │   ├── session/
│           │               │   │   └── InMemoryReactiveIndexedSessionRepositoryTest.java
│           │               │   └── switchuser/
│           │               │       ├── SwitchUserConfigurerTest.java
│           │               │       ├── SwitchUserSecurityContextFactory.java
│           │               │       └── WithSwitchUser.java
│           │               ├── theme/
│           │               │   ├── CompositeTemplateResolverTest.java
│           │               │   ├── ReactiveFinderExpressionParserTests.java
│           │               │   ├── SiteSettingVariablesAcquirerTest.java
│           │               │   ├── ThemeContextTest.java
│           │               │   ├── ThemeIntegrationTest.java
│           │               │   ├── ThemeLinkBuilderTest.java
│           │               │   ├── ThemeLocaleContextResolverTest.java
│           │               │   ├── ViewNameResolverTest.java
│           │               │   ├── dialect/
│           │               │   │   ├── CommentElementTagProcessorTest.java
│           │               │   │   ├── CommentEnabledVariableProcessorTest.java
│           │               │   │   ├── ContentTemplateHeadProcessorIntegrationTest.java
│           │               │   │   ├── ContentTemplateHeadProcessorTest.java
│           │               │   │   ├── DuplicateMetaTagProcessorTest.java
│           │               │   │   ├── GeneratorMetaProcessorTest.java
│           │               │   │   ├── HaloPostTemplateHandlerTest.java
│           │               │   │   ├── HaloProcessorDialectTest.java
│           │               │   │   ├── HaloSpringSecurityDialectTest.java
│           │               │   │   ├── InjectionExcluderProcessorTest.java
│           │               │   │   ├── LinkExpressionObjectDialectTest.java
│           │               │   │   └── TemplateFooterElementTagProcessorTest.java
│           │               │   ├── endpoint/
│           │               │   │   └── ThemeEndpointTest.java
│           │               │   ├── engine/
│           │               │   │   ├── DefaultThemeTemplateAvailabilityProviderTest.java
│           │               │   │   └── PluginClassloaderTemplateResolverTest.java
│           │               │   ├── finders/
│           │               │   │   ├── FinderRegistryTest.java
│           │               │   │   ├── impl/
│           │               │   │   │   ├── CategoryFinderImplTest.java
│           │               │   │   │   ├── CommentPublicQueryServiceImplTest.java
│           │               │   │   │   ├── CommentPublicQueryServiceIntegrationTest.java
│           │               │   │   │   ├── MenuFinderImplTest.java
│           │               │   │   │   ├── PluginFinderImplTest.java
│           │               │   │   │   ├── PostFinderImplIntegrationTest.java
│           │               │   │   │   ├── PostFinderImplTest.java
│           │               │   │   │   ├── PostPublicQueryServiceImplTest.java
│           │               │   │   │   ├── SinglePageConversionServiceImplTest.java
│           │               │   │   │   ├── SinglePageFinderImplTest.java
│           │               │   │   │   ├── TagFinderImplTest.java
│           │               │   │   │   └── ThumbnailFinderImplTest.java
│           │               │   │   └── vo/
│           │               │   │       └── UserVoTest.java
│           │               │   ├── message/
│           │               │   │   ├── ThemeMessageResolutionUtilsTest.java
│           │               │   │   └── ThemeMessageResolverIntegrationTest.java
│           │               │   ├── router/
│           │               │   │   ├── EmptyView.java
│           │               │   │   ├── PageUrlUtilsTest.java
│           │               │   │   ├── PreviewRouterFunctionTest.java
│           │               │   │   ├── ReactiveQueryPostPredicateResolverTest.java
│           │               │   │   ├── SinglePageRouteTest.java
│           │               │   │   └── factories/
│           │               │   │       ├── ArchiveRouteFactoryTest.java
│           │               │   │       ├── AuthorPostsRouteFactoryTest.java
│           │               │   │       ├── CategoriesRouteFactoryTest.java
│           │               │   │       ├── IndexRouteFactoryTest.java
│           │               │   │       ├── PostRouteFactoryTest.java
│           │               │   │       ├── RouteFactoryTest.java
│           │               │   │       ├── RouteFactoryTestSuite.java
│           │               │   │       └── TagPostRouteFactoryTest.java
│           │               │   ├── service/
│           │               │   │   └── ThemeServiceImplTest.java
│           │               │   └── utils/
│           │               │       └── PatternUtilsTest.java
│           │               ├── ui/
│           │               │   ├── WebSocketServerWebExchangeMatcherTest.java
│           │               │   └── WebSocketUtilsTest.java
│           │               └── webfilter/
│           │                   └── LocaleChangeWebFilterTest.java
│           └── resources/
│               ├── apiToken.salt
│               ├── app.key
│               ├── app.pub
│               ├── application.yaml
│               ├── backups/
│               │   └── backup-for-restoration/
│               │       ├── extensions.data
│               │       └── workdir/
│               │           └── fake-file
│               ├── categories/
│               │   └── independent-post-count.json
│               ├── config/
│               │   └── i18n/
│               │       ├── messages.properties
│               │       └── messages_zh.properties
│               ├── console/
│               │   ├── assets/
│               │   │   └── fake.txt
│               │   └── index.html
│               ├── file-type-detect/
│               │   ├── index.html
│               │   ├── index.js
│               │   ├── other.xlsx
│               │   ├── test.docx
│               │   └── test.json
│               ├── folder-to-zip/
│               │   └── examplefile
│               ├── plugin/
│               │   ├── plugin-0.0.1/
│               │   │   ├── extensions/
│               │   │   │   ├── reverseProxy.yaml
│               │   │   │   ├── roles.yaml
│               │   │   │   ├── setting.yaml
│               │   │   │   └── test.yml
│               │   │   └── plugin.yaml
│               │   ├── plugin-0.0.2/
│               │   │   └── plugin.yaml
│               │   ├── plugin-for-finder/
│               │   │   └── META-INF/
│               │   │       └── plugin-components.idx
│               │   ├── plugin-for-reverseproxy/
│               │   │   └── static/
│               │   │       └── test.txt
│               │   └── plugin.yaml
│               ├── presets/
│               │   └── plugins/
│               │       └── fake-plugin.jar
│               ├── themes/
│               │   ├── default/
│               │   │   ├── i18n/
│               │   │   │   ├── default.properties
│               │   │   │   ├── en.properties
│               │   │   │   └── zh.properties
│               │   │   ├── templates/
│               │   │   │   ├── index.html
│               │   │   │   ├── index.properties
│               │   │   │   ├── index_zh.properties
│               │   │   │   └── timezone.html
│               │   │   └── theme.yaml
│               │   ├── invalid-missing-manifest/
│               │   │   ├── i18n/
│               │   │   │   ├── default.properties
│               │   │   │   └── en.properties
│               │   │   └── templates/
│               │   │       ├── index.html
│               │   │       └── timezone.html
│               │   └── other/
│               │       ├── i18n/
│               │       │   ├── default.properties
│               │       │   └── en.properties
│               │       ├── templates/
│               │       │   └── index.html
│               │       └── theme.yaml
│               └── ui/
│                   ├── console.html
│                   ├── uc.html
│                   └── ui-assets/
│                       └── fake.txt
├── buildSrc/
│   ├── build.gradle
│   └── src/
│       └── main/
│           └── groovy/
│               ├── UploadBundleTask.groovy
│               └── halo.publish.gradle
├── config/
│   └── checkstyle/
│       └── checkstyle.xml
├── docs/
│   ├── authentication/
│   │   └── README.md
│   ├── backup-and-restore.md
│   ├── cache/
│   │   └── page.md
│   ├── developer-guide/
│   │   ├── custom-endpoint.md
│   │   └── plugin-configuration-properties.md
│   ├── email-verification/
│   │   └── README.md
│   ├── extension-points/
│   │   ├── authentication.md
│   │   ├── content.md
│   │   └── search-engine.md
│   ├── full-text-search/
│   │   └── README.md
│   ├── index/
│   │   └── README.md
│   ├── notification/
│   │   └── README.md
│   └── plugin/
│       ├── shared-event.md
│       └── websocket.md
├── e2e/
│   ├── Dockerfile
│   ├── Makefile
│   ├── README.md
│   ├── compose-mysql.yaml
│   ├── compose-postgres.yaml
│   ├── compose.yaml
│   ├── start.sh
│   └── testsuite.yaml
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── hack/
│   └── cherry_pick_pull.sh
├── platform/
│   ├── application/
│   │   └── build.gradle
│   └── plugin/
│       └── build.gradle
├── settings.gradle
└── ui/
    ├── .editorconfig
    ├── .husky/
    │   └── pre-commit
    ├── .npmrc
    ├── .oxfmtrc.json
    ├── Makefile
    ├── build.gradle
    ├── console-src/
    │   ├── App.vue
    │   ├── components/
    │   │   └── snapshots/
    │   │       ├── BaseSnapshots.vue
    │   │       ├── SnapshotContent.vue
    │   │       ├── SnapshotDiffContent.vue
    │   │       ├── SnapshotListItem.vue
    │   │       └── query-keys.ts
    │   ├── composables/
    │   │   ├── use-content-snapshot.ts
    │   │   ├── use-dashboard-stats.ts
    │   │   ├── use-entity-extension-points.ts
    │   │   ├── use-operation-extension-points.ts
    │   │   ├── use-save-keybinding.ts
    │   │   └── use-slugify.ts
    │   ├── layouts/
    │   │   ├── BasicLayout.vue
    │   │   └── BlankLayout.vue
    │   ├── main.ts
    │   ├── modules/
    │   │   ├── contents/
    │   │   │   ├── attachments/
    │   │   │   │   ├── AttachmentList.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── AttachmentDetailModal.vue
    │   │   │   │   │   ├── AttachmentError.vue
    │   │   │   │   │   ├── AttachmentGroupBadge.vue
    │   │   │   │   │   ├── AttachmentGroupEditingModal.vue
    │   │   │   │   │   ├── AttachmentGroupList.vue
    │   │   │   │   │   ├── AttachmentListItem.vue
    │   │   │   │   │   ├── AttachmentLoading.vue
    │   │   │   │   │   ├── AttachmentPoliciesListItem.vue
    │   │   │   │   │   ├── AttachmentPoliciesModal.vue
    │   │   │   │   │   ├── AttachmentPolicyBadge.vue
    │   │   │   │   │   ├── AttachmentPolicyEditingModal.vue
    │   │   │   │   │   ├── AttachmentSelectorModal.vue
    │   │   │   │   │   ├── AttachmentUploadArea.vue
    │   │   │   │   │   ├── AttachmentUploadModal.vue
    │   │   │   │   │   ├── DisplayNameEditForm.vue
    │   │   │   │   │   ├── UploadFromUrl.vue
    │   │   │   │   │   └── selector-providers/
    │   │   │   │   │       ├── CoreSelectorProvider.vue
    │   │   │   │   │       └── components/
    │   │   │   │   │           ├── AttachmentSelectorListItem.vue
    │   │   │   │   │           ├── GroupFilter.vue
    │   │   │   │   │           └── PolicyFilter.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   ├── use-attachment-group.ts
    │   │   │   │   │   ├── use-attachment-policy.ts
    │   │   │   │   │   └── use-attachment.ts
    │   │   │   │   └── module.ts
    │   │   │   ├── comments/
    │   │   │   │   ├── CommentList.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── CommentDetailModal.vue
    │   │   │   │   │   ├── CommentEditor.vue
    │   │   │   │   │   ├── CommentListItem.vue
    │   │   │   │   │   ├── DefaultCommentContent.vue
    │   │   │   │   │   ├── DefaultCommentEditor.vue
    │   │   │   │   │   ├── OwnerButton.vue
    │   │   │   │   │   ├── ReplyCreationModal.vue
    │   │   │   │   │   ├── ReplyDetailModal.vue
    │   │   │   │   │   ├── ReplyListItem.vue
    │   │   │   │   │   ├── SubjectQueryCommentList.vue
    │   │   │   │   │   └── SubjectQueryCommentListModal.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   ├── use-comment-last-readtime-mutate.ts
    │   │   │   │   │   ├── use-comments-fetch.ts
    │   │   │   │   │   ├── use-content-provider-extension-point.ts
    │   │   │   │   │   └── use-subject-ref.ts
    │   │   │   │   └── module.ts
    │   │   │   ├── pages/
    │   │   │   │   ├── DeletedSinglePageList.vue
    │   │   │   │   ├── SinglePageEditor.vue
    │   │   │   │   ├── SinglePageList.vue
    │   │   │   │   ├── SinglePageSnapshots.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── SinglePageListItem.vue
    │   │   │   │   │   ├── SinglePageSettingModal.vue
    │   │   │   │   │   └── entity-fields/
    │   │   │   │   │       ├── ContributorsField.vue
    │   │   │   │   │       ├── CoverField.vue
    │   │   │   │   │       ├── PublishStatusField.vue
    │   │   │   │   │       ├── PublishTimeField.vue
    │   │   │   │   │       ├── TitleField.vue
    │   │   │   │   │       └── VisibleField.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   └── use-page-update-mutate.ts
    │   │   │   │   └── module.ts
    │   │   │   └── posts/
    │   │   │       ├── DeletedPostList.vue
    │   │   │       ├── PostEditor.vue
    │   │   │       ├── PostList.vue
    │   │   │       ├── PostSnapshots.vue
    │   │   │       ├── categories/
    │   │   │       │   ├── CategoryList.vue
    │   │   │       │   ├── components/
    │   │   │       │   │   ├── CategoryEditingModal.vue
    │   │   │       │   │   ├── CategoryListItem.vue
    │   │   │       │   │   └── __tests__/
    │   │   │       │   │       └── CategoryEditingModal.spec.ts
    │   │   │       │   ├── composables/
    │   │   │       │   │   └── use-post-category.ts
    │   │   │       │   └── utils/
    │   │   │       │       ├── __tests__/
    │   │   │       │       │   └── index.spec.ts
    │   │   │       │       └── index.ts
    │   │   │       ├── components/
    │   │   │       │   ├── PostBatchSettingModal.vue
    │   │   │       │   ├── PostListItem.vue
    │   │   │       │   ├── PostSettingModal.vue
    │   │   │       │   ├── __tests__/
    │   │   │       │   │   └── PostSettingModal.spec.ts
    │   │   │       │   └── entity-fields/
    │   │   │       │       ├── ContributorsField.vue
    │   │   │       │       ├── CoverField.vue
    │   │   │       │       ├── PublishStatusField.vue
    │   │   │       │       ├── PublishTimeField.vue
    │   │   │       │       ├── TitleField.vue
    │   │   │       │       └── VisibleField.vue
    │   │   │       ├── composables/
    │   │   │       │   └── use-post-update-mutate.ts
    │   │   │       ├── module.ts
    │   │   │       └── tags/
    │   │   │           ├── TagList.vue
    │   │   │           ├── components/
    │   │   │           │   ├── PostTag.vue
    │   │   │           │   ├── TagEditingModal.vue
    │   │   │           │   └── TagListItem.vue
    │   │   │           └── composables/
    │   │   │               └── use-post-tag.ts
    │   │   ├── dashboard/
    │   │   │   ├── Dashboard.vue
    │   │   │   ├── DashboardDesigner.vue
    │   │   │   ├── components/
    │   │   │   │   ├── ActionButton.vue
    │   │   │   │   ├── WidgetCard.vue
    │   │   │   │   ├── WidgetConfigFormModal.vue
    │   │   │   │   ├── WidgetEditableItem.vue
    │   │   │   │   ├── WidgetHubModal.vue
    │   │   │   │   └── WidgetViewItem.vue
    │   │   │   ├── composables/
    │   │   │   │   ├── use-dashboard-extension-point.ts
    │   │   │   │   └── use-dashboard-widgets-fetch.ts
    │   │   │   ├── module.ts
    │   │   │   ├── styles/
    │   │   │   │   └── dashboard.css
    │   │   │   └── widgets/
    │   │   │       ├── defaults.ts
    │   │   │       ├── index.ts
    │   │   │       └── presets/
    │   │   │           ├── comments/
    │   │   │           │   ├── CommentItem.vue
    │   │   │           │   ├── CommentStatsWidget.vue
    │   │   │           │   └── PendingCommentsWidget.vue
    │   │   │           ├── core/
    │   │   │           │   ├── iframe/
    │   │   │           │   │   └── IframeWidget.vue
    │   │   │           │   ├── quick-action/
    │   │   │           │   │   ├── QuickActionItem.vue
    │   │   │           │   │   ├── QuickActionWidget.vue
    │   │   │           │   │   ├── ThemePreviewItem.vue
    │   │   │           │   │   └── composables/
    │   │   │           │   │       └── use-dashboard-extension-point.ts
    │   │   │           │   ├── stack/
    │   │   │           │   │   ├── StackWidget.vue
    │   │   │           │   │   ├── StackWidgetConfigModal.vue
    │   │   │           │   │   ├── components/
    │   │   │           │   │   │   ├── IndexIndicator.vue
    │   │   │           │   │   │   ├── WidgetEditableItem.vue
    │   │   │           │   │   │   └── WidgetViewItem.vue
    │   │   │           │   │   └── types.ts
    │   │   │           │   ├── upvotes-stats/
    │   │   │           │   │   └── UpvotesStatsWidget.vue
    │   │   │           │   └── view-stats/
    │   │   │           │       └── ViewsStatsWidget.vue
    │   │   │           ├── posts/
    │   │   │           │   ├── PostStatsWidget.vue
    │   │   │           │   ├── RecentPublishedWidget.vue
    │   │   │           │   └── components/
    │   │   │           │       └── PostListItem.vue
    │   │   │           ├── single-pages/
    │   │   │           │   └── SinglePageStatsWidget.vue
    │   │   │           └── users/
    │   │   │               ├── NotificationWidget.vue
    │   │   │               └── UserStatsWidget.vue
    │   │   ├── index.ts
    │   │   ├── interface/
    │   │   │   ├── menus/
    │   │   │   │   ├── Menus.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── MenuEditingModal.vue
    │   │   │   │   │   ├── MenuItemEditingModal.vue
    │   │   │   │   │   └── MenuList.vue
    │   │   │   │   ├── module.ts
    │   │   │   │   └── utils/
    │   │   │   │       ├── __tests__/
    │   │   │   │       │   ├── __snapshots__/
    │   │   │   │       │   │   └── index.spec.ts.snap
    │   │   │   │       │   └── index.spec.ts
    │   │   │   │       └── index.ts
    │   │   │   └── themes/
    │   │   │       ├── ThemeDetail.vue
    │   │   │       ├── ThemeSetting.vue
    │   │   │       ├── components/
    │   │   │       │   ├── ThemeListItem.vue
    │   │   │       │   ├── ThemeListModal.vue
    │   │   │       │   ├── list-tabs/
    │   │   │       │   │   ├── InstalledThemes.vue
    │   │   │       │   │   ├── LocalUpload.vue
    │   │   │       │   │   ├── NotInstalledThemes.vue
    │   │   │       │   │   └── RemoteDownload.vue
    │   │   │       │   ├── operation/
    │   │   │       │   │   ├── MoreOperationItem.vue
    │   │   │       │   │   └── UninstallOperationItem.vue
    │   │   │       │   └── preview/
    │   │   │       │       ├── ThemePreviewListItem.vue
    │   │   │       │       └── ThemePreviewModal.vue
    │   │   │       ├── composables/
    │   │   │       │   └── use-theme.ts
    │   │   │       ├── constants/
    │   │   │       │   └── index.ts
    │   │   │       ├── layouts/
    │   │   │       │   └── ThemeLayout.vue
    │   │   │       ├── module.ts
    │   │   │       └── types/
    │   │   │           └── index.ts
    │   │   └── system/
    │   │       ├── auth-providers/
    │   │       │   ├── AuthProviderDetail.vue
    │   │       │   ├── AuthProviders.vue
    │   │       │   ├── components/
    │   │       │   │   ├── AuthProviderListItem.vue
    │   │       │   │   └── AuthProvidersSection.vue
    │   │       │   └── module.ts
    │   │       ├── backup/
    │   │       │   ├── Backups.vue
    │   │       │   ├── components/
    │   │       │   │   └── BackupListItem.vue
    │   │       │   ├── composables/
    │   │       │   │   └── use-backup.ts
    │   │       │   ├── module.ts
    │   │       │   └── tabs/
    │   │       │       ├── List.vue
    │   │       │       └── Restore.vue
    │   │       ├── overview/
    │   │       │   ├── Overview.vue
    │   │       │   ├── components/
    │   │       │   │   ├── ExternalUrlForm.vue
    │   │       │   │   └── ExternalUrlItem.vue
    │   │       │   └── module.ts
    │   │       ├── plugins/
    │   │       │   ├── PluginDetail.vue
    │   │       │   ├── PluginExtensionPointSettings.vue
    │   │       │   ├── PluginList.vue
    │   │       │   ├── components/
    │   │       │   │   ├── PluginConditionsModal.vue
    │   │       │   │   ├── PluginDetailModal.vue
    │   │       │   │   ├── PluginInstallationModal.vue
    │   │       │   │   ├── PluginListItem.vue
    │   │       │   │   ├── entity-fields/
    │   │       │   │   │   ├── AuthorField.vue
    │   │       │   │   │   ├── LogoField.vue
    │   │       │   │   │   ├── ReloadField.vue
    │   │       │   │   │   ├── SwitchField.vue
    │   │       │   │   │   └── TitleField.vue
    │   │       │   │   ├── extension-points/
    │   │       │   │   │   ├── ExtensionDefinitionListItem.vue
    │   │       │   │   │   ├── ExtensionDefinitionMultiInstanceView.vue
    │   │       │   │   │   └── ExtensionDefinitionSingletonView.vue
    │   │       │   │   ├── installation-tabs/
    │   │       │   │   │   ├── LocalUpload.vue
    │   │       │   │   │   └── RemoteDownload.vue
    │   │       │   │   └── tabs/
    │   │       │   │       ├── Detail.vue
    │   │       │   │       └── Setting.vue
    │   │       │   ├── composables/
    │   │       │   │   ├── use-extension-definition-fetch.ts
    │   │       │   │   └── use-plugin.ts
    │   │       │   ├── constants/
    │   │       │   │   └── index.ts
    │   │       │   ├── module.ts
    │   │       │   └── types/
    │   │       │       └── index.ts
    │   │       ├── roles/
    │   │       │   ├── RoleDetail.vue
    │   │       │   ├── RoleList.vue
    │   │       │   ├── components/
    │   │       │   │   └── RoleEditingModal.vue
    │   │       │   └── module.ts
    │   │       ├── settings/
    │   │       │   ├── SystemSettings.vue
    │   │       │   ├── module.ts
    │   │       │   └── tabs/
    │   │       │       ├── NotificationSetting.vue
    │   │       │       ├── Notifications.vue
    │   │       │       └── Setting.vue
    │   │       ├── tools/
    │   │       │   ├── Tools.vue
    │   │       │   └── module.ts
    │   │       └── users/
    │   │           ├── UserDetail.vue
    │   │           ├── UserList.vue
    │   │           ├── components/
    │   │           │   ├── GrantPermissionModal.vue
    │   │           │   ├── RolesView.vue
    │   │           │   ├── UserCreationModal.vue
    │   │           │   ├── UserEditingModal.vue
    │   │           │   ├── UserListItem.vue
    │   │           │   └── UserPasswordChangeModal.vue
    │   │           ├── composables/
    │   │           │   ├── use-role.ts
    │   │           │   └── use-user.ts
    │   │           ├── module.ts
    │   │           └── tabs/
    │   │               └── Detail.vue
    │   ├── router/
    │   │   ├── constant.ts
    │   │   ├── guards/
    │   │   │   ├── auth-check.ts
    │   │   │   └── permission.ts
    │   │   ├── index.ts
    │   │   └── routes.config.ts
    │   └── stores/
    │       └── theme.ts
    ├── console.html
    ├── docs/
    │   ├── components/
    │   │   └── README.md
    │   ├── custom-formkit-input/
    │   │   └── README.md
    │   ├── extension-points/
    │   │   ├── backup.md
    │   │   ├── comment-content.md
    │   │   ├── comment-editor.md
    │   │   ├── comment-subject-ref.md
    │   │   ├── dashboard.md
    │   │   ├── default-editor–extension.md
    │   │   ├── editor.md
    │   │   ├── entity-listitem-field.md
    │   │   ├── entity-listitem-operation.md
    │   │   ├── plugin-installation-tabs.md
    │   │   ├── plugin-self-tabs.md
    │   │   └── theme-list-tabs.md
    │   ├── project-structure/
    │   │   └── README.md
    │   └── routes-generation/
    │       └── README.md
    ├── env.d.ts
    ├── eslint.config.ts
    ├── package.json
    ├── packages/
    │   ├── api-client/
    │   │   ├── .openapi_config.yaml
    │   │   ├── README.md
    │   │   ├── entry/
    │   │   │   ├── api-client.ts
    │   │   │   ├── index.ts
    │   │   │   └── utils/
    │   │   │       ├── index.ts
    │   │   │       └── paginate.ts
    │   │   ├── openapitools.json
    │   │   ├── package.json
    │   │   ├── src/
    │   │   │   ├── .gitignore
    │   │   │   ├── .npmignore
    │   │   │   ├── .openapi-generator/
    │   │   │   │   ├── FILES
    │   │   │   │   └── VERSION
    │   │   │   ├── .openapi-generator-ignore
    │   │   │   ├── api/
    │   │   │   │   ├── annotation-setting-v1-alpha-uc-api.ts
    │   │   │   │   ├── annotation-setting-v1alpha1-api.ts
    │   │   │   │   ├── attachment-v1alpha1-api.ts
    │   │   │   │   ├── attachment-v1alpha1-console-api.ts
    │   │   │   │   ├── attachment-v1alpha1-uc-api.ts
    │   │   │   │   ├── auth-provider-v1alpha1-api.ts
    │   │   │   │   ├── auth-provider-v1alpha1-console-api.ts
    │   │   │   │   ├── backup-v1alpha1-api.ts
    │   │   │   │   ├── category-v1alpha1-api.ts
    │   │   │   │   ├── category-v1alpha1-public-api.ts
    │   │   │   │   ├── comment-v1alpha1-api.ts
    │   │   │   │   ├── comment-v1alpha1-console-api.ts
    │   │   │   │   ├── comment-v1alpha1-public-api.ts
    │   │   │   │   ├── config-map-v1alpha1-api.ts
    │   │   │   │   ├── counter-v1alpha1-api.ts
    │   │   │   │   ├── device-v1alpha1-api.ts
    │   │   │   │   ├── device-v1alpha1-uc-api.ts
    │   │   │   │   ├── extension-definition-v1alpha1-api.ts
    │   │   │   │   ├── extension-point-definition-v1alpha1-api.ts
    │   │   │   │   ├── group-v1alpha1-api.ts
    │   │   │   │   ├── index-v1alpha1-public-api.ts
    │   │   │   │   ├── indices-v1alpha1-console-api.ts
    │   │   │   │   ├── local-thumbnail-v1alpha1-api.ts
    │   │   │   │   ├── menu-item-v1alpha1-api.ts
    │   │   │   │   ├── menu-v1alpha1-api.ts
    │   │   │   │   ├── menu-v1alpha1-public-api.ts
    │   │   │   │   ├── metrics-v1alpha1-public-api.ts
    │   │   │   │   ├── migration-v1alpha1-console-api.ts
    │   │   │   │   ├── notification-template-v1alpha1-api.ts
    │   │   │   │   ├── notification-v1alpha1-api.ts
    │   │   │   │   ├── notification-v1alpha1-public-api.ts
    │   │   │   │   ├── notification-v1alpha1-uc-api.ts
    │   │   │   │   ├── notifier-descriptor-v1alpha1-api.ts
    │   │   │   │   ├── notifier-v1alpha1-console-api.ts
    │   │   │   │   ├── notifier-v1alpha1-uc-api.ts
    │   │   │   │   ├── personal-access-token-v1alpha1-api.ts
    │   │   │   │   ├── personal-access-token-v1alpha1-uc-api.ts
    │   │   │   │   ├── plugin-v1alpha1-api.ts
    │   │   │   │   ├── plugin-v1alpha1-console-api.ts
    │   │   │   │   ├── plugin-v1alpha1-public-api.ts
    │   │   │   │   ├── policy-alpha1-console-api.ts
    │   │   │   │   ├── policy-template-v1alpha1-api.ts
    │   │   │   │   ├── policy-v1alpha1-api.ts
    │   │   │   │   ├── post-v1alpha1-api.ts
    │   │   │   │   ├── post-v1alpha1-console-api.ts
    │   │   │   │   ├── post-v1alpha1-public-api.ts
    │   │   │   │   ├── post-v1alpha1-uc-api.ts
    │   │   │   │   ├── reason-type-v1alpha1-api.ts
    │   │   │   │   ├── reason-v1alpha1-api.ts
    │   │   │   │   ├── remember-me-token-v1alpha1-api.ts
    │   │   │   │   ├── reply-v1alpha1-api.ts
    │   │   │   │   ├── reply-v1alpha1-console-api.ts
    │   │   │   │   ├── reverse-proxy-v1alpha1-api.ts
    │   │   │   │   ├── role-binding-v1alpha1-api.ts
    │   │   │   │   ├── role-v1alpha1-api.ts
    │   │   │   │   ├── secret-v1alpha1-api.ts
    │   │   │   │   ├── setting-v1alpha1-api.ts
    │   │   │   │   ├── single-page-v1alpha1-api.ts
    │   │   │   │   ├── single-page-v1alpha1-console-api.ts
    │   │   │   │   ├── single-page-v1alpha1-public-api.ts
    │   │   │   │   ├── snapshot-v1alpha1-api.ts
    │   │   │   │   ├── snapshot-v1alpha1-uc-api.ts
    │   │   │   │   ├── subscription-v1alpha1-api.ts
    │   │   │   │   ├── system-config-v1alpha1-console-api.ts
    │   │   │   │   ├── system-v1alpha1-console-api.ts
    │   │   │   │   ├── system-v1alpha1-public-api.ts
    │   │   │   │   ├── tag-v1alpha1-api.ts
    │   │   │   │   ├── tag-v1alpha1-console-api.ts
    │   │   │   │   ├── tag-v1alpha1-public-api.ts
    │   │   │   │   ├── theme-v1alpha1-api.ts
    │   │   │   │   ├── theme-v1alpha1-console-api.ts
    │   │   │   │   ├── thumbnail-v1alpha1-api.ts
    │   │   │   │   ├── thumbnail-v1alpha1-public-api.ts
    │   │   │   │   ├── two-factor-auth-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-connection-v1alpha1-api.ts
    │   │   │   │   ├── user-connection-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-preference-v1alpha1-uc-api.ts
    │   │   │   │   ├── user-v1alpha1-api.ts
    │   │   │   │   └── user-v1alpha1-console-api.ts
    │   │   │   ├── api.ts
    │   │   │   ├── base.ts
    │   │   │   ├── common.ts
    │   │   │   ├── configuration.ts
    │   │   │   ├── git_push.sh
    │   │   │   ├── index.ts
    │   │   │   └── models/
    │   │   │       ├── add-operation.ts
    │   │   │       ├── annotation-setting-list.ts
    │   │   │       ├── annotation-setting-spec.ts
    │   │   │       ├── annotation-setting.ts
    │   │   │       ├── attachment-list.ts
    │   │   │       ├── attachment-spec.ts
    │   │   │       ├── attachment-status.ts
    │   │   │       ├── attachment.ts
    │   │   │       ├── auth-provider-list.ts
    │   │   │       ├── auth-provider-spec.ts
    │   │   │       ├── auth-provider.ts
    │   │   │       ├── author.ts
    │   │   │       ├── backup-file.ts
    │   │   │       ├── backup-list.ts
    │   │   │       ├── backup-spec.ts
    │   │   │       ├── backup-status.ts
    │   │   │       ├── backup.ts
    │   │   │       ├── category-list.ts
    │   │   │       ├── category-spec.ts
    │   │   │       ├── category-status.ts
    │   │   │       ├── category-vo-list.ts
    │   │   │       ├── category-vo.ts
    │   │   │       ├── category.ts
    │   │   │       ├── change-own-password-request.ts
    │   │   │       ├── change-password-request.ts
    │   │   │       ├── comment-email-owner.ts
    │   │   │       ├── comment-list.ts
    │   │   │       ├── comment-owner.ts
    │   │   │       ├── comment-request.ts
    │   │   │       ├── comment-spec.ts
    │   │   │       ├── comment-stats-vo.ts
    │   │   │       ├── comment-stats.ts
    │   │   │       ├── comment-status.ts
    │   │   │       ├── comment-vo-list.ts
    │   │   │       ├── comment-vo.ts
    │   │   │       ├── comment-with-reply-vo-list.ts
    │   │   │       ├── comment-with-reply-vo.ts
    │   │   │       ├── comment.ts
    │   │   │       ├── condition.ts
    │   │   │       ├── config-map-list.ts
    │   │   │       ├── config-map-ref.ts
    │   │   │       ├── config-map.ts
    │   │   │       ├── content-update-param.ts
    │   │   │       ├── content-vo.ts
    │   │   │       ├── content-wrapper.ts
    │   │   │       ├── content.ts
    │   │   │       ├── contributor-vo.ts
    │   │   │       ├── contributor.ts
    │   │   │       ├── copy-operation.ts
    │   │   │       ├── counter-list.ts
    │   │   │       ├── counter-request.ts
    │   │   │       ├── counter.ts
    │   │   │       ├── create-user-request.ts
    │   │   │       ├── custom-templates.ts
    │   │   │       ├── dashboard-stats.ts
    │   │   │       ├── detailed-user.ts
    │   │   │       ├── device-list.ts
    │   │   │       ├── device-spec.ts
    │   │   │       ├── device-status.ts
    │   │   │       ├── device.ts
    │   │   │       ├── email-config-validation-request.ts
    │   │   │       ├── email-verify-request.ts
    │   │   │       ├── excerpt.ts
    │   │   │       ├── extension-definition-list.ts
    │   │   │       ├── extension-definition.ts
    │   │   │       ├── extension-point-definition-list.ts
    │   │   │       ├── extension-point-definition.ts
    │   │   │       ├── extension-point-spec.ts
    │   │   │       ├── extension-spec.ts
    │   │   │       ├── extension.ts
    │   │   │       ├── file-reverse-proxy-provider.ts
    │   │   │       ├── grant-request.ts
    │   │   │       ├── group-kind.ts
    │   │   │       ├── group-list.ts
    │   │   │       ├── group-spec.ts
    │   │   │       ├── group-status.ts
    │   │   │       ├── group.ts
    │   │   │       ├── halo-document.ts
    │   │   │       ├── index.ts
    │   │   │       ├── install-from-uri-request.ts
    │   │   │       ├── interest-reason-subject.ts
    │   │   │       ├── interest-reason.ts
    │   │   │       ├── json-patch-inner.ts
    │   │   │       ├── license.ts
    │   │   │       ├── list-result-reply-vo.ts
    │   │   │       ├── listed-auth-provider.ts
    │   │   │       ├── listed-comment-list.ts
    │   │   │       ├── listed-comment.ts
    │   │   │       ├── listed-post-list.ts
    │   │   │       ├── listed-post-vo-list.ts
    │   │   │       ├── listed-post-vo.ts
    │   │   │       ├── listed-post.ts
    │   │   │       ├── listed-reply-list.ts
    │   │   │       ├── listed-reply.ts
    │   │   │       ├── listed-single-page-list.ts
    │   │   │       ├── listed-single-page-vo-list.ts
    │   │   │       ├── listed-single-page-vo.ts
    │   │   │       ├── listed-single-page.ts
    │   │   │       ├── listed-snapshot-dto.ts
    │   │   │       ├── listed-snapshot-spec.ts
    │   │   │       ├── listed-user.ts
    │   │   │       ├── local-thumbnail-list.ts
    │   │   │       ├── local-thumbnail-spec.ts
    │   │   │       ├── local-thumbnail-status.ts
    │   │   │       ├── local-thumbnail.ts
    │   │   │       ├── mark-specified-request.ts
    │   │   │       ├── menu-item-list.ts
    │   │   │       ├── menu-item-spec.ts
    │   │   │       ├── menu-item-status.ts
    │   │   │       ├── menu-item-vo.ts
    │   │   │       ├── menu-item.ts
    │   │   │       ├── menu-list.ts
    │   │   │       ├── menu-spec.ts
    │   │   │       ├── menu-vo.ts
    │   │   │       ├── menu.ts
    │   │   │       ├── metadata.ts
    │   │   │       ├── move-operation.ts
    │   │   │       ├── navigation-post-vo.ts
    │   │   │       ├── notification-list.ts
    │   │   │       ├── notification-spec.ts
    │   │   │       ├── notification-template-list.ts
    │   │   │       ├── notification-template-spec.ts
    │   │   │       ├── notification-template.ts
    │   │   │       ├── notification.ts
    │   │   │       ├── notifier-descriptor-list.ts
    │   │   │       ├── notifier-descriptor-spec.ts
    │   │   │       ├── notifier-descriptor.ts
    │   │   │       ├── notifier-info.ts
    │   │   │       ├── notifier-setting-ref.ts
    │   │   │       ├── owner-info.ts
    │   │   │       ├── password-request.ts
    │   │   │       ├── pat-spec.ts
    │   │   │       ├── personal-access-token-list.ts
    │   │   │       ├── personal-access-token.ts
    │   │   │       ├── plugin-author.ts
    │   │   │       ├── plugin-list.ts
    │   │   │       ├── plugin-running-state-request.ts
    │   │   │       ├── plugin-spec.ts
    │   │   │       ├── plugin-status.ts
    │   │   │       ├── plugin.ts
    │   │   │       ├── policy-list.ts
    │   │   │       ├── policy-rule.ts
    │   │   │       ├── policy-spec.ts
    │   │   │       ├── policy-template-list.ts
    │   │   │       ├── policy-template-spec.ts
    │   │   │       ├── policy-template.ts
    │   │   │       ├── policy.ts
    │   │   │       ├── post-list.ts
    │   │   │       ├── post-request.ts
    │   │   │       ├── post-spec.ts
    │   │   │       ├── post-status.ts
    │   │   │       ├── post-vo.ts
    │   │   │       ├── post.ts
    │   │   │       ├── reason-attributes.ts
    │   │   │       ├── reason-list.ts
    │   │   │       ├── reason-property.ts
    │   │   │       ├── reason-selector.ts
    │   │   │       ├── reason-spec.ts
    │   │   │       ├── reason-subject.ts
    │   │   │       ├── reason-type-info.ts
    │   │   │       ├── reason-type-list.ts
    │   │   │       ├── reason-type-notifier-collection-request.ts
    │   │   │       ├── reason-type-notifier-matrix.ts
    │   │   │       ├── reason-type-notifier-request.ts
    │   │   │       ├── reason-type-spec.ts
    │   │   │       ├── reason-type.ts
    │   │   │       ├── reason.ts
    │   │   │       ├── ref.ts
    │   │   │       ├── remember-me-token-list.ts
    │   │   │       ├── remember-me-token-spec.ts
    │   │   │       ├── remember-me-token.ts
    │   │   │       ├── remove-operation.ts
    │   │   │       ├── replace-operation.ts
    │   │   │       ├── reply-list.ts
    │   │   │       ├── reply-request.ts
    │   │   │       ├── reply-spec.ts
    │   │   │       ├── reply-status.ts
    │   │   │       ├── reply-vo-list.ts
    │   │   │       ├── reply-vo.ts
    │   │   │       ├── reply.ts
    │   │   │       ├── reverse-proxy-list.ts
    │   │   │       ├── reverse-proxy-rule.ts
    │   │   │       ├── reverse-proxy.ts
    │   │   │       ├── revert-snapshot-for-post-param.ts
    │   │   │       ├── revert-snapshot-for-single-param.ts
    │   │   │       ├── role-binding-list.ts
    │   │   │       ├── role-binding.ts
    │   │   │       ├── role-list.ts
    │   │   │       ├── role-ref.ts
    │   │   │       ├── role.ts
    │   │   │       ├── search-option.ts
    │   │   │       ├── search-result.ts
    │   │   │       ├── secret-list.ts
    │   │   │       ├── secret.ts
    │   │   │       ├── setting-form.ts
    │   │   │       ├── setting-list.ts
    │   │   │       ├── setting-ref.ts
    │   │   │       ├── setting-spec.ts
    │   │   │       ├── setting.ts
    │   │   │       ├── setup-request.ts
    │   │   │       ├── single-page-list.ts
    │   │   │       ├── single-page-request.ts
    │   │   │       ├── single-page-spec.ts
    │   │   │       ├── single-page-status.ts
    │   │   │       ├── single-page-vo.ts
    │   │   │       ├── single-page.ts
    │   │   │       ├── site-stats-vo.ts
    │   │   │       ├── snap-shot-spec.ts
    │   │   │       ├── snapshot-list.ts
    │   │   │       ├── snapshot.ts
    │   │   │       ├── stats-vo.ts
    │   │   │       ├── stats.ts
    │   │   │       ├── subject.ts
    │   │   │       ├── subscription-list.ts
    │   │   │       ├── subscription-spec.ts
    │   │   │       ├── subscription-subscriber.ts
    │   │   │       ├── subscription.ts
    │   │   │       ├── tag-list.ts
    │   │   │       ├── tag-spec.ts
    │   │   │       ├── tag-status.ts
    │   │   │       ├── tag-vo-list.ts
    │   │   │       ├── tag-vo.ts
    │   │   │       ├── tag.ts
    │   │   │       ├── template-content.ts
    │   │   │       ├── template-descriptor.ts
    │   │   │       ├── test-operation.ts
    │   │   │       ├── theme-list.ts
    │   │   │       ├── theme-spec.ts
    │   │   │       ├── theme-status.ts
    │   │   │       ├── theme.ts
    │   │   │       ├── thumbnail-list.ts
    │   │   │       ├── thumbnail-spec.ts
    │   │   │       ├── thumbnail.ts
    │   │   │       ├── totp-auth-link-response.ts
    │   │   │       ├── totp-request.ts
    │   │   │       ├── two-factor-auth-settings.ts
    │   │   │       ├── uc-upload-from-url-request.ts
    │   │   │       ├── upgrade-from-uri-request.ts
    │   │   │       ├── upload-from-url-request.ts
    │   │   │       ├── user-connection-list.ts
    │   │   │       ├── user-connection-spec.ts
    │   │   │       ├── user-connection.ts
    │   │   │       ├── user-device.ts
    │   │   │       ├── user-endpoint-listed-user-list.ts
    │   │   │       ├── user-list.ts
    │   │   │       ├── user-permission.ts
    │   │   │       ├── user-spec.ts
    │   │   │       ├── user-status.ts
    │   │   │       ├── user.ts
    │   │   │       ├── verify-code-request.ts
    │   │   │       └── vote-request.ts
    │   │   ├── tsconfig.json
    │   │   └── tsdown.config.ts
    │   ├── components/
    │   │   ├── .storybook/
    │   │   │   ├── main.ts
    │   │   │   └── preview.ts
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── postcss.config.cjs
    │   │   ├── src/
    │   │   │   ├── components/
    │   │   │   │   ├── alert/
    │   │   │   │   │   ├── Alert.stories.ts
    │   │   │   │   │   ├── Alert.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Alert.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── avatar/
    │   │   │   │   │   ├── Avatar.stories.ts
    │   │   │   │   │   ├── Avatar.vue
    │   │   │   │   │   ├── AvatarGroup.stories.ts
    │   │   │   │   │   ├── AvatarGroup.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── button/
    │   │   │   │   │   ├── Button.stories.ts
    │   │   │   │   │   ├── Button.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Button.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── Button.spec.ts.snap
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── card/
    │   │   │   │   │   ├── Card.stories.ts
    │   │   │   │   │   ├── Card.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Card.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── description/
    │   │   │   │   │   ├── Description.vue
    │   │   │   │   │   ├── DescriptionItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── dialog/
    │   │   │   │   │   ├── Dialog.stories.ts
    │   │   │   │   │   ├── Dialog.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Dialog.spec.ts
    │   │   │   │   │   ├── dialog-manager.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── dropdown/
    │   │   │   │   │   ├── Draopdown.stories.ts
    │   │   │   │   │   ├── DropdownDivider.vue
    │   │   │   │   │   ├── DropdownItem.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── style.scss
    │   │   │   │   ├── empty/
    │   │   │   │   │   ├── Empty.stories.ts
    │   │   │   │   │   ├── Empty.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Empty.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── Empty.spec.ts.snap
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── entity/
    │   │   │   │   │   ├── Entity.vue
    │   │   │   │   │   ├── EntityContainer.vue
    │   │   │   │   │   ├── EntityField.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Entity.spec.ts
    │   │   │   │   │   │   └── EntityField.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── header/
    │   │   │   │   │   ├── PageHeader.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── loading/
    │   │   │   │   │   ├── Loading.stories.ts
    │   │   │   │   │   ├── Loading.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── menu/
    │   │   │   │   │   ├── Menu.stories.ts
    │   │   │   │   │   ├── Menu.vue
    │   │   │   │   │   ├── MenuItem.vue
    │   │   │   │   │   ├── MenuLabel.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── Menu.spec.tsx
    │   │   │   │   │   │   ├── MenuLabel.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       ├── Menu.spec.tsx.snap
    │   │   │   │   │   │       └── MenuLabel.spec.ts.snap
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── modal/
    │   │   │   │   │   ├── Modal.stories.ts
    │   │   │   │   │   ├── Modal.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Modal.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── pagination/
    │   │   │   │   │   ├── Pagination.stories.ts
    │   │   │   │   │   ├── Pagination.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Pagination.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── space/
    │   │   │   │   │   ├── Space.stories.ts
    │   │   │   │   │   ├── Space.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Space.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── status/
    │   │   │   │   │   ├── StatusDot.stories.ts
    │   │   │   │   │   ├── StatusDot.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── StatusDot.spec.ts
    │   │   │   │   │   │   └── __snapshots__/
    │   │   │   │   │   │       └── StatusDot.spec.ts.snap
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── switch/
    │   │   │   │   │   ├── Switch.stories.ts
    │   │   │   │   │   ├── Switch.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Switch.spec.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── tabs/
    │   │   │   │   │   ├── TabItem.vue
    │   │   │   │   │   ├── Tabbar.stories.ts
    │   │   │   │   │   ├── Tabbar.vue
    │   │   │   │   │   ├── Tabs.stories.ts
    │   │   │   │   │   ├── Tabs.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   ├── TabItem.spec.ts
    │   │   │   │   │   │   ├── Tabbar.spec.ts
    │   │   │   │   │   │   └── Tabs.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── tag/
    │   │   │   │   │   ├── Tag.stories.ts
    │   │   │   │   │   ├── Tag.story.vue
    │   │   │   │   │   ├── Tag.vue
    │   │   │   │   │   ├── __tests__/
    │   │   │   │   │   │   └── Tag.spec.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   ├── toast/
    │   │   │   │   │   ├── Toast.story.vue
    │   │   │   │   │   ├── Toast.vue
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── toast-manager.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   └── tooltip/
    │   │   │   │       ├── index.ts
    │   │   │   │       └── style.css
    │   │   │   ├── components.ts
    │   │   │   ├── icons/
    │   │   │   │   └── icons.ts
    │   │   │   ├── index.ts
    │   │   │   ├── stories/
    │   │   │   │   └── Introduction.mdx
    │   │   │   └── styles/
    │   │   │       └── tailwind.css
    │   │   ├── tailwind.config.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   ├── tsconfig.vitest.json
    │   │   └── vite.config.ts
    │   ├── console-shared/
    │   │   ├── README.md
    │   │   ├── index.js
    │   │   └── package.json
    │   ├── editor/
    │   │   ├── README.md
    │   │   ├── docs/
    │   │   │   └── extension.md
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── postcss.config.cjs
    │   │   ├── src/
    │   │   │   ├── components/
    │   │   │   │   ├── Editor.vue
    │   │   │   │   ├── EditorHeader.vue
    │   │   │   │   ├── base/
    │   │   │   │   │   ├── DropdownItem.vue
    │   │   │   │   │   ├── Input.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── block/
    │   │   │   │   │   ├── BlockActionButton.vue
    │   │   │   │   │   ├── BlockActionHorizontalSeparator.vue
    │   │   │   │   │   ├── BlockActionSeparator.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bubble/
    │   │   │   │   │   ├── BubbleButton.vue
    │   │   │   │   │   ├── BubbleItem.vue
    │   │   │   │   │   ├── EditorBubbleMenu.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── common/
    │   │   │   │   │   └── ColorPickerDropdown.vue
    │   │   │   │   ├── drag/
    │   │   │   │   │   ├── EditorDragButtonItem.vue
    │   │   │   │   │   ├── EditorDragHandle.vue
    │   │   │   │   │   ├── EditorDragMenu.vue
    │   │   │   │   │   ├── default-drag.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── icon/
    │   │   │   │   │   └── MingcuteDelete2Line.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── toolbar/
    │   │   │   │   │   ├── ToolbarItem.vue
    │   │   │   │   │   ├── ToolbarSubItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── toolbox/
    │   │   │   │   │   ├── ToolboxItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── upload/
    │   │   │   │       ├── EditorLinkObtain.vue
    │   │   │   │       ├── ResourceReplaceButton.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── composables/
    │   │   │   │   └── use-attachment.ts
    │   │   │   ├── extensions/
    │   │   │   │   ├── align/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── audio/
    │   │   │   │   │   ├── AudioView.vue
    │   │   │   │   │   ├── BubbleItemAudioLink.vue
    │   │   │   │   │   ├── BubbleItemAudioPosition.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── block-position/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── blockquote/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bold/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── bullet-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── character-count/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── clear-format/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── code/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── code-block/
    │   │   │   │   │   ├── CodeBlockSelect.vue
    │   │   │   │   │   ├── CodeBlockViewRenderer.vue
    │   │   │   │   │   ├── code-block.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── color/
    │   │   │   │   │   ├── ColorBubbleItem.vue
    │   │   │   │   │   ├── ColorToolbarItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── columns/
    │   │   │   │   │   ├── column.ts
    │   │   │   │   │   ├── columns.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── commands-menu/
    │   │   │   │   │   ├── CommandsView.vue
    │   │   │   │   │   ├── commands.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── details/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── document/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── drop-cursor/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── extensions-kit.ts
    │   │   │   │   ├── figure/
    │   │   │   │   │   ├── FigureCaptionView.vue
    │   │   │   │   │   ├── figure-caption.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── font-size/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── format-brush/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── util.ts
    │   │   │   │   ├── gallery/
    │   │   │   │   │   ├── BubbleItemAddImage.vue
    │   │   │   │   │   ├── BubbleItemGap.vue
    │   │   │   │   │   ├── BubbleItemGroupSize.vue
    │   │   │   │   │   ├── BubbleItemLayout.vue
    │   │   │   │   │   ├── GalleryView.vue
    │   │   │   │   │   ├── gallery-bubble.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── useGalleryImages.ts
    │   │   │   │   ├── gap-cursor/
    │   │   │   │   │   ├── gap-cursor-selection.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── hard-break/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── heading/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── highlight/
    │   │   │   │   │   ├── HighlightBubbleItem.vue
    │   │   │   │   │   ├── HighlightToolbarItem.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── history/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── horizontal-rule/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── iframe/
    │   │   │   │   │   ├── BubbleItemIframeAlign.vue
    │   │   │   │   │   ├── BubbleItemIframeLink.vue
    │   │   │   │   │   ├── BubbleItemIframeSize.vue
    │   │   │   │   │   ├── IframeView.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── image/
    │   │   │   │   │   ├── BubbleItemImageAlt.vue
    │   │   │   │   │   ├── BubbleItemImageHref.vue
    │   │   │   │   │   ├── BubbleItemImageLink.vue
    │   │   │   │   │   ├── BubbleItemImagePosition.vue
    │   │   │   │   │   ├── BubbleItemImageSize.vue
    │   │   │   │   │   ├── ImageView.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── indent/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── italic/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── link/
    │   │   │   │   │   ├── LinkBubbleButton.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── list-extra/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── list-keymap/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── node-selected/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── ordered-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── paragraph/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── placeholder/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── range-selection/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   └── range-selection.ts
    │   │   │   │   ├── search-and-replace/
    │   │   │   │   │   ├── IconButton.vue
    │   │   │   │   │   ├── MatchToggleButton.vue
    │   │   │   │   │   ├── SearchAndReplace.vue
    │   │   │   │   │   ├── SearchAndReplacePlugin.ts
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── smart-scroll/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── strike/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── subscript/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── superscript/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── table/
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── table-cell.ts
    │   │   │   │   │   ├── table-header.ts
    │   │   │   │   │   ├── table-row.ts
    │   │   │   │   │   └── util.ts
    │   │   │   │   ├── task-list/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text/
    │   │   │   │   │   ├── BubbleItemTextType.vue
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text-align/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── text-style/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── trailing-node/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── underline/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── upload/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── video/
    │   │   │   │       ├── BubbleItemVideoLink.vue
    │   │   │   │       ├── BubbleItemVideoPosition.vue
    │   │   │   │       ├── BubbleItemVideoSize.vue
    │   │   │   │       ├── VideoView.vue
    │   │   │   │       └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── locales/
    │   │   │   │   ├── en.json
    │   │   │   │   ├── es.json
    │   │   │   │   ├── index.ts
    │   │   │   │   └── zh-CN.json
    │   │   │   ├── styles/
    │   │   │   │   ├── base.scss
    │   │   │   │   ├── columns.scss
    │   │   │   │   ├── details.scss
    │   │   │   │   ├── draggable.scss
    │   │   │   │   ├── figure.scss
    │   │   │   │   ├── format-brush.scss
    │   │   │   │   ├── gap-cursor.scss
    │   │   │   │   ├── index.scss
    │   │   │   │   ├── node-select.scss
    │   │   │   │   ├── range-selection.scss
    │   │   │   │   ├── resizer.scss
    │   │   │   │   ├── search.scss
    │   │   │   │   ├── table.scss
    │   │   │   │   └── tailwind.css
    │   │   │   ├── tiptap/
    │   │   │   │   ├── core/
    │   │   │   │   │   └── index.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── pm/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── vue-3/
    │   │   │   │       └── index.ts
    │   │   │   ├── types/
    │   │   │   │   └── index.ts
    │   │   │   └── utils/
    │   │   │       ├── anchor.ts
    │   │   │       ├── attachment.ts
    │   │   │       ├── clipboard.ts
    │   │   │       ├── delete-node.ts
    │   │   │       ├── filter-duplicate-extensions.ts
    │   │   │       ├── index.ts
    │   │   │       ├── is-allowed-uri.ts
    │   │   │       ├── is-list-active.ts
    │   │   │       ├── is-node-empty.ts
    │   │   │       ├── keyboard.ts
    │   │   │       └── upload.ts
    │   │   ├── tailwind.config.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   ├── tsconfig.vitest.json
    │   │   └── vite.config.ts
    │   ├── shared/
    │   │   ├── env.d.ts
    │   │   ├── package.json
    │   │   ├── src/
    │   │   │   ├── events/
    │   │   │   │   └── index.ts
    │   │   │   ├── index.ts
    │   │   │   ├── plugin/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types/
    │   │   │   │       ├── attachment-selector.ts
    │   │   │   │       ├── backup.ts
    │   │   │   │       ├── comment.ts
    │   │   │   │       ├── dashboard-widget.ts
    │   │   │   │       ├── editor-provider.ts
    │   │   │   │       ├── index.ts
    │   │   │   │       ├── list-entity-field.ts
    │   │   │   │       ├── list-operation.ts
    │   │   │   │       ├── plugin-installation-tab.ts
    │   │   │   │       ├── plugin-tab.ts
    │   │   │   │       ├── theme-list-tab.ts
    │   │   │   │       ├── ui-plugin-entry.ts
    │   │   │   │       ├── ui-plugin-module.ts
    │   │   │   │       └── user-tab.ts
    │   │   │   ├── stores/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types/
    │   │   │   │       ├── actuator.ts
    │   │   │   │       ├── index.ts
    │   │   │   │       └── slug.ts
    │   │   │   ├── types/
    │   │   │   │   ├── index.ts
    │   │   │   │   └── menus.ts
    │   │   │   └── utils/
    │   │   │       ├── attachment.ts
    │   │   │       ├── date.ts
    │   │   │       ├── id.ts
    │   │   │       ├── index.ts
    │   │   │       └── permission.ts
    │   │   ├── tsconfig.app.json
    │   │   ├── tsconfig.json
    │   │   ├── tsconfig.node.json
    │   │   └── tsdown.config.ts
    │   └── ui-plugin-bundler-kit/
    │       ├── README.md
    │       ├── package.json
    │       ├── src/
    │       │   ├── constants/
    │       │   │   ├── build.ts
    │       │   │   ├── externals.ts
    │       │   │   └── halo-plugin.ts
    │       │   ├── index.ts
    │       │   ├── legacy.ts
    │       │   ├── rsbuild.ts
    │       │   ├── utils/
    │       │   │   └── halo-plugin.ts
    │       │   └── vite.ts
    │       ├── tsconfig.json
    │       └── tsdown.config.ts
    ├── patches/
    │   └── @tiptap__extension-drag-handle@3.17.1.patch
    ├── pnpm-workspace.yaml
    ├── postcss.config.cjs
    ├── scripts/
    │   ├── apply_missing_translations.mjs
    │   ├── find_missing_translations.mjs
    │   └── fix_translations.mjs
    ├── src/
    │   ├── components/
    │   │   ├── alerts/
    │   │   │   └── H2WarningAlert.vue
    │   │   ├── attachment/
    │   │   │   ├── AttachmentGridListItem.vue
    │   │   │   ├── AttachmentImagePreview.vue
    │   │   │   └── AttachmentPermalinkList.vue
    │   │   ├── back-to-top/
    │   │   │   └── BackToTop.vue
    │   │   ├── base-app/
    │   │   │   └── BaseApp.vue
    │   │   ├── button/
    │   │   │   └── SubmitButton.vue
    │   │   ├── codemirror/
    │   │   │   ├── Codemirror.vue
    │   │   │   └── supports.ts
    │   │   ├── common/
    │   │   │   └── AppDownloadAlert.vue
    │   │   ├── dropdown-selector/
    │   │   │   └── EditorProviderSelector.vue
    │   │   ├── editor/
    │   │   │   └── DefaultEditor.vue
    │   │   ├── entity/
    │   │   │   └── EntityDropdownItems.vue
    │   │   ├── entity-fields/
    │   │   │   ├── EntityFieldItems.vue
    │   │   │   └── StatusDotField.vue
    │   │   ├── filter/
    │   │   │   ├── CategoryFilterDropdown.vue
    │   │   │   ├── FilterCleanButton.vue
    │   │   │   ├── FilterDropdown.vue
    │   │   │   ├── FilterTag.vue
    │   │   │   ├── TagFilterDropdown.vue
    │   │   │   └── UserFilterDropdown.vue
    │   │   ├── form/
    │   │   │   └── AnnotationsForm.vue
    │   │   ├── global-search/
    │   │   │   └── GlobalSearchModal.vue
    │   │   ├── icon/
    │   │   │   └── AttachmentFileTypeIcon.vue
    │   │   ├── input/
    │   │   │   └── SearchInput.vue
    │   │   ├── menu/
    │   │   │   ├── MenuLoading.vue
    │   │   │   └── RoutesMenu.tsx
    │   │   ├── permission/
    │   │   │   └── HasPermission.vue
    │   │   ├── preview/
    │   │   │   └── UrlPreviewModal.vue
    │   │   ├── sticky-block/
    │   │   │   └── StickyBlock.vue
    │   │   ├── upload/
    │   │   │   └── UppyUpload.vue
    │   │   ├── user/
    │   │   │   └── PostContributorList.vue
    │   │   ├── user-avatar/
    │   │   │   ├── UserAvatar.vue
    │   │   │   └── UserAvatarCropper.vue
    │   │   └── video/
    │   │       └── LazyVideo.vue
    │   ├── composables/
    │   │   ├── use-auto-save-content.ts
    │   │   ├── use-content-cache.ts
    │   │   ├── use-editor-extension-points.ts
    │   │   ├── use-role.ts
    │   │   ├── use-route-menu-generator.ts
    │   │   ├── use-session-keep-alive.ts
    │   │   └── use-title.ts
    │   ├── constants/
    │   │   ├── annotations.ts
    │   │   ├── app.ts
    │   │   ├── constants.ts
    │   │   ├── error-types.ts
    │   │   ├── finalizers.ts
    │   │   ├── labels.ts
    │   │   └── regex.ts
    │   ├── formkit/
    │   │   ├── formkit.config.ts
    │   │   ├── inputs/
    │   │   │   ├── array/
    │   │   │   │   ├── ArrayFormModal.vue
    │   │   │   │   ├── ArrayInput.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── labels/
    │   │   │   │   │   ├── ColorLabel.vue
    │   │   │   │   │   └── IconifyLabel.vue
    │   │   │   │   ├── renderers/
    │   │   │   │   │   ├── attachment.ts
    │   │   │   │   │   ├── category-select.ts
    │   │   │   │   │   ├── checkbox.ts
    │   │   │   │   │   ├── helpers/
    │   │   │   │   │   │   └── findOption.ts
    │   │   │   │   │   ├── iconify.ts
    │   │   │   │   │   ├── index.ts
    │   │   │   │   │   ├── native-select.ts
    │   │   │   │   │   ├── radio.ts
    │   │   │   │   │   ├── select.ts
    │   │   │   │   │   ├── tag-select.ts
    │   │   │   │   │   ├── toggle.ts
    │   │   │   │   │   └── types.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── attachment/
    │   │   │   │   ├── AttachmentDropdownItem.vue
    │   │   │   │   ├── AttachmentInput.vue
    │   │   │   │   ├── AttachmentPreview.vue
    │   │   │   │   ├── CustomLinkDropdownItem.vue
    │   │   │   │   ├── UploadDropdownItem.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── attachment-group-select.ts
    │   │   │   ├── attachment-input/
    │   │   │   │   ├── AttachmentInput.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── attachment-policy-select.ts
    │   │   │   ├── category-checkbox.ts
    │   │   │   ├── category-select/
    │   │   │   │   ├── CategorySelect.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── CategoryListItem.vue
    │   │   │   │   │   ├── CategoryTag.vue
    │   │   │   │   │   └── SearchResultListItem.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── code/
    │   │   │   │   ├── CodeInput.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── color/
    │   │   │   │   ├── ColorInput.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types.ts
    │   │   │   ├── form.ts
    │   │   │   ├── group.ts
    │   │   │   ├── iconify/
    │   │   │   │   ├── Collections.vue
    │   │   │   │   ├── CollectionsView.vue
    │   │   │   │   ├── Icon.vue
    │   │   │   │   ├── IconConfirmPanel.vue
    │   │   │   │   ├── IconifyInput.vue
    │   │   │   │   ├── IconifyPicker.vue
    │   │   │   │   ├── Icons.vue
    │   │   │   │   ├── SearchView.vue
    │   │   │   │   ├── api.ts
    │   │   │   │   ├── feature.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   └── types.ts
    │   │   │   ├── list/
    │   │   │   │   ├── AddButton.vue
    │   │   │   │   ├── features/
    │   │   │   │   │   └── lists.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── listSection.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── menu-checkbox.ts
    │   │   │   ├── menu-item-select.ts
    │   │   │   ├── menu-radio.ts
    │   │   │   ├── menu-select.ts
    │   │   │   ├── password/
    │   │   │   │   ├── RevealButton.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── post-select.ts
    │   │   │   ├── repeater/
    │   │   │   │   ├── AddButton.vue
    │   │   │   │   ├── features/
    │   │   │   │   │   └── repeats.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── repeaterSection.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── role-select.ts
    │   │   │   ├── secret/
    │   │   │   │   ├── SecretSelect.vue
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── SecretCreationModal.vue
    │   │   │   │   │   ├── SecretEditModal.vue
    │   │   │   │   │   ├── SecretForm.vue
    │   │   │   │   │   ├── SecretListItem.vue
    │   │   │   │   │   └── SecretListModal.vue
    │   │   │   │   ├── composables/
    │   │   │   │   │   └── use-secrets-fetch.ts
    │   │   │   │   ├── feature.ts
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── sections/
    │   │   │   │   │   └── index.ts
    │   │   │   │   └── types/
    │   │   │   │       └── index.ts
    │   │   │   ├── select/
    │   │   │   │   ├── MultipleOverflow.vue
    │   │   │   │   ├── MultipleOverflowItem.vue
    │   │   │   │   ├── MultipleSelect.vue
    │   │   │   │   ├── MultipleSelectItem.vue
    │   │   │   │   ├── MultipleSelectSearchInput.vue
    │   │   │   │   ├── MultipleSelectSelector.vue
    │   │   │   │   ├── SelectContainer.vue
    │   │   │   │   ├── SelectDropdownContainer.vue
    │   │   │   │   ├── SelectMain.vue
    │   │   │   │   ├── SelectOption.vue
    │   │   │   │   ├── SelectOptionItem.vue
    │   │   │   │   ├── SelectSearchInput.vue
    │   │   │   │   ├── SelectSelector.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   ├── isFalse.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── singlePage-select.ts
    │   │   │   ├── switch/
    │   │   │   │   ├── SwitchInput.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── tag-checkbox.ts
    │   │   │   ├── tag-select/
    │   │   │   │   ├── TagSelect.vue
    │   │   │   │   ├── index.ts
    │   │   │   │   └── sections/
    │   │   │   │       └── index.ts
    │   │   │   ├── toggle/
    │   │   │   │   ├── ToggleInput.vue
    │   │   │   │   ├── feature.ts
    │   │   │   │   └── index.ts
    │   │   │   ├── user-select.ts
    │   │   │   └── verify-form/
    │   │   │       ├── VerificationButton.vue
    │   │   │       ├── features/
    │   │   │       │   └── index.ts
    │   │   │       └── index.ts
    │   │   ├── plugins/
    │   │   │   ├── auto-scroll-to-errors.ts
    │   │   │   ├── password-prevent-autocomplete.ts
    │   │   │   ├── radio-alt.ts
    │   │   │   ├── required-asterisk.ts
    │   │   │   └── stop-implicit-submission.ts
    │   │   ├── theme.ts
    │   │   └── utils/
    │   │       └── focus.ts
    │   ├── layouts/
    │   │   ├── MobileMenu.vue
    │   │   └── UserProfileBanner.vue
    │   ├── locales/
    │   │   ├── en.json
    │   │   ├── es.json
    │   │   ├── index.ts
    │   │   ├── zh-CN.json
    │   │   └── zh-TW.json
    │   ├── router/
    │   │   └── process-bar.ts
    │   ├── setup/
    │   │   ├── setupApiClient.ts
    │   │   ├── setupComponents.ts
    │   │   ├── setupModules.ts
    │   │   ├── setupStyles.ts
    │   │   ├── setupUserPermissions.ts
    │   │   └── setupVueQuery.ts
    │   ├── stores/
    │   │   ├── plugin.ts
    │   │   └── role.ts
    │   ├── styles/
    │   │   ├── index.css
    │   │   └── tailwind.css
    │   ├── utils/
    │   │   ├── __tests__/
    │   │   │   └── media-type.spec.ts
    │   │   ├── cookie.ts
    │   │   ├── device.ts
    │   │   ├── image.ts
    │   │   ├── load-style.ts
    │   │   ├── media-type.ts
    │   │   ├── modal.ts
    │   │   └── role.ts
    │   ├── views/
    │   │   └── exceptions/
    │   │       ├── Forbidden.vue
    │   │       ├── NotFound.vue
    │   │       ├── __tests__/
    │   │       │   └── NotFound.spec.ts
    │   │       └── components/
    │   │           └── Exception.vue
    │   └── vite/
    │       ├── library-external.ts
    │       └── plugin-dev.ts
    ├── tailwind.config.ts
    ├── tsconfig.app.json
    ├── tsconfig.json
    ├── tsconfig.node.json
    ├── tsconfig.vitest.json
    ├── uc-src/
    │   ├── App.vue
    │   ├── layouts/
    │   │   └── BasicLayout.vue
    │   ├── main.ts
    │   ├── modules/
    │   │   ├── contents/
    │   │   │   ├── attachments/
    │   │   │   │   ├── components/
    │   │   │   │   │   ├── AttachmentDetailModal.vue
    │   │   │   │   │   ├── AttachmentSelectorModal.vue
    │   │   │   │   │   └── selector-providers/
    │   │   │   │   │       ├── AttachmentUploadModal.vue
    │   │   │   │   │       ├── CoreSelectorProvider.vue
    │   │   │   │   │       └── components/
    │   │   │   │   │           └── AttachmentSelectorListItem.vue
    │   │   │   │   └── module.ts
    │   │   │   └── posts/
    │   │   │       ├── PostEditor.vue
    │   │   │       ├── PostList.vue
    │   │   │       ├── components/
    │   │   │       │   ├── PostCreationModal.vue
    │   │   │       │   ├── PostListItem.vue
    │   │   │       │   ├── PostSettingEditModal.vue
    │   │   │       │   └── PostSettingForm.vue
    │   │   │       ├── composables/
    │   │   │       │   ├── use-post-publish-mutate.ts
    │   │   │       │   └── use-post-update-mutate.ts
    │   │   │       ├── module.ts
    │   │   │       └── types/
    │   │   │           └── index.ts
    │   │   ├── index.ts
    │   │   ├── notifications/
    │   │   │   ├── Notifications.vue
    │   │   │   ├── components/
    │   │   │   │   ├── NotificationContent.vue
    │   │   │   │   └── NotificationListItem.vue
    │   │   │   └── module.ts
    │   │   └── profile/
    │   │       ├── Profile.vue
    │   │       ├── components/
    │   │       │   ├── EmailVerifyModal.vue
    │   │       │   ├── PasswordChangeModal.vue
    │   │       │   ├── PersonalAccessTokenCreationModal.vue
    │   │       │   ├── PersonalAccessTokenListItem.vue
    │   │       │   └── ProfileEditingModal.vue
    │   │       ├── module.ts
    │   │       └── tabs/
    │   │           ├── Authentication.vue
    │   │           ├── Detail.vue
    │   │           ├── Devices.vue
    │   │           ├── NotificationPreferences.vue
    │   │           ├── PersonalAccessTokens.vue
    │   │           ├── components/
    │   │           │   ├── AuthProviders.vue
    │   │           │   ├── DeviceDetailModal.vue
    │   │           │   ├── DeviceListItem.vue
    │   │           │   ├── PasswordValidationForm.vue
    │   │           │   ├── TotpConfigureModal.vue
    │   │           │   ├── TotpDeletionModal.vue
    │   │           │   ├── TwoFactor.vue
    │   │           │   ├── TwoFactorDisableModal.vue
    │   │           │   └── TwoFactorEnableModal.vue
    │   │           └── composables/
    │   │               ├── use-user-agent.ts
    │   │               └── use-user-device.ts
    │   └── router/
    │       ├── constant.ts
    │       ├── guards/
    │       │   ├── auth-check.ts
    │       │   └── permission.ts
    │       ├── index.ts
    │       └── routes.config.ts
    ├── uc.html
    └── vite.config.ts
Download .txt
Showing preview only (934K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (10096 symbols across 1795 files)

FILE: api/src/main/java/run/halo/app/content/ContentWrapper.java
  class ContentWrapper (line 13) | @Data
    method patchSnapshot (line 21) | public static ContentWrapper patchSnapshot(Snapshot patchSnapshot, Sna...

FILE: api/src/main/java/run/halo/app/content/ExcerptGenerator.java
  type ExcerptGenerator (line 9) | public interface ExcerptGenerator extends ExtensionPoint {
    method generate (line 11) | Mono<String> generate(ExcerptGenerator.Context context);
    class Context (line 13) | @Data

FILE: api/src/main/java/run/halo/app/content/PatchUtils.java
  class PatchUtils (line 24) | public class PatchUtils {
    method create (line 28) | public static Patch<String> create(String deltasJson) {
    method patchToJson (line 49) | public static String patchToJson(Patch<String> patch) {
    method applyPatch (line 54) | public static String applyPatch(String original, String patchJson) {
    method diffToJsonPatch (line 63) | public static String diffToJsonPatch(String original, String revised) {
    method breakLine (line 68) | public static List<String> breakLine(String content) {
    class Delta (line 75) | @Data
    class StringChunk (line 82) | @Data

FILE: api/src/main/java/run/halo/app/content/PostContentService.java
  type PostContentService (line 6) | public interface PostContentService {
    method getHeadContent (line 8) | Mono<ContentWrapper> getHeadContent(String postName);
    method getReleaseContent (line 10) | Mono<ContentWrapper> getReleaseContent(String postName);
    method getSpecifiedContent (line 12) | Mono<ContentWrapper> getSpecifiedContent(String postName, String snaps...
    method listSnapshots (line 14) | Flux<String> listSnapshots(String postName);

FILE: api/src/main/java/run/halo/app/content/comment/CommentSubject.java
  type CommentSubject (line 14) | public interface CommentSubject<T extends Extension> extends ExtensionPo...
    method get (line 16) | Mono<T> get(String name);
    method getSubjectDisplay (line 18) | default Mono<SubjectDisplay> getSubjectDisplay(String name) {
    method supports (line 22) | boolean supports(Ref ref);

FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java
  type ThumbnailProvider (line 18) | @Deprecated(forRemoval = true, since = "2.22.0")
    method generate (line 27) | Mono<URI> generate(ThumbnailContext context);
    method delete (line 34) | Mono<Void> delete(URL imageUrl);
    method supports (line 41) | Mono<Boolean> supports(ThumbnailContext context);
    class ThumbnailContext (line 43) | @Data

FILE: api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java
  type ThumbnailSize (line 7) | @Getter
    method ThumbnailSize (line 16) | ThumbnailSize(int width) {
    method fromWidth (line 25) | public static ThumbnailSize fromWidth(String width) {
    method fromName (line 37) | public static ThumbnailSize fromName(String name) {
    method optionalValueOf (line 46) | public static Optional<ThumbnailSize> optionalValueOf(String name) {
    method allowedWidths (line 55) | public static Integer[] allowedWidths() {

FILE: api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java
  type WebSocketEndpoint (line 11) | public interface WebSocketEndpoint {
    method urlPath (line 18) | String urlPath();
    method groupVersion (line 25) | GroupVersion groupVersion();
    method handler (line 32) | WebSocketHandler handler();

FILE: api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java
  class AnnotationSetting (line 15) | @Data
    class AnnotationSettingSpec (line 28) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/AuthProvider.java
  class AuthProvider (line 21) | @Data
    class AuthProviderSpec (line 35) | @Data
      method setAuthType (line 74) | public void setAuthType(AuthType authType) {
    class SettingRef (line 79) | @Data
    class ConfigMapRef (line 89) | @Data
    type AuthType (line 96) | public enum AuthType {

FILE: api/src/main/java/run/halo/app/core/extension/Counter.java
  class Counter (line 15) | @Data
    method emptyCounter (line 31) | public static Counter emptyCounter(String name) {

FILE: api/src/main/java/run/halo/app/core/extension/Device.java
  class Device (line 15) | @Data
    method setStatus (line 30) | public void setStatus(Status status) {
    class Spec (line 34) | @Data
    class Status (line 58) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/Menu.java
  class Menu (line 14) | @Data
    class Spec (line 23) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/MenuItem.java
  class MenuItem (line 17) | @Data
    type Target (line 30) | public enum Target {
      method Target (line 38) | @JsonCreator
      method getValue (line 43) | @JsonValue
    class MenuItemSpec (line 49) | @Data
    class MenuItemStatus (line 75) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/Plugin.java
  class Plugin (line 28) | @Data
    method statusNonNull (line 49) | @NonNull
    class PluginSpec (line 58) | @Data
    class License (line 107) | @Data
    class PluginStatus (line 113) | @Data
      method nullSafeConditions (line 133) | public static ConditionList nullSafeConditions(@NonNull PluginStatus...
    type Phase (line 142) | public enum Phase {
    class PluginAuthor (line 156) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/RememberMeToken.java
  class RememberMeToken (line 13) | @Data
    class Spec (line 22) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/ReverseProxy.java
  class ReverseProxy (line 17) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/Role.java
  class Role (line 23) | @Data
    class PolicyRule (line 60) | @Getter
      method PolicyRule (line 101) | public PolicyRule() {
      method PolicyRule (line 105) | public PolicyRule(String[] apiGroups, String[] resources,
      method nullElseEmpty (line 115) | String[] nullElseEmpty(String... items) {
      method compareTo (line 122) | @Override
      class Builder (line 144) | public static class Builder {
        method apiGroups (line 155) | public Builder apiGroups(String... apiGroups) {
        method resources (line 160) | public Builder resources(String... resources) {
        method resourceNames (line 165) | public Builder resourceNames(String... resourceNames) {
        method nonResourceURLs (line 170) | public Builder nonResourceURLs(String... nonResourceURLs) {
        method verbs (line 175) | public Builder verbs(String... verbs) {
        method build (line 180) | public PolicyRule build() {

FILE: api/src/main/java/run/halo/app/core/extension/RoleBinding.java
  class RoleBinding (line 30) | @Data
    class RoleRef (line 64) | @Data
    class Subject (line 87) | @Data
      method isUser (line 111) | public static Predicate<Subject> isUser(String username) {
      method containsUser (line 117) | public static Predicate<Subject> containsUser(Set<String> usernames) {
      method toString (line 123) | @Override
    method create (line 132) | public static RoleBinding create(String username, String roleName) {
    method containsUser (line 158) | public static Predicate<RoleBinding> containsUser(String username) {
    method containsUser (line 164) | public static Predicate<RoleBinding> containsUser(Set<String> username...

FILE: api/src/main/java/run/halo/app/core/extension/Setting.java
  class Setting (line 20) | @Data
    class SettingSpec (line 33) | @Data
    class SettingForm (line 40) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/Theme.java
  class Theme (line 24) | @Data
    class ThemeSpec (line 40) | @Data
    class ThemeStatus (line 77) | @Data
    method nullSafeConditionList (line 90) | public static ConditionList nullSafeConditionList(Theme theme) {
    type ThemePhase (line 100) | public enum ThemePhase {
    class Author (line 106) | @Data
    class CustomTemplates (line 116) | @Data
    class TemplateDescriptor (line 129) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/User.java
  class User (line 21) | @Data
    class UserSpec (line 55) | @Data
    class UserStatus (line 86) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/UserConnection.java
  class UserConnection (line 19) | @Data
    class UserConnectionSpec (line 28) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java
  class Attachment (line 17) | @Data
    class AttachmentSpec (line 31) | @Data
    class AttachmentStatus (line 60) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/attachment/Constant.java
  type Constant (line 5) | public enum Constant {

FILE: api/src/main/java/run/halo/app/core/extension/attachment/Group.java
  class Group (line 14) | @Data
    class GroupSpec (line 29) | @Data
    class GroupStatus (line 37) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/attachment/Policy.java
  class Policy (line 13) | @Data
    class PolicySpec (line 26) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java
  class PolicyTemplate (line 13) | @Data
    class PolicyTemplateSpec (line 24) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java
  type AttachmentHandler (line 16) | public interface AttachmentHandler extends ExtensionPoint {
    method upload (line 18) | Mono<Attachment> upload(UploadContext context);
    method delete (line 20) | Mono<Attachment> delete(DeleteContext context);
    method getSharedURL (line 35) | default Mono<URI> getSharedURL(Attachment attachment,
    method getPermalink (line 54) | default Mono<URI> getPermalink(Attachment attachment,
    method getThumbnailLinks (line 68) | default Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment att...
    type UploadContext (line 74) | interface UploadContext {
      method file (line 76) | FilePart file();
      method policy (line 78) | Policy policy();
      method configMap (line 80) | ConfigMap configMap();
      method group (line 87) | @Nullable
    type DeleteContext (line 94) | interface DeleteContext {
      method attachment (line 95) | Attachment attachment();
      method policy (line 97) | Policy policy();
      method configMap (line 99) | ConfigMap configMap();

FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java
  method transferTo (line 24) | @Override
  method name (line 29) | @Override
  method headers (line 34) | @Override

FILE: api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java
  method from (line 19) | public static UploadOption from(String filename,

FILE: api/src/main/java/run/halo/app/core/extension/content/Category.java
  class Category (line 22) | @Data
    method isDeleted (line 40) | @JsonIgnore
    class CategorySpec (line 45) | @Data
    method getStatusOrDefault (line 94) | @JsonIgnore
    class CategoryStatus (line 102) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/content/Comment.java
  class Comment (line 25) | @Data
    method getStatusOrDefault (line 42) | @JsonIgnore
    class CommentSpec (line 50) | @Data
    class BaseCommentSpec (line 61) | @Data
    class CommentOwner (line 100) | @Data
      method getAnnotation (line 117) | @Nullable
      method ownerIdentity (line 123) | public static String ownerIdentity(String kind, String name) {
    class CommentStatus (line 128) | @Data
    method toSubjectRefKey (line 144) | public static String toSubjectRefKey(Ref subjectRef) {
    method getUnreadReplyCount (line 148) | public static int getUnreadReplyCount(List<Reply> replies, Instant las...

FILE: api/src/main/java/run/halo/app/core/extension/content/Constant.java
  type Constant (line 3) | public enum Constant {

FILE: api/src/main/java/run/halo/app/core/extension/content/Post.java
  class Post (line 28) | @Data
    method getStatusOrDefault (line 72) | @JsonIgnore
    method isDeleted (line 80) | @JsonIgnore
    method isPublished (line 86) | @JsonIgnore
    method isPublished (line 91) | public static boolean isPublished(MetadataOperator metadata) {
    method isRecycled (line 96) | public static boolean isRecycled(MetadataOperator metadata) {
    method isPublic (line 101) | public static boolean isPublic(PostSpec spec) {
    class PostSpec (line 105) | @Data
    class PostStatus (line 158) | @Data
      method getConditionsOrDefault (line 184) | @JsonIgnore
    class Excerpt (line 193) | @Data
    type PostPhase (line 202) | public enum PostPhase {
      method from (line 214) | public static PostPhase from(String value) {
    type VisibleEnum (line 224) | public enum VisibleEnum {
      method from (line 235) | public static VisibleEnum from(String value) {

FILE: api/src/main/java/run/halo/app/core/extension/content/Reply.java
  class Reply (line 19) | @Data
    class ReplySpec (line 37) | @Data
    class Status (line 47) | @Data
    method setStatus (line 53) | public void setStatus(Status status) {

FILE: api/src/main/java/run/halo/app/core/extension/content/SinglePage.java
  class SinglePage (line 24) | @Data
    method getStatusOrDefault (line 47) | @JsonIgnore
    method isPublished (line 55) | @JsonIgnore
    class SinglePageSpec (line 61) | @Data
    class SinglePageStatus (line 110) | @Data
    method changePublishedState (line 116) | public static void changePublishedState(SinglePage page, boolean value) {

FILE: api/src/main/java/run/halo/app/core/extension/content/Snapshot.java
  class Snapshot (line 23) | @Data
    class SnapShotSpec (line 37) | @Data
    method addContributor (line 63) | public static void addContributor(Snapshot snapshot, String name) {
    method isBaseSnapshot (line 79) | public static boolean isBaseSnapshot(@NonNull Snapshot snapshot) {
    method toSubjectRefKey (line 87) | public static String toSubjectRefKey(Ref subjectRef) {

FILE: api/src/main/java/run/halo/app/core/extension/content/Tag.java
  class Tag (line 19) | @Data
    class TagSpec (line 38) | @Data
    method getStatusOrDefault (line 68) | @JsonIgnore
    class TagStatus (line 76) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java
  type CustomEndpoint (line 12) | public interface CustomEndpoint {
    method endpoint (line 14) | RouterFunction<ServerResponse> endpoint();
    method groupVersion (line 16) | default GroupVersion groupVersion() {

FILE: api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java
  type SortResolver (line 10) | public interface SortResolver {
    method resolve (line 14) | @NonNull
    class DefaultSortResolver (line 17) | class DefaultSortResolver extends ReactiveSortHandlerMethodArgumentRes...
      method getDefaultFromAnnotationOrFallback (line 20) | @Override
      method resolve (line 26) | @Override

FILE: api/src/main/java/run/halo/app/core/extension/notification/Notification.java
  class Notification (line 28) | @Data
    class NotificationSpec (line 37) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/notification/NotificationTemplate.java
  class NotificationTemplate (line 21) | @Data
    class Spec (line 30) | @Data
    class Template (line 40) | @Data
    class ReasonSelector (line 51) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/notification/NotifierDescriptor.java
  class NotifierDescriptor (line 20) | @Data
    class Spec (line 29) | @Data
    class SettingRef (line 45) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/notification/Reason.java
  class Reason (line 25) | @Data
    class Spec (line 34) | @Data
    class Subject (line 52) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/notification/ReasonType.java
  class ReasonType (line 21) | @Data
    class Spec (line 32) | @Data
    class ReasonProperty (line 45) | @Data

FILE: api/src/main/java/run/halo/app/core/extension/notification/Subscription.java
  class Subscription (line 26) | @Data
    class Spec (line 35) | @Data
    class InterestReason (line 52) | @Data
      method ensureSubjectHasValue (line 75) | public static void ensureSubjectHasValue(InterestReason interestReas...
      method isFallbackSubject (line 84) | public static boolean isFallbackSubject(ReasonSubject reasonSubject) {
      method createFallbackSubject (line 93) | static ReasonSubject createFallbackSubject() {
    class ReasonSubject (line 101) | @Data
      method toString (line 118) | @Override
    class Subscriber (line 124) | @Data
      method toString (line 130) | @Override
    method generateUnsubscribeToken (line 141) | public static String generateUnsubscribeToken() {

FILE: api/src/main/java/run/halo/app/core/extension/service/AttachmentService.java
  type AttachmentService (line 24) | public interface AttachmentService {
    method upload (line 38) | Mono<Attachment> upload(
    method upload (line 59) | Mono<Attachment> upload(@NonNull String policyName,
    method delete (line 73) | Mono<Attachment> delete(Attachment attachment);
    method getPermalink (line 83) | Mono<URI> getPermalink(Attachment attachment);
    method getSharedURL (line 95) | Mono<URI> getSharedURL(Attachment attachment, Duration ttl);
    method getThumbnailLinks (line 104) | Mono<Map<ThumbnailSize, URI>> getThumbnailLinks(Attachment attachment);
    method uploadFromUrl (line 115) | Mono<Attachment> uploadFromUrl(@NonNull URL url, @NonNull String polic...

FILE: api/src/main/java/run/halo/app/core/user/service/RoleService.java
  type RoleService (line 16) | public interface RoleService {
    method listRoleBindings (line 18) | Flux<RoleBinding> listRoleBindings(Subject subject);
    method getRolesByUsername (line 20) | Flux<String> getRolesByUsername(String username);
    method getRolesByUsernames (line 22) | Mono<Map<String, Collection<String>>> getRolesByUsernames(Collection<S...
    method contains (line 24) | Mono<Boolean> contains(Collection<String> source, Collection<String> c...
    method listPermissions (line 33) | Flux<Role> listPermissions(Set<String> names);
    method listDependenciesFlux (line 35) | Flux<Role> listDependenciesFlux(Set<String> names);
    method list (line 43) | Flux<Role> list(Set<String> roleNames);
    method list (line 52) | Flux<Role> list(Set<String> roleNames, boolean excludeHidden);

FILE: api/src/main/java/run/halo/app/core/user/service/SignUpData.java
  class SignUpData (line 25) | @Data
    class SignUpDataConstraintValidator (line 65) | private static class SignUpDataConstraintValidator
      method isValid (line 68) | @Override

FILE: api/src/main/java/run/halo/app/core/user/service/UserPostCreatingHandler.java
  type UserPostCreatingHandler (line 13) | public interface UserPostCreatingHandler extends ExtensionPoint {
    method postCreating (line 21) | Mono<Void> postCreating(User user);

FILE: api/src/main/java/run/halo/app/core/user/service/UserPreCreatingHandler.java
  type UserPreCreatingHandler (line 13) | public interface UserPreCreatingHandler extends ExtensionPoint {
    method preCreating (line 21) | Mono<Void> preCreating(User user);

FILE: api/src/main/java/run/halo/app/core/user/service/UserService.java
  type UserService (line 9) | public interface UserService {
    method getUser (line 19) | Mono<User> getUser(String username);
    method findUserByVerifiedEmail (line 27) | Mono<User> findUserByVerifiedEmail(String email);
    method getUserOrGhost (line 29) | Mono<User> getUserOrGhost(String username);
    method getUsersOrGhosts (line 31) | Flux<User> getUsersOrGhosts(Collection<String> names);
    method updatePassword (line 33) | Mono<User> updatePassword(String username, String newPassword);
    method updateWithRawPassword (line 35) | Mono<User> updateWithRawPassword(String username, String rawPassword);
    method grantRoles (line 37) | Mono<User> grantRoles(String username, Set<String> roles);
    method hasSufficientRoles (line 45) | Mono<Boolean> hasSufficientRoles(Collection<String> roles);
    method signUp (line 47) | Mono<User> signUp(SignUpData signUpData);
    method createUser (line 49) | Mono<User> createUser(User user, Set<String> roles);
    method confirmPassword (line 51) | Mono<Boolean> confirmPassword(String username, String rawPassword);
    method listByEmail (line 53) | Flux<User> listByEmail(String email);
    method checkEmailAlreadyVerified (line 55) | Mono<Boolean> checkEmailAlreadyVerified(String email);
    method encryptPassword (line 57) | String encryptPassword(String rawPassword);
    method disable (line 59) | Mono<User> disable(String username);
    method enable (line 61) | Mono<User> enable(String username);

FILE: api/src/main/java/run/halo/app/event/post/PostDeletedEvent.java
  class PostDeletedEvent (line 6) | @SharedEvent
    method PostDeletedEvent (line 11) | public PostDeletedEvent(Object source, Post post) {
    method getPost (line 21) | public Post getPost() {

FILE: api/src/main/java/run/halo/app/event/post/PostEvent.java
  class PostEvent (line 10) | public abstract class PostEvent extends ApplicationEvent {
    method PostEvent (line 14) | public PostEvent(Object source, String name) {
    method getName (line 24) | public String getName() {

FILE: api/src/main/java/run/halo/app/event/post/PostPublishedEvent.java
  class PostPublishedEvent (line 5) | @SharedEvent
    method PostPublishedEvent (line 8) | public PostPublishedEvent(Object source, String postName) {

FILE: api/src/main/java/run/halo/app/event/post/PostUnpublishedEvent.java
  class PostUnpublishedEvent (line 5) | @SharedEvent
    method PostUnpublishedEvent (line 8) | public PostUnpublishedEvent(Object source, String postName) {

FILE: api/src/main/java/run/halo/app/event/post/PostUpdatedEvent.java
  class PostUpdatedEvent (line 5) | @SharedEvent
    method PostUpdatedEvent (line 8) | public PostUpdatedEvent(Object source, String postName) {

FILE: api/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java
  class PostVisibleChangedEvent (line 7) | @SharedEvent
    method PostVisibleChangedEvent (line 15) | public PostVisibleChangedEvent(Object source, String postName,
    method getOldVisible (line 22) | @Nullable
    method getNewVisible (line 27) | public Post.VisibleEnum getNewVisible() {

FILE: api/src/main/java/run/halo/app/event/user/UserConnectionDisconnectedEvent.java
  class UserConnectionDisconnectedEvent (line 14) | @SharedEvent
    method UserConnectionDisconnectedEvent (line 20) | public UserConnectionDisconnectedEvent(Object source, UserConnection u...

FILE: api/src/main/java/run/halo/app/event/user/UserLoginEvent.java
  class UserLoginEvent (line 13) | @SharedEvent
    method UserLoginEvent (line 19) | public UserLoginEvent(Object source, User user) {

FILE: api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java
  class UserLogoutEvent (line 13) | @SharedEvent
    method UserLogoutEvent (line 19) | public UserLogoutEvent(Object source, User user) {

FILE: api/src/main/java/run/halo/app/extension/AbstractExtension.java
  class AbstractExtension (line 10) | @Data
    method getApiVersion (line 19) | @Override
    method getKind (line 25) | @Override

FILE: api/src/main/java/run/halo/app/extension/Comparators.java
  type Comparators (line 6) | public enum Comparators {
    method compareCreationTimestamp (line 9) | public static <E extends Extension> Comparator<E> compareCreationTimes...
    method compareName (line 15) | public static <E extends Extension> Comparator<E> compareName(boolean ...
    method defaultComparator (line 20) | public static <T extends Extension> Comparator<T> defaultComparator() {
    method nullsComparator (line 32) | public static Comparator<Object> nullsComparator(boolean isAscending) {

FILE: api/src/main/java/run/halo/app/extension/ConfigMap.java
  class ConfigMap (line 16) | @Data
    method putDataItem (line 28) | public ConfigMap putDataItem(String key, String dataItem) {

FILE: api/src/main/java/run/halo/app/extension/DefaultExtensionMatcher.java
  class DefaultExtensionMatcher (line 12) | @Getter
    method builder (line 21) | public static DefaultExtensionMatcherBuilder builder(ExtensionClient c...
    method match (line 32) | @Override
    method hasFieldSelector (line 50) | boolean hasFieldSelector() {
    method hasLabelSelector (line 54) | boolean hasLabelSelector() {

FILE: api/src/main/java/run/halo/app/extension/Extension.java
  type Extension (line 10) | public interface Extension extends ExtensionOperator, Comparable<Extensi...
    method compareTo (line 12) | @Override

FILE: api/src/main/java/run/halo/app/extension/ExtensionClient.java
  type ExtensionClient (line 19) | public interface ExtensionClient {
    method list (line 30) | <E extends Extension> List<E> list(Class<E> type, Predicate<E> predicate,
    method list (line 45) | @Deprecated
    method listAll (line 49) | <E extends Extension> List<E> listAll(Class<E> type, ListOptions optio...
    method listAllNames (line 51) | <E extends Extension> List<String> listAllNames(Class<E> type, ListOpt...
    method listTopNames (line 53) | <E extends Extension> List<String> listTopNames(Class<E> type, ListOpt...
    method listBy (line 56) | <E extends Extension> ListResult<E> listBy(Class<E> type, ListOptions ...
    method listNamesBy (line 59) | <E extends Extension> ListResult<String> listNamesBy(Class<E> type, Li...
    method countBy (line 62) | <E extends Extension> long countBy(Class<E> type, ListOptions options);
    method fetch (line 72) | <E extends Extension> Optional<E> fetch(Class<E> type, String name);
    method fetch (line 74) | Optional<Unstructured> fetch(GroupVersionKind gvk, String name);
    method create (line 84) | <E extends Extension> void create(E extension);
    method update (line 93) | <E extends Extension> void update(E extension);
    method delete (line 102) | <E extends Extension> void delete(E extension);
    method indexedQueryEngine (line 104) | @Deprecated(forRemoval = true, since = "2.22.0")
    method watch (line 107) | void watch(Watcher watcher);

FILE: api/src/main/java/run/halo/app/extension/ExtensionMatcher.java
  type ExtensionMatcher (line 3) | @FunctionalInterface
    method match (line 6) | boolean match(Extension extension);

FILE: api/src/main/java/run/halo/app/extension/ExtensionOperator.java
  type ExtensionOperator (line 16) | public interface ExtensionOperator {
    method getApiVersion (line 18) | @Schema(requiredMode = REQUIRED)
    method getKind (line 32) | @Schema(requiredMode = REQUIRED)
    method getMetadata (line 43) | @Schema(requiredMode = REQUIRED, implementation = Metadata.class)
    method setApiVersion (line 47) | void setApiVersion(String apiVersion);
    method setKind (line 49) | void setKind(String kind);
    method setMetadata (line 51) | void setMetadata(MetadataOperator metadata);
    method groupVersionKind (line 58) | default void groupVersionKind(GroupVersionKind gvk) {
    method groupVersionKind (line 68) | @JsonIgnore
    method isNotDeleted (line 73) | static <T extends ExtensionOperator> Predicate<T> isNotDeleted() {
    method isDeleted (line 77) | static boolean isDeleted(ExtensionOperator extension) {

FILE: api/src/main/java/run/halo/app/extension/ExtensionUtil.java
  type ExtensionUtil (line 13) | public enum ExtensionUtil {
    method hasDoNotOverwriteLabel (line 28) | public static boolean hasDoNotOverwriteLabel(ExtensionOperator extensi...
    method isDeleted (line 36) | public static boolean isDeleted(ExtensionOperator extension) {
    method addFinalizers (line 41) | public static boolean addFinalizers(MetadataOperator metadata, Set<Str...
    method removeFinalizers (line 51) | public static boolean removeFinalizers(MetadataOperator metadata, Set<...
    method notDeleting (line 68) | public static Query notDeleting() {
    method defaultSort (line 77) | public static Sort defaultSort() {

FILE: api/src/main/java/run/halo/app/extension/GroupVersion.java
  method toString (line 15) | @Override
  method parseAPIVersion (line 29) | public static GroupVersion parseAPIVersion(String apiVersion) {

FILE: api/src/main/java/run/halo/app/extension/GroupVersionKind.java
  method groupVersion (line 26) | public GroupVersion groupVersion() {
  method groupKind (line 30) | public GroupKind groupKind() {
  method hasGroup (line 34) | public boolean hasGroup() {
  method fromAPIVersionAndKind (line 45) | public static GroupVersionKind fromAPIVersionAndKind(String apiVersion, ...
  method fromExtension (line 52) | public static <T extends Extension> GroupVersionKind fromExtension(Class...
  method toString (line 57) | @Override

FILE: api/src/main/java/run/halo/app/extension/JsonExtension.java
  class JsonExtension (line 29) | @JsonSerialize(using = JsonExtension.ObjectNodeExtensionSerializer.class)
    method JsonExtension (line 38) | public JsonExtension(ObjectMapper objectMapper) {
    method JsonExtension (line 42) | public JsonExtension(ObjectMapper objectMapper, ObjectNode objectNode) {
    method JsonExtension (line 47) | public JsonExtension(ObjectMapper objectMapper, Extension e) {
    method getMetadata (line 51) | @Override
    method getApiVersion (line 60) | @Override
    method getKind (line 66) | @Override
    method setApiVersion (line 71) | @Override
    method setKind (line 76) | @Override
    method setMetadata (line 81) | @Override
    class ObjectNodeExtensionSerializer (line 86) | public static class ObjectNodeExtensionSerializer extends JsonSerializ...
      method serialize (line 88) | @Override
    class ObjectNodeExtensionDeSerializer (line 95) | public static class ObjectNodeExtensionDeSerializer
      method deserialize (line 98) | @Override
    method getInternal (line 112) | public ObjectNode getInternal() {
    method getObjectMapper (line 121) | public ObjectMapper getObjectMapper() {
    method getMetadataOrCreate (line 125) | public MetadataOperator getMetadataOrCreate() {
    method equals (line 131) | @Override
    method hashCode (line 143) | @Override
    class ObjectNodeMetadata (line 148) | class ObjectNodeMetadata implements MetadataOperator {
      method ObjectNodeMetadata (line 152) | public ObjectNodeMetadata(ObjectNode objectNode) {
      method getName (line 156) | @Override
      method getGenerateName (line 162) | @Override
      method getLabels (line 168) | @Override
      method getAnnotations (line 175) | @Override
      method getVersion (line 182) | @Override
      method getCreationTimestamp (line 188) | @Override
      method getDeletionTimestamp (line 193) | @Override
      method getFinalizers (line 198) | @Override
      method setName (line 204) | @Override
      method setGenerateName (line 211) | @Override
      method setLabels (line 218) | @Override
      method setAnnotations (line 225) | @Override
      method setVersion (line 232) | @Override
      method setCreationTimestamp (line 239) | @Override
      method setDeletionTimestamp (line 246) | @Override
      method setFinalizers (line 253) | @Override
      method equals (line 260) | @Override
      method hashCode (line 270) | @Override

FILE: api/src/main/java/run/halo/app/extension/ListOptions.java
  class ListOptions (line 14) | @Data
    method toString (line 22) | @Override
    method toCondition (line 32) | @NonNull
    method builder (line 60) | public static ListOptionsBuilder builder() {
    method builder (line 64) | public static ListOptionsBuilder builder(ListOptions listOptions) {
    class ListOptionsBuilder (line 68) | public static class ListOptionsBuilder {
      method ListOptionsBuilder (line 72) | public ListOptionsBuilder() {
      method ListOptionsBuilder (line 78) | public ListOptionsBuilder(ListOptions listOptions) {
      method labelSelector (line 91) | public LabelSelectorBuilder labelSelector() {
      method fieldQuery (line 98) | public ListOptionsBuilder fieldQuery(Query query) {
      method andQuery (line 106) | public ListOptionsBuilder andQuery(Query query) {
      method orQuery (line 126) | public ListOptionsBuilder orQuery(Query query) {
      method build (line 146) | public ListOptions build() {
    class LabelSelectorBuilder (line 158) | public static class LabelSelectorBuilder
      method LabelSelectorBuilder (line 162) | public LabelSelectorBuilder(List<LabelCondition> conditions,
      method LabelSelectorBuilder (line 168) | public LabelSelectorBuilder(ListOptionsBuilder listOptionsBuilder) {
      method end (line 172) | public ListOptionsBuilder end() {

FILE: api/src/main/java/run/halo/app/extension/ListResult.java
  class ListResult (line 19) | @Data
    method ListResult (line 36) | @JsonCreator
    method ListResult (line 58) | public ListResult(List<T> items) {
    method isFirst (line 62) | @Schema(description = "Indicates whether current page is the first pag...
    method isLast (line 68) | @Schema(description = "Indicates whether current page is the last page.",
    method hasNext (line 74) | @Schema(description = "Indicates whether current page has previous pag...
    method hasPrevious (line 84) | @Schema(description = "Indicates whether current page has previous pag...
    method iterator (line 91) | @Override
    method getTotalPages (line 96) | @Schema(description = "Indicates total pages.", requiredMode = REQUIRED)
    method generateGenericClass (line 109) | public static Class<?> generateGenericClass(Scheme scheme) {
    method generateGenericClass (line 125) | public static <T> Class<?> generateGenericClass(Class<T> type) {
    method emptyResult (line 130) | public static <T> ListResult<T> emptyResult() {
    method subList (line 137) | public static <T> List<T> subList(List<T> list, int page, int size) {
    method first (line 157) | public static <T> Optional<T> first(ListResult<T> listResult) {
    method get (line 163) | @Override

FILE: api/src/main/java/run/halo/app/extension/Metadata.java
  class Metadata (line 14) | @Data

FILE: api/src/main/java/run/halo/app/extension/MetadataOperator.java
  type MetadataOperator (line 18) | @JsonDeserialize(as = Metadata.class)
    method getName (line 23) | @Schema(name = "name", description = "Metadata name", requiredMode = R...
    method getGenerateName (line 27) | @Schema(name = "generateName", description = "The name field will be g...
    method getLabels (line 31) | @Schema(name = "labels")
    method getAnnotations (line 35) | @Schema(name = "annotations")
    method getVersion (line 39) | @Schema(name = "version", nullable = true)
    method getCreationTimestamp (line 43) | @Schema(name = "creationTimestamp", nullable = true)
    method getDeletionTimestamp (line 47) | @Schema(name = "deletionTimestamp", nullable = true)
    method getFinalizers (line 51) | @Schema(name = "finalizers", nullable = true)
    method setName (line 54) | void setName(String name);
    method setGenerateName (line 56) | void setGenerateName(String generateName);
    method setLabels (line 58) | void setLabels(Map<String, String> labels);
    method setAnnotations (line 60) | void setAnnotations(Map<String, String> annotations);
    method setVersion (line 62) | void setVersion(Long version);
    method setCreationTimestamp (line 64) | void setCreationTimestamp(Instant creationTimestamp);
    method setDeletionTimestamp (line 66) | void setDeletionTimestamp(Instant deletionTimestamp);
    method setFinalizers (line 68) | void setFinalizers(Set<String> finalizers);
    method equals (line 77) | static boolean equals(MetadataOperator left, MetadataOperator right) {
    method hashCode (line 100) | static int hashCode(MetadataOperator metadata) {

FILE: api/src/main/java/run/halo/app/extension/MetadataUtil.java
  type MetadataUtil (line 7) | public enum MetadataUtil {
    method nullSafeLabels (line 19) | public static Map<String, String> nullSafeLabels(AbstractExtension ext...
    method nullSafeAnnotations (line 36) | public static Map<String, String> nullSafeAnnotations(AbstractExtensio...

FILE: api/src/main/java/run/halo/app/extension/PageRequest.java
  type PageRequest (line 15) | public interface PageRequest {
    method getPageNumber (line 16) | int getPageNumber();
    method getPageSize (line 18) | int getPageSize();
    method previous (line 20) | PageRequest previous();
    method next (line 22) | PageRequest next();
    method previousOrFirst (line 31) | PageRequest previousOrFirst();
    method first (line 39) | PageRequest first();
    method withPage (line 47) | PageRequest withPage(int pageNumber);
    method withSort (line 49) | PageRequestImpl withSort(Sort sort);
    method hasPrevious (line 51) | boolean hasPrevious();
    method getSort (line 53) | Sort getSort();
    method getSortOr (line 61) | default Sort getSortOr(Sort sort) {

FILE: api/src/main/java/run/halo/app/extension/PageRequestImpl.java
  class PageRequestImpl (line 9) | @Slf4j
    method PageRequestImpl (line 18) | public PageRequestImpl(int pageNumber, int pageSize, Sort sort) {
    method of (line 36) | public static PageRequestImpl of(int pageNumber, int pageSize) {
    method of (line 40) | public static PageRequestImpl of(int pageNumber, int pageSize, Sort so...
    method ofSize (line 44) | public static PageRequestImpl ofSize(int pageSize) {
    method getPageNumber (line 48) | @Override
    method getPageSize (line 53) | @Override
    method previous (line 58) | @Override
    method getSort (line 64) | @Override
    method next (line 69) | @Override
    method previousOrFirst (line 74) | @Override
    method first (line 79) | @Override
    method withPage (line 84) | @Override
    method withSort (line 89) | @Override
    method hasPrevious (line 95) | @Override

FILE: api/src/main/java/run/halo/app/extension/ReactiveExtensionClient.java
  type ReactiveExtensionClient (line 16) | public interface ReactiveExtensionClient {
    method list (line 27) | <E extends Extension> Flux<E> list(Class<E> type, Predicate<E> predicate,
    method list (line 41) | @Deprecated
    method listAll (line 45) | <E extends Extension> Flux<E> listAll(Class<E> type, ListOptions optio...
    method listAllNames (line 47) | <E extends Extension> Flux<String> listAllNames(Class<E> type, ListOpt...
    method listTopNames (line 49) | <E extends Extension> Flux<String> listTopNames(Class<E> type, ListOpt...
    method listBy (line 52) | <E extends Extension> Mono<ListResult<E>> listBy(Class<E> type, ListOp...
    method listNamesBy (line 55) | <E extends Extension> Mono<ListResult<String>> listNamesBy(Class<E> ty...
    method countBy (line 58) | <E extends Extension> Mono<Long> countBy(Class<E> type, ListOptions op...
    method fetch (line 68) | <E extends Extension> Mono<E> fetch(Class<E> type, String name);
    method fetch (line 70) | Mono<Unstructured> fetch(GroupVersionKind gvk, String name);
    method get (line 72) | <E extends Extension> Mono<E> get(Class<E> type, String name);
    method getJsonExtension (line 74) | @Deprecated(forRemoval = true, since = "2.23.0")
    method create (line 84) | <E extends Extension> Mono<E> create(E extension);
    method update (line 93) | <E extends Extension> Mono<E> update(E extension);
    method delete (line 102) | <E extends Extension> Mono<E> delete(E extension);
    method indexedQueryEngine (line 104) | @Deprecated(forRemoval = true, since = "2.22.0")
    method watch (line 107) | void watch(Watcher watcher);

FILE: api/src/main/java/run/halo/app/extension/Ref.java
  class Ref (line 11) | @Data
    method of (line 28) | public static Ref of(String name) {
    method of (line 34) | public static Ref of(String name, GroupVersionKind gvk) {
    method of (line 43) | public static Ref of(Extension extension) {
    method groupKindEquals (line 61) | public static boolean groupKindEquals(Ref ref, GroupVersionKind gvk) {
    method equals (line 73) | public static boolean equals(@NonNull Ref ref, @NonNull ExtensionOpera...

FILE: api/src/main/java/run/halo/app/extension/Scheme.java
  method buildFromType (line 41) | public static Scheme buildFromType(Class<? extends Extension> type) {
  method getGvkFromType (line 69) | @NonNull
  method equals (line 77) | @Override
  method hashCode (line 89) | @Override

FILE: api/src/main/java/run/halo/app/extension/SchemeManager.java
  type SchemeManager (line 12) | public interface SchemeManager {
    method register (line 20) | default <E extends Extension> void register(Class<E> type) {
    method register (line 24) | default void register(Scheme scheme) {
    method register (line 28) | <E extends Extension> void register(
    method unregister (line 32) | void unregister(@NonNull Scheme scheme);
    method size (line 34) | default int size() {
    method schemes (line 38) | @NonNull
    method fetch (line 41) | @NonNull
    method get (line 48) | @NonNull
    method get (line 54) | @NonNull
    method get (line 60) | @NonNull

FILE: api/src/main/java/run/halo/app/extension/Secret.java
  class Secret (line 16) | @Data

FILE: api/src/main/java/run/halo/app/extension/Unstructured.java
  class Unstructured (line 37) | @JsonSerialize(using = Unstructured.UnstructuredSerializer.class)
    method Unstructured (line 57) | public Unstructured() {
    method Unstructured (line 61) | public Unstructured(Map data) {
    method getData (line 65) | public Map getData() {
    method getApiVersion (line 69) | @Override
    method getKind (line 74) | @Override
    method getMetadata (line 79) | @Override
    class UnstructuredMetadata (line 86) | static class UnstructuredMetadata implements MetadataOperator {
      method UnstructuredMetadata (line 91) | UnstructuredMetadata(@NonNull Map<String, Object> metadata) {
      method getName (line 95) | @Override
      method getGenerateName (line 100) | @Override
      method getLabels (line 105) | @Override
      method getAnnotations (line 110) | @Override
      method getVersion (line 115) | @Override
      method getCreationTimestamp (line 120) | @Override
      method getDeletionTimestamp (line 125) | @Override
      method getFinalizers (line 130) | @Override
      method setName (line 135) | @Override
      method setGenerateName (line 140) | @Override
      method setLabels (line 145) | @Override
      method setAnnotations (line 150) | @Override
      method setVersion (line 155) | @Override
      method setCreationTimestamp (line 160) | @Override
      method setDeletionTimestamp (line 165) | @Override
      method setFinalizers (line 170) | @Override
      method equals (line 175) | @Override
      method hashCode (line 184) | @Override
    method setApiVersion (line 191) | @Override
    method setKind (line 196) | @Override
    method setMetadata (line 201) | @Override
    method getNestedValue (line 208) | public static Optional<Object> getNestedValue(Map map, String... field...
    method getNestedStringList (line 223) | @SuppressWarnings("unchecked")
    method getNestedStringSet (line 228) | public static Optional<Set<String>> getNestedStringSet(Map map, String...
    method setNestedValue (line 238) | @SuppressWarnings("unchecked")
    method getNestedMap (line 252) | public static Optional<Map> getNestedMap(Map map, String... fields) {
    method getNestedStringStringMap (line 256) | @SuppressWarnings("unchecked")
    method getNestedInstant (line 263) | public static Optional<Instant> getNestedInstant(Map map, String... fi...
    method getNestedLong (line 274) | public static Optional<Long> getNestedLong(Map map, String... fields) {
    class UnstructuredSerializer (line 284) | public static class UnstructuredSerializer extends JsonSerializer<Unst...
      method serialize (line 286) | @Override
    class UnstructuredValueSerializer (line 294) | static class UnstructuredValueSerializer extends ValueSerializer<Unstr...
      method serialize (line 296) | @Override
      method handledType (line 303) | @Override
    class UnstructuredValueDeserializer (line 309) | static class UnstructuredValueDeserializer extends ValueDeserializer<U...
      method deserialize (line 311) | @Override
    class UnstructuredDeserializer (line 319) | public static class UnstructuredDeserializer extends JsonDeserializer<...
      method deserialize (line 321) | @Override
    method equals (line 329) | @Override
    method hashCode (line 341) | @Override

FILE: api/src/main/java/run/halo/app/extension/Watcher.java
  type Watcher (line 8) | public interface Watcher extends Disposable {
    method onAdd (line 10) | default void onAdd(Reconciler.Request request) {
    method onAdd (line 14) | default void onAdd(Extension extension) {
    method onUpdate (line 18) | default void onUpdate(Extension oldExtension, Extension newExtension) {
    method onDelete (line 22) | default void onDelete(Extension extension) {
    method registerDisposeHook (line 26) | default void registerDisposeHook(Runnable dispose) {
    class WatcherComposite (line 29) | class WatcherComposite implements Watcher {
      method WatcherComposite (line 37) | public WatcherComposite() {
      method onAdd (line 41) | @Override
      method onUpdate (line 47) | @Override
      method onDelete (line 53) | @Override
      method addWatcher (line 59) | public void addWatcher(Watcher watcher) {
      method removeWatcher (line 66) | public void removeWatcher(Watcher watcher) {
      method registerDisposeHook (line 70) | @Override
      method dispose (line 75) | @Override
      method isDisposed (line 84) | @Override

FILE: api/src/main/java/run/halo/app/extension/WatcherExtensionMatchers.java
  class WatcherExtensionMatchers (line 8) | public class WatcherExtensionMatchers {
    method WatcherExtensionMatchers (line 20) | @Builder(builderMethodName = "internalBuilder")
    method getGroupVersionKind (line 36) | public GroupVersionKind getGroupVersionKind() {
    method onAddMatcher (line 40) | public ExtensionMatcher onAddMatcher() {
    method onUpdateMatcher (line 44) | public ExtensionMatcher onUpdateMatcher() {
    method onDeleteMatcher (line 48) | public ExtensionMatcher onDeleteMatcher() {
    method builder (line 52) | public static WatcherExtensionMatchersBuilder builder(ExtensionClient ...
    method emptyMatcher (line 57) | static ExtensionMatcher emptyMatcher(ExtensionClient client,
    method delegateExtensionMatcher (line 62) | ExtensionMatcher delegateExtensionMatcher(ExtensionMatcher matcher) {

FILE: api/src/main/java/run/halo/app/extension/WatcherPredicates.java
  class WatcherPredicates (line 6) | public class WatcherPredicates {
    method WatcherPredicates (line 15) | public WatcherPredicates(Predicate<Extension> onAddPredicate,
    method onAddPredicate (line 23) | public Predicate<Extension> onAddPredicate() {
    method onUpdatePredicate (line 30) | public BiPredicate<Extension, Extension> onUpdatePredicate() {
    method onDeletePredicate (line 37) | public Predicate<Extension> onDeletePredicate() {
    class Builder (line 44) | public static final class Builder {
      method withGroupVersionKind (line 52) | public Builder withGroupVersionKind(GroupVersionKind gvk) {
      method onAddPredicate (line 57) | public Builder onAddPredicate(Predicate<Extension> onAddPredicate) {
      method onUpdatePredicate (line 62) | public Builder onUpdatePredicate(
      method onDeletePredicate (line 68) | public Builder onDeletePredicate(Predicate<Extension> onDeletePredic...
      method build (line 73) | public WatcherPredicates build() {

FILE: api/src/main/java/run/halo/app/extension/controller/Controller.java
  type Controller (line 5) | public interface Controller extends Disposable {
    method getName (line 7) | String getName();
    method start (line 9) | void start();

FILE: api/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java
  class ControllerBuilder (line 14) | public class ControllerBuilder {
    method ControllerBuilder (line 42) | public ControllerBuilder(Reconciler<Request> reconciler, ExtensionClie...
    method minDelay (line 50) | public ControllerBuilder minDelay(Duration minDelay) {
    method maxDelay (line 55) | public ControllerBuilder maxDelay(Duration maxDelay) {
    method nowSupplier (line 60) | public ControllerBuilder nowSupplier(Supplier<Instant> nowSupplier) {
    method extension (line 65) | public ControllerBuilder extension(Extension extension) {
    method onAddMatcher (line 70) | public ControllerBuilder onAddMatcher(ExtensionMatcher onAddMatcher) {
    method onDeleteMatcher (line 75) | public ControllerBuilder onDeleteMatcher(ExtensionMatcher onDeleteMatc...
    method onUpdateMatcher (line 80) | public ControllerBuilder onUpdateMatcher(ExtensionMatcher extensionMat...
    method syncAllOnStart (line 85) | public ControllerBuilder syncAllOnStart(boolean syncAllAtStart) {
    method syncAllListOptions (line 90) | public ControllerBuilder syncAllListOptions(ListOptions syncAllListOpt...
    method workerCount (line 95) | public ControllerBuilder workerCount(int workerCount) {
    method build (line 100) | public Controller build() {
    method determineSyncAllListOptions (line 132) | ListOptions determineSyncAllListOptions() {

FILE: api/src/main/java/run/halo/app/extension/controller/DefaultController.java
  class DefaultController (line 19) | @Slf4j
    method DefaultController (line 47) | public DefaultController(String name,
    method DefaultController (line 59) | public DefaultController(String name,
    method DefaultController (line 80) | public DefaultController(String name,
    method DefaultController (line 89) | public DefaultController(String name,
    method DefaultController (line 98) | public DefaultController(String name,
    method executor (line 109) | private static Executor executor(String name) {
    method getName (line 119) | @Override
    method getWorkerCount (line 124) | public int getWorkerCount() {
    method start (line 128) | @Override
    class Worker (line 149) | class Worker implements Runnable {
      method Worker (line 153) | Worker() {
      method getName (line 158) | public String getName() {
      method run (line 162) | @Override
    method dispose (line 234) | @Override
    method isDisposed (line 263) | @Override
    method isStarted (line 268) | public boolean isStarted() {
    method closeExecutorService (line 277) | private static void closeExecutorService(ExecutorService executorServi...

FILE: api/src/main/java/run/halo/app/extension/controller/DefaultQueue.java
  class DefaultQueue (line 14) | @Slf4j
    method DefaultQueue (line 31) | public DefaultQueue(Supplier<Instant> nowSupplier) {
    method DefaultQueue (line 35) | public DefaultQueue(Supplier<Instant> nowSupplier, Duration minDelay) {
    method addImmediately (line 44) | @Override
    method add (line 51) | @Override
    method take (line 88) | @Override
    method done (line 106) | @Override
    method size (line 122) | @Override
    method peek (line 127) | @Override
    method dispose (line 132) | @Override
    method isDisposed (line 145) | @Override
    method findOldEntry (line 150) | private Optional<DelayedEntry<R>> findOldEntry(DelayedEntry<R> entry) {

FILE: api/src/main/java/run/halo/app/extension/controller/ExtensionWatcher.java
  class ExtensionWatcher (line 8) | public class ExtensionWatcher implements Watcher {
    method ExtensionWatcher (line 18) | public ExtensionWatcher(RequestQueue<Request> queue, WatcherExtensionM...
    method onAdd (line 23) | @Override
    method onAdd (line 31) | @Override
    method onUpdate (line 40) | @Override
    method onDelete (line 49) | @Override
    method registerDisposeHook (line 58) | @Override
    method dispose (line 63) | @Override
    method isDisposed (line 71) | @Override

FILE: api/src/main/java/run/halo/app/extension/controller/Reconciler.java
  type Reconciler (line 5) | public interface Reconciler<R> {
    method reconcile (line 7) | Result reconcile(R request);
    method setupWith (line 9) | Controller setupWith(ControllerBuilder builder);
    method doNotRetry (line 16) | public static Result doNotRetry() {
    method requeue (line 20) | public static Result requeue(Duration retryAfter) {

FILE: api/src/main/java/run/halo/app/extension/controller/RequestQueue.java
  type RequestQueue (line 11) | public interface RequestQueue<E> extends Disposable {
    method addImmediately (line 13) | boolean addImmediately(E request);
    method add (line 15) | boolean add(DelayedEntry<E> entry);
    method take (line 17) | DelayedEntry<E> take() throws InterruptedException;
    method done (line 19) | void done(E request);
    method size (line 21) | long size();
    method peek (line 23) | DelayedEntry<E> peek();
    class DelayedEntry (line 25) | class DelayedEntry<E> implements Delayed {
      method DelayedEntry (line 35) | DelayedEntry(E entry, Duration retryAfter, Supplier<Instant> nowSupp...
      method DelayedEntry (line 42) | public DelayedEntry(E entry, Instant readyAt, Supplier<Instant> nowS...
      method getDelay (line 49) | @Override
      method getRetryAfter (line 55) | public Duration getRetryAfter() {
      method getReadyAt (line 59) | public Instant getReadyAt() {
      method compareTo (line 63) | @Override
      method getEntry (line 68) | public E getEntry() {
      method equals (line 72) | @Override
      method hashCode (line 84) | @Override

FILE: api/src/main/java/run/halo/app/extension/controller/RequestSynchronizer.java
  class RequestSynchronizer (line 15) | @Slf4j
    method RequestSynchronizer (line 38) | public RequestSynchronizer(boolean syncAllOnStart,
    method start (line 50) | @Override
    method dispose (line 78) | @Override
    method isDisposed (line 84) | @Override

FILE: api/src/main/java/run/halo/app/extension/controller/RequeueException.java
  class RequeueException (line 11) | public class RequeueException extends RuntimeException {
    method RequeueException (line 15) | public RequeueException(Result result) {
    method RequeueException (line 19) | public RequeueException(Result result, String reason) {
    method RequeueException (line 23) | public RequeueException(Result result, String reason, Throwable t) {
    method getResult (line 28) | public Result getResult() {

FILE: api/src/main/java/run/halo/app/extension/controller/Synchronizer.java
  type Synchronizer (line 5) | public interface Synchronizer<R> extends Disposable {
    method start (line 7) | void start();

FILE: api/src/main/java/run/halo/app/extension/exception/ExtensionException.java
  class ExtensionException (line 12) | public class ExtensionException extends ResponseStatusException {
    method ExtensionException (line 14) | public ExtensionException(String reason) {
    method ExtensionException (line 18) | public ExtensionException(String reason, Throwable cause) {
    method ExtensionException (line 22) | protected ExtensionException(HttpStatusCode status, String reason, Thr...

FILE: api/src/main/java/run/halo/app/extension/exception/NotImplementedException.java
  class NotImplementedException (line 8) | public class NotImplementedException extends UnsupportedOperationExcepti...
    method NotImplementedException (line 10) | public NotImplementedException() {
    method NotImplementedException (line 14) | public NotImplementedException(String message) {

FILE: api/src/main/java/run/halo/app/extension/exception/SchemeNotFoundException.java
  class SchemeNotFoundException (line 11) | public class SchemeNotFoundException extends ExtensionException {
    method SchemeNotFoundException (line 13) | public SchemeNotFoundException(GroupVersionKind gvk) {

FILE: api/src/main/java/run/halo/app/extension/index/AbstractValueIndexSpecBuilder.java
  class AbstractValueIndexSpecBuilder (line 15) | abstract class AbstractValueIndexSpecBuilder<
    method AbstractValueIndexSpecBuilder (line 29) | protected AbstractValueIndexSpecBuilder(String name, Class<K> keyType) {
    method unique (line 36) | public B unique(boolean unique) {
    method nullable (line 41) | public B nullable(boolean nullable) {

FILE: api/src/main/java/run/halo/app/extension/index/DefaultIndexAttribute.java
  class DefaultIndexAttribute (line 9) | @Deprecated(forRemoval = true, since = "2.22.0")
    method DefaultIndexAttribute (line 21) | public DefaultIndexAttribute(
    method getObjectType (line 36) | @Override
    method getKeyType (line 41) | @Override
    method getValues (line 46) | @Override
    method checkType (line 54) | private boolean checkType(Extension object) {
    method singleValue (line 58) | @Override

FILE: api/src/main/java/run/halo/app/extension/index/IndexAttribute.java
  type IndexAttribute (line 14) | @Deprecated(forRemoval = true, since = "2.22.0")
    method getObjectType (line 22) | Class<E> getObjectType();
    method getKeyType (line 29) | Class<K> getKeyType();
    method getValues (line 38) | Set<K> getValues(E e);
    method singleValue (line 45) | boolean singleValue();

FILE: api/src/main/java/run/halo/app/extension/index/IndexAttributeFactory.java
  class IndexAttributeFactory (line 15) | @Deprecated(forRemoval = true, since = "2.22.0")
    method simpleAttribute (line 19) | public static <E extends Extension> IndexAttribute<E, UnknownKey> simp...
    method multiValueAttribute (line 26) | public static <E extends Extension> IndexAttribute<E, UnknownKey> mult...
    method attributes (line 37) | private static <E extends Extension, K extends Comparable<K>> IndexAtt...
    method attribute (line 43) | private static <E extends Extension, K extends Comparable<K>> IndexAtt...

FILE: api/src/main/java/run/halo/app/extension/index/IndexSpec.java
  class IndexSpec (line 17) | @Data
    method getValues (line 31) | public Set<K> getValues(E extension) {
    type OrderType (line 35) | public enum OrderType {
    method isNullable (line 40) | @Override
    method getKeyType (line 45) | @Override
    method equals (line 50) | @Override
    method hashCode (line 62) | @Override
    method normalize (line 72) | public ValueIndexSpec<E, K> normalize() {

FILE: api/src/main/java/run/halo/app/extension/index/IndexSpecBuilder.java
  type IndexSpecBuilder (line 13) | public interface IndexSpecBuilder<
    method unique (line 25) | B unique(boolean unique);
    method nullable (line 33) | B nullable(boolean nullable);
    method build (line 40) | ValueIndexSpec<E, K> build();

FILE: api/src/main/java/run/halo/app/extension/index/IndexSpecs.java
  type IndexSpecs (line 13) | public interface IndexSpecs<E extends Extension> {
    method add (line 22) | default <K extends Comparable<K>> void add(IndexSpec<E, K> indexSpec) {
    method add (line 26) | <K extends Comparable<K>> void add(ValueIndexSpec<E, K> indexSpec);
    method add (line 28) | default <K extends Comparable<K>> void add(IndexSpecBuilder<E, K, ?> b...
    method getIndexSpecs (line 37) | List<ValueIndexSpec<E, ?>> getIndexSpecs();
    method multi (line 48) | static <E extends Extension, K extends Comparable<K>> MultiValueIndexS...
    method single (line 64) | static <E extends Extension, K extends Comparable<K>> SingleValueIndex...

FILE: api/src/main/java/run/halo/app/extension/index/IndexedQueryEngine.java
  type IndexedQueryEngine (line 24) | @Deprecated(forRemoval = true, since = "2.22.0")
    method retrieve (line 37) | ListResult<String> retrieve(GroupVersionKind type, ListOptions options...
    method retrieveAll (line 48) | List<String> retrieveAll(GroupVersionKind type, ListOptions options, S...

FILE: api/src/main/java/run/halo/app/extension/index/KeyComparator.java
  class KeyComparator (line 6) | @Deprecated(forRemoval = true, since = "2.22.0")
    method compare (line 10) | @Override
    method compareStrings (line 24) | private int compareStrings(String a, String b) {
    method compareNumbers (line 60) | private int compareNumbers(String a, String b, int startA, int startB) {
    method compareDecimalNumbers (line 90) | private int compareDecimalNumbers(String a, String b, int startA, int ...
    method compareIntegerPart (line 105) | private int compareIntegerPart(String a, String b, int startA, int sta...
    method compareFractionalPart (line 129) | private int compareFractionalPart(String a, String b, int i, int j) {
    method countDigits (line 156) | private int countDigits(String s, int start) {
    method moveIndexToNextNonDigit (line 165) | private int moveIndexToNextNonDigit(String s, int index) {

FILE: api/src/main/java/run/halo/app/extension/index/MultiValueBuilder.java
  class MultiValueBuilder (line 16) | class MultiValueBuilder<E extends Extension, K extends Comparable<K>>
    method MultiValueBuilder (line 22) | MultiValueBuilder(String name, Class<K> keyType) {
    method indexFunc (line 26) | @Override
    method build (line 32) | @Override

FILE: api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpec.java
  type MultiValueIndexSpec (line 15) | interface MultiValueIndexSpec<E extends Extension, K extends Comparable<K>>
    method getValues (line 18) | @Nullable
    method builder (line 21) | static <E extends Extension, K extends Comparable<K>> MultiValueBuilde...

FILE: api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpecBuilder.java
  type MultiValueIndexSpecBuilder (line 15) | public interface MultiValueIndexSpecBuilder<E extends Extension, K exten...
    method indexFunc (line 24) | MultiValueIndexSpecBuilder<E, K> indexFunc(Function<E, Set<K>> indexFu...

FILE: api/src/main/java/run/halo/app/extension/index/SingleValueBuilder.java
  class SingleValueBuilder (line 15) | class SingleValueBuilder<E extends Extension, K extends Comparable<K>>
    method SingleValueBuilder (line 21) | SingleValueBuilder(String name, Class<K> keyType) {
    method indexFunc (line 25) | @Override
    method build (line 31) | @Override

FILE: api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpec.java
  type SingleValueIndexSpec (line 14) | interface SingleValueIndexSpec<E extends Extension, K extends Comparable...
    method getValue (line 17) | @Nullable
    method builder (line 20) | static <E extends Extension, K extends Comparable<K>> SingleValueBuild...

FILE: api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpecBuilder.java
  type SingleValueIndexSpecBuilder (line 14) | public interface SingleValueIndexSpecBuilder<E extends Extension, K exte...
    method indexFunc (line 23) | SingleValueIndexSpecBuilder<E, K> indexFunc(Function<E, K> indexFunc);

FILE: api/src/main/java/run/halo/app/extension/index/UnknownKey.java
  method compareTo (line 17) | @Override
  method equals (line 22) | @Override
  method toString (line 32) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/ValueIndexSpec.java
  type ValueIndexSpec (line 13) | public interface ValueIndexSpec<E extends Extension, K extends Comparabl...
    method getName (line 20) | String getName();
    method isUnique (line 27) | boolean isUnique();
    method isNullable (line 34) | boolean isNullable();
    method getKeyType (line 41) | Class<K> getKeyType();

FILE: api/src/main/java/run/halo/app/extension/index/query/AllCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/And.java
  method not (line 15) | @Override
  method toString (line 20) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/AndCondition.java
  method not (line 13) | @Override
  method toString (line 18) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/BetweenCondition.java
  method not (line 9) | @Override
  method toString (line 14) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/Condition.java
  type Condition (line 12) | public interface Condition extends Visitable, Query {
    method and (line 20) | default Condition and(Condition another) {
    method or (line 30) | default Condition or(Condition another) {
    method not (line 39) | default Condition not() {
    method empty (line 48) | static Condition empty() {

FILE: api/src/main/java/run/halo/app/extension/index/query/EmptyCondition.java
  method toString (line 7) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/EqualCondition.java
  method not (line 12) | @Override
  method toString (line 17) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/GreaterThanCondition.java
  method not (line 8) | @Override
  method toString (line 13) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/InCondition.java
  method not (line 14) | @Override
  method toString (line 19) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/IndexCondition.java
  type IndexCondition (line 9) | public interface IndexCondition extends Condition {
    method indexName (line 16) | String indexName();

FILE: api/src/main/java/run/halo/app/extension/index/query/IsNotNullCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/IsNullCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelCondition.java
  type LabelCondition (line 9) | public interface LabelCondition extends Condition {
    method labelKey (line 18) | String labelKey();
    method not (line 20) | @Override

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelEqualsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelExistsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelInCondition.java
  method not (line 13) | @Override
  method toString (line 18) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotEqualsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotExistsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LabelNotInCondition.java
  method not (line 14) | @Override
  method toString (line 19) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/LessThanCondition.java
  method not (line 8) | @Override
  method toString (line 13) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/NoneCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/NotBetweenCondition.java
  method not (line 9) | @Override
  method toString (line 14) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/NotCondition.java
  method not (line 12) | @Override
  method toString (line 17) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/NotEqualCondition.java
  method not (line 13) | @Override
  method toString (line 18) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/NotInCondition.java
  method not (line 14) | @Override
  method toString (line 19) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/OrCondition.java
  method not (line 13) | @Override
  method toString (line 18) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/Queries.java
  type Queries (line 17) | public enum Queries {
    method and (line 27) | public static Condition and(Condition condition, Condition... addition...
    method or (line 40) | public static Condition or(Condition condition, Condition... additiona...
    method not (line 52) | public static Condition not(Condition condition) {
    method between (line 67) | public static Condition between(String fieldName,
    method empty (line 77) | public static Condition empty() {
    method all (line 87) | public static Condition all(String fieldName) {
    method isNull (line 97) | public static Condition isNull(String fieldName) {
    method equal (line 108) | public static Condition equal(String fieldName, Object attributeValue) {
    method greaterThan (line 123) | public static Condition greaterThan(
    method greaterThan (line 135) | public static Condition greaterThan(String fieldName, Object attribute...
    method in (line 148) | @SuppressWarnings("unchecked")
    method in (line 174) | public static Condition in(String fieldName, Collection<Object> values) {
    method lessThan (line 191) | public static Condition lessThan(String fieldName, Object attributeVal...
    method lessThan (line 202) | public static Condition lessThan(String fieldName, Object attributeVal...
    method notEqual (line 213) | public static Condition notEqual(String fieldName, Object attributeVal...
    method startsWith (line 224) | public static Condition startsWith(String fieldName, String prefix) {
    method endsWith (line 235) | public static Condition endsWith(String fieldName, String suffix) {
    method contains (line 246) | public static Condition contains(String fieldName, String substring) {
    method labelExists (line 256) | public static LabelCondition labelExists(String labelKey) {
    method labelEqual (line 268) | public static LabelCondition labelEqual(String labelKey, String labelV...
    method labelIn (line 280) | public static LabelCondition labelIn(String labelKey, Collection<Strin...

FILE: api/src/main/java/run/halo/app/extension/index/query/Query.java
  type Query (line 13) | @Deprecated(since = "2.22.0", forRemoval = true)

FILE: api/src/main/java/run/halo/app/extension/index/query/QueryFactory.java
  class QueryFactory (line 17) | @Deprecated(since = "2.22.0", forRemoval = true)
    method all (line 21) | public static Query all() {
    method all (line 25) | public static Query all(String fieldName) {
    method isNull (line 29) | public static Query isNull(String fieldName) {
    method isNotNull (line 33) | public static Query isNotNull(String fieldName) {
    method notEqual (line 37) | public static Query notEqual(String fieldName, String attributeValue) {
    method equal (line 41) | public static Query equal(String fieldName, String attributeValue) {
    method lessThan (line 45) | public static Query lessThan(String fieldName, String attributeValue) {
    method lessThanOrEqual (line 49) | public static Query lessThanOrEqual(String fieldName, String attribute...
    method greaterThan (line 53) | public static Query greaterThan(String fieldName, String attributeValu...
    method greaterThanOrEqual (line 57) | public static Query greaterThanOrEqual(String fieldName, String attrib...
    method in (line 61) | public static Query in(String fieldName, String... attributeValues) {
    method in (line 65) | public static Query in(String fieldName, Collection<String> values) {
    method and (line 72) | public static Query and(Collection<Query> queries) {
    method and (line 89) | public static And and(Query left, Query right) {
    method and (line 97) | public static Query and(Query left, Query right, Query... additionalQu...
    method and (line 105) | public static Query and(Query left, Query right, Collection<Query> add...
    method or (line 113) | private static Query or(Collection<Query> queries) {
    method or (line 130) | public static Query or(Query left, Query right) {
    method or (line 134) | public static Query or(Query query1, Query query2, Query... additional...
    method or (line 142) | public static Query or(Query query1, Query query2, Collection<Query> a...
    method not (line 150) | public static Query not(Query query) {
    method betweenLowerExclusive (line 156) | public static Query betweenLowerExclusive(String fieldName, String low...
    method betweenUpperExclusive (line 161) | public static Query betweenUpperExclusive(String fieldName, String low...
    method betweenExclusive (line 166) | public static Query betweenExclusive(String fieldName, String lowerValue,
    method between (line 171) | public static Query between(String fieldName, String lowerValue, Strin...
    method startsWith (line 175) | public static Query startsWith(String fieldName, String value) {
    method endsWith (line 179) | public static Query endsWith(String fieldName, String value) {
    method contains (line 183) | public static Query contains(String fieldName, String value) {

FILE: api/src/main/java/run/halo/app/extension/index/query/StringContainsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/StringEndsWithCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotContainsCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotEndsWithCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/StringNotStartsWithCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/index/query/StringStartsWithCondition.java
  method not (line 7) | @Override
  method toString (line 12) | @NotNull

FILE: api/src/main/java/run/halo/app/extension/router/IListRequest.java
  type IListRequest (line 16) | public interface IListRequest {
    method getPage (line 18) | @Schema(description = "The page number. Zero indicates no page.")
    method getSize (line 21) | @Schema(description = "Size of one page. Zero indicates no limit.")
    method getLabelSelector (line 24) | @Schema(description = "Label selector for filtering.")
    method getFieldSelector (line 27) | @Schema(description = "Field selector for filtering.")
    class QueryListRequest (line 30) | class QueryListRequest implements IListRequest {
      method QueryListRequest (line 37) | public QueryListRequest(MultiValueMap<String, String> queryParams) {
      method getPage (line 41) | @Override
      method getSize (line 50) | @Override
      method getLabelSelector (line 59) | @Override
      method getFieldSelector (line 64) | @Override
    method buildParameters (line 70) | static void buildParameters(Builder builder) {

FILE: api/src/main/java/run/halo/app/extension/router/QueryParamBuildUtil.java
  class QueryParamBuildUtil (line 11) | @Slf4j
    method sortParameter (line 15) | public static org.springdoc.core.fn.builders.parameter.Builder sortPar...

FILE: api/src/main/java/run/halo/app/extension/router/SortableRequest.java
  class SortableRequest (line 25) | public class SortableRequest extends IListRequest.QueryListRequest {
    method SortableRequest (line 29) | public SortableRequest(ServerWebExchange exchange) {
    method getSort (line 34) | @ArraySchema(uniqueItems = true,
    method toListOptions (line 51) | public ListOptions toListOptions() {
    method toPageRequest (line 55) | public PageRequest toPageRequest() {
    method toComparator (line 65) | public <T extends Extension> Comparator<T> toComparator() {
    method buildParameters (line 90) | public static void buildParameters(Builder builder) {

FILE: api/src/main/java/run/halo/app/extension/router/selector/FieldSelector.java
  method FieldSelector (line 12) | public FieldSelector(Query query) {
  method of (line 16) | public static FieldSelector of(Query query) {
  method all (line 20) | public static FieldSelector all() {
  method andQuery (line 24) | public FieldSelector andQuery(Query other) {

FILE: api/src/main/java/run/halo/app/extension/router/selector/FieldSelectorConverter.java
  class FieldSelectorConverter (line 12) | public class FieldSelectorConverter implements Converter<SelectorCriteri...
    method convert (line 14) | @NonNull
    method getSingleValue (line 39) | String getSingleValue(SelectorCriteria criteria) {

FILE: api/src/main/java/run/halo/app/extension/router/selector/LabelSelector.java
  class LabelSelector (line 13) | @Data
    method toString (line 19) | @Override
    method and (line 38) | public LabelSelector and(LabelSelector other) {
    method builder (line 47) | public static LabelSelectorBuilder<?> builder() {
    class LabelSelectorBuilder (line 51) | public static class LabelSelectorBuilder<T extends LabelSelectorBuilde...
      method LabelSelectorBuilder (line 54) | public LabelSelectorBuilder() {
      method LabelSelectorBuilder (line 60) | public LabelSelectorBuilder(List<LabelCondition> conditions) {
      method self (line 66) | @SuppressWarnings("unchecked")
      method eq (line 71) | public T eq(String key, String value) {
      method notEq (line 76) | public T notEq(String key, String value) {
      method in (line 81) | public T in(String key, String... values) {
      method notIn (line 86) | public T notIn(String key, String... values) {
      method exists (line 91) | public T exists(String key) {
      method notExists (line 96) | public T notExists(String key) {
      method build (line 104) | public LabelSelector build() {

FILE: api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java
  class LabelSelectorConverter (line 12) | public class LabelSelectorConverter implements Converter<SelectorCriteri...
    method convert (line 14) | @NonNull
    method getSingleValue (line 38) | String getSingleValue(SelectorCriteria criteria) {

FILE: api/src/main/java/run/halo/app/extension/router/selector/Operator.java
  type Operator (line 7) | public enum Operator implements Converter<String, SelectorCriteria> {
    method convert (line 10) | @Override
    method convert (line 25) | @Override
    method convert (line 42) | @Override
    method convert (line 57) | @Override
    method convert (line 69) | @Override
    method Operator (line 85) | Operator(String operator, int order) {
    method getOperator (line 90) | public String getOperator() {
    method getOrder (line 94) | public int getOrder() {
    method preFlightCheck (line 98) | protected boolean preFlightCheck(String selector, int minLength) {

FILE: api/src/main/java/run/halo/app/extension/router/selector/SelectorConverter.java
  class SelectorConverter (line 10) | @Slf4j
    method convert (line 13) | @Override

FILE: api/src/main/java/run/halo/app/extension/router/selector/SelectorUtil.java
  class SelectorUtil (line 9) | public final class SelectorUtil {
    method SelectorUtil (line 11) | private SelectorUtil() {
    method labelAndFieldSelectorToListOptions (line 21) | public static ListOptions labelAndFieldSelectorToListOptions(

FILE: api/src/main/java/run/halo/app/infra/AnonymousUserConst.java
  type AnonymousUserConst (line 3) | public interface AnonymousUserConst {
    method isAnonymousUser (line 8) | static boolean isAnonymousUser(String principal) {

FILE: api/src/main/java/run/halo/app/infra/BackupRootGetter.java
  type BackupRootGetter (line 12) | public interface BackupRootGetter extends Supplier<Path> {

FILE: api/src/main/java/run/halo/app/infra/Condition.java
  class Condition (line 22) | @Data

FILE: api/src/main/java/run/halo/app/infra/ConditionList.java
  class ConditionList (line 21) | public class ConditionList extends AbstractCollection<Condition> {
    method add (line 25) | @Override
    method addFirst (line 33) | public boolean addFirst(@NonNull Condition condition) {
    method addAndEvictFIFO (line 47) | public boolean addAndEvictFIFO(@NonNull Condition condition) {
    method addAndEvictFIFO (line 57) | public boolean addAndEvictFIFO(@NonNull Condition condition, int evict...
    method getCondition (line 75) | private Condition getCondition(String type) {
    method remove (line 85) | public void remove(Condition condition) {
    method peek (line 99) | public Condition peek() {
    method peekFirst (line 103) | public Condition peekFirst() {
    method removeLast (line 107) | public Condition removeLast() {
    method clear (line 111) | @Override
    method size (line 116) | public int size() {
    method isSame (line 120) | private boolean isSame(Condition a, Condition b) {
    method iterator (line 130) | @Override
    method forEach (line 135) | @Override
    method equals (line 140) | @Override
    method hashCode (line 152) | @Override

FILE: api/src/main/java/run/halo/app/infra/ConditionStatus.java
  type ConditionStatus (line 7) | public enum ConditionStatus {

FILE: api/src/main/java/run/halo/app/infra/ExternalLinkProcessor.java
  type ExternalLinkProcessor (line 14) | public interface ExternalLinkProcessor {
    method processLink (line 23) | String processLink(String link);
    method processLink (line 36) | Mono<URI> processLink(URI uri);

FILE: api/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java
  type ExternalUrlSupplier (line 14) | public interface ExternalUrlSupplier extends Supplier<URI> {
    method get (line 22) | @Override
    method getURL (line 32) | URL getURL(HttpRequest request);
    method getRaw (line 39) | @Nullable

FILE: api/src/main/java/run/halo/app/infra/FileCategoryMatcher.java
  type FileCategoryMatcher (line 23) | public enum FileCategoryMatcher {
    method match (line 25) | @Override
    method match (line 31) | @Override
    method match (line 37) | @Override
    method match (line 43) | @Override
    method match (line 49) | @Override
    method match (line 65) | @Override
    method match (line 88) | @Override
    method match (line 94) | public abstract boolean match(String mimeType);
    method of (line 99) | public static FileCategoryMatcher of(String name) {

FILE: api/src/main/java/run/halo/app/infra/SystemInfo.java
  class SystemInfo (line 10) | @Data
    class SeoProp (line 33) | @Data

FILE: api/src/main/java/run/halo/app/infra/SystemInfoGetter.java
  type SystemInfoGetter (line 6) | public interface SystemInfoGetter extends Supplier<Mono<SystemInfo>> {

FILE: api/src/main/java/run/halo/app/infra/SystemSetting.java
  class SystemSetting (line 25) | public class SystemSetting {
    class Theme (line 62) | @Data
    class ThemeRouteRules (line 69) | @Data
      method empty (line 79) | public static ThemeRouteRules empty() {
    class CodeInjection (line 89) | @Data
    class Basic (line 100) | @Data
      method useSystemLocale (line 110) | @JsonIgnore
    class User (line 118) | @Data
    class Post (line 140) | @Data
    class Seo (line 155) | @Data
    class Comment (line 163) | @Data
    class Menu (line 171) | @Data
    class AuthProvider (line 177) | @Data
    class AuthProviderState (line 185) | @Data
    class ExtensionPointEnabled (line 197) | public static class ExtensionPointEnabled extends LinkedHashMap<String...
    method get (line 203) | @Nullable

FILE: api/src/main/java/run/halo/app/infra/SystemVersionSupplier.java
  type SystemVersionSupplier (line 14) | public interface SystemVersionSupplier extends Supplier<Version> {

FILE: api/src/main/java/run/halo/app/infra/ValidationUtils.java
  class ValidationUtils (line 11) | @UtilityClass
    method validate (line 27) | public static BindingResult validate(Object target, String objectName,
    method validate (line 39) | public static BindingResult validate(Object target, Validator validator,

FILE: api/src/main/java/run/halo/app/infra/model/License.java
  class License (line 8) | @Data

FILE: api/src/main/java/run/halo/app/infra/utils/FileTypeDetectUtils.java
  class FileTypeDetectUtils (line 17) | @UtilityClass
    method detectMimeType (line 30) | public static String detectMimeType(InputStream inputStream, String na...
    method detectMimeType (line 42) | public static String detectMimeType(InputStream inputStream) throws IO...
    method doDetectMimeType (line 46) | private static String doDetectMimeType(InputStream inputStream, Metada...
    method detectFileExtension (line 55) | public static String detectFileExtension(String mimeType) throws MimeT...
    method detectFileExtensions (line 60) | public static List<String> detectFileExtensions(String mimeType) throw...
    method getFileExtension (line 69) | @NonNull
    method isValidExtensionForMime (line 90) | public boolean isValidExtensionForMime(String mimeType, String fileNam...

FILE: api/src/main/java/run/halo/app/infra/utils/GenericClassUtils.java
  type GenericClassUtils (line 7) | public enum GenericClassUtils {
    method generateConcreteClass (line 18) | public static <T> Class<?> generateConcreteClass(Class<?> rawClass, Cl...
    method generateConcreteClass (line 32) | public static <T> Class<?> generateConcreteClass(Class<?> rawClass, Cl...

FILE: api/src/main/java/run/halo/app/infra/utils/JsonParseException.java
  class JsonParseException (line 9) | public class JsonParseException extends RuntimeException {
    method JsonParseException (line 10) | public JsonParseException() {
    method JsonParseException (line 14) | public JsonParseException(String message) {
    method JsonParseException (line 18) | public JsonParseException(String message, Throwable cause) {
    method JsonParseException (line 22) | public JsonParseException(Throwable cause) {
    method JsonParseException (line 26) | protected JsonParseException(String message, Throwable cause, boolean ...

FILE: api/src/main/java/run/halo/app/infra/utils/JsonUtils.java
  class JsonUtils (line 20) | @Deprecated(forRemoval = true, since = "2.23.0")
    method JsonUtils (line 24) | private JsonUtils() {
    method mapper (line 27) | public static ObjectMapper mapper() {
    method mapToObject (line 39) | @NonNull
    method objectToJson (line 50) | @NonNull
    method jsonToObject (line 68) | public static <T> T jsonToObject(String json, Class<T> toValueType) {
    method jsonToObject (line 84) | public static <T> T jsonToObject(String json, TypeReference<T> typeRef...
    method deepCopy (line 99) | @SuppressWarnings("unchecked")

FILE: api/src/main/java/run/halo/app/infra/utils/PathUtils.java
  class PathUtils (line 15) | @Slf4j
    method isAbsoluteUri (line 39) | public static boolean isAbsoluteUri(final String uriString) {
    method combinePath (line 61) | public static String combinePath(String... pathSegments) {
    method appendPathSeparatorIfMissing (line 87) | public static String appendPathSeparatorIfMissing(String path) {
    method simplifyPathPattern (line 104) | public static String simplifyPathPattern(String pattern) {

FILE: api/src/main/java/run/halo/app/migration/Backup.java
  class Backup (line 11) | @Data
    class Spec (line 22) | @Data
    class Status (line 33) | @Data
    type Phase (line 58) | public enum Phase {

FILE: api/src/main/java/run/halo/app/migration/Constant.java
  type Constant (line 3) | public enum Constant {

FILE: api/src/main/java/run/halo/app/notification/NotificationCenter.java
  type NotificationCenter (line 13) | public interface NotificationCenter {
    method notify (line 20) | Mono<Void> notify(Reason reason);
    method subscribe (line 29) | Mono<Subscription> subscribe(Subscription.Subscriber subscriber,
    method unsubscribe (line 37) | Mono<Void> unsubscribe(Subscription.Subscriber subscriber);
    method unsubscribe (line 45) | Mono<Void> unsubscribe(Subscription.Subscriber subscriber, Subscriptio...

FILE: api/src/main/java/run/halo/app/notification/NotificationContext.java
  class NotificationContext (line 8) | @Data
    class Message (line 17) | @Data
    class Subject (line 28) | @Data
    class MessagePayload (line 38) | @Data

FILE: api/src/main/java/run/halo/app/notification/NotificationReasonEmitter.java
  type NotificationReasonEmitter (line 13) | public interface NotificationReasonEmitter {
    method emit (line 21) | Mono<Void> emit(String reasonType, Consumer<ReasonPayload.ReasonPayloa...

FILE: api/src/main/java/run/halo/app/notification/ReactiveNotifier.java
  type ReactiveNotifier (line 12) | public interface ReactiveNotifier extends ExtensionPoint {
    method notify (line 19) | Mono<Void> notify(NotificationContext context);

FILE: api/src/main/java/run/halo/app/notification/ReasonAttributes.java
  class ReasonAttributes (line 11) | public class ReasonAttributes extends HashMap<String, Object> {

FILE: api/src/main/java/run/halo/app/notification/ReasonPayload.java
  class ReasonPayload (line 16) | @Data
    method builder (line 23) | public static ReasonPayloadBuilder builder() {
    class ReasonPayloadBuilder (line 27) | public static class ReasonPayloadBuilder {
      method ReasonPayloadBuilder (line 32) | ReasonPayloadBuilder() {
      method subject (line 36) | public ReasonPayloadBuilder subject(Reason.Subject subject) {
      method attribute (line 41) | public ReasonPayloadBuilder attribute(String key, Object value) {
      method attributes (line 46) | public ReasonPayloadBuilder attributes(Map<String, Object> attribute...
      method author (line 51) | public ReasonPayloadBuilder author(UserIdentity author) {
      method build (line 56) | public ReasonPayload build() {

FILE: api/src/main/java/run/halo/app/notification/UserIdentity.java
  method of (line 23) | public static UserIdentity of(String username) {
  method anonymousWithEmail (line 35) | public static UserIdentity anonymousWithEmail(String email) {
  method isAnonymous (line 41) | public boolean isAnonymous() {
  method getEmail (line 50) | public Optional<String> getEmail() {

FILE: api/src/main/java/run/halo/app/plugin/BasePlugin.java
  class BasePlugin (line 14) | @Getter
    method BasePlugin (line 25) | public BasePlugin(PluginContext pluginContext) {
    method BasePlugin (line 29) | public BasePlugin() {

FILE: api/src/main/java/run/halo/app/plugin/PluginConfigUpdatedEvent.java
  class PluginConfigUpdatedEvent (line 20) | @Getter
    method PluginConfigUpdatedEvent (line 49) | @Builder

FILE: api/src/main/java/run/halo/app/plugin/PluginContext.java
  class PluginContext (line 20) | @Getter

FILE: api/src/main/java/run/halo/app/plugin/PluginsRootGetter.java
  type PluginsRootGetter (line 12) | public interface PluginsRootGetter extends Supplier<Path> {

FILE: api/src/main/java/run/halo/app/plugin/ReactiveSettingFetcher.java
  type ReactiveSettingFetcher (line 13) | public interface ReactiveSettingFetcher {
    method fetch (line 15) | <T> Mono<T> fetch(String group, Class<T> clazz);
    method get (line 17) | @Deprecated(forRemoval = true, since = "2.23.0")
    method getSettingValue (line 26) | Mono<JsonNode> getSettingValue(String group);
    method getValues (line 28) | @Deprecated(forRemoval = true, since = "2.23.0")
    method getSettingValues (line 36) | Mono<Map<String, JsonNode>> getSettingValues();

FILE: api/src/main/java/run/halo/app/plugin/SettingFetcher.java
  type SettingFetcher (line 13) | public interface SettingFetcher {
    method fetch (line 15) | <T> Optional<T> fetch(String group, Class<T> clazz);
    method get (line 24) | @Deprecated(forRemoval = true, since = "2.23.0")
    method getSettingValue (line 33) | JsonNode getSettingValue(String group);
    method getValues (line 41) | @Deprecated(forRemoval = true, since = "2.23.0")
    method getSettingValues (line 49) | Map<String, JsonNode> getSettingValues();

FILE: api/src/main/java/run/halo/app/plugin/event/PluginStartedEvent.java
  class PluginStartedEvent (line 11) | public class PluginStartedEvent extends ApplicationEvent {
    method PluginStartedEvent (line 13) | public PluginStartedEvent(Object source) {

FILE: api/src/main/java/run/halo/app/plugin/extensionpoint/ExtensionGetter.java
  type ExtensionGetter (line 8) | public interface ExtensionGetter {
    method getEnabledExtension (line 17) | <T extends ExtensionPoint> Mono<T> getEnabledExtension(Class<T> extens...
    method getEnabledExtensions (line 28) | <T extends ExtensionPoint> Flux<T> getEnabledExtensions(Class<T> exten...
    method getExtensions (line 37) | <T extends ExtensionPoint> Flux<T> getExtensions(Class<T> extensionPoi...
    method getExtensionList (line 46) | <T extends ExtensionPoint> List<T> getExtensionList(Class<T> extension...

FILE: api/src/main/java/run/halo/app/search/HaloDocument.java
  class HaloDocument (line 13) | @Data

FILE: api/src/main/java/run/halo/app/search/HaloDocumentsProvider.java
  type HaloDocumentsProvider (line 11) | public interface HaloDocumentsProvider extends ExtensionPoint {
    method fetchAll (line 18) | Flux<HaloDocument> fetchAll();
    method getType (line 25) | String getType();

FILE: api/src/main/java/run/halo/app/search/SearchEngine.java
  type SearchEngine (line 11) | public interface SearchEngine extends ExtensionPoint {
    method available (line 18) | boolean available();
    method addOrUpdate (line 25) | void addOrUpdate(Iterable<HaloDocument> haloDocuments);
    method deleteDocument (line 32) | void deleteDocument(Iterable<String> haloDocIds);
    method deleteAll (line 37) | void deleteAll();
    method search (line 45) | SearchResult search(SearchOption option);

FILE: api/src/main/java/run/halo/app/search/SearchOption.java
  class SearchOption (line 15) | @Data

FILE: api/src/main/java/run/halo/app/search/SearchResult.java
  class SearchResult (line 6) | @Data

FILE: api/src/main/java/run/halo/app/search/SearchService.java
  type SearchService (line 11) | public interface SearchService {
    method search (line 19) | Mono<SearchResult> search(SearchOption option);

FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentAddRequestEvent.java
  class HaloDocumentAddRequestEvent (line 7) | @SharedEvent
    method HaloDocumentAddRequestEvent (line 12) | public HaloDocumentAddRequestEvent(Object source, Iterable<HaloDocumen...
    method getDocuments (line 17) | public Iterable<HaloDocument> getDocuments() {

FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentDeleteRequestEvent.java
  class HaloDocumentDeleteRequestEvent (line 7) | @SharedEvent
    method HaloDocumentDeleteRequestEvent (line 18) | public HaloDocumentDeleteRequestEvent(Object source, @Nullable Iterabl...
    method getDocIds (line 23) | public Iterable<String> getDocIds() {

FILE: api/src/main/java/run/halo/app/search/event/HaloDocumentRebuildRequestEvent.java
  class HaloDocumentRebuildRequestEvent (line 6) | @SharedEvent
    method HaloDocumentRebuildRequestEvent (line 9) | public HaloDocumentRebuildRequestEvent(Object source) {

FILE: api/src/main/java/run/halo/app/security/AdditionalWebFilter.java
  type AdditionalWebFilter (line 15) | public interface AdditionalWebFilter extends WebFilter, ExtensionPoint, ...
    method getOrder (line 22) | default int getOrder() {

FILE: api/src/main/java/run/halo/app/security/AfterSecurityWebFilter.java
  type AfterSecurityWebFilter (line 12) | public interface AfterSecurityWebFilter extends WebFilter, ExtensionPoint {

FILE: api/src/main/java/run/halo/app/security/AnonymousAuthenticationSecurityWebFilter.java
  type AnonymousAuthenticationSecurityWebFilter (line 11) | public interface AnonymousAuthenticationSecurityWebFilter extends WebFil...

FILE: api/src/main/java/run/halo/app/security/AuthenticationSecurityWebFilter.java
  type AuthenticationSecurityWebFilter (line 11) | public interface AuthenticationSecurityWebFilter extends WebFilter, Exte...

FILE: api/src/main/java/run/halo/app/security/BeforeSecurityWebFilter.java
  type BeforeSecurityWebFilter (line 12) | public interface BeforeSecurityWebFilter extends WebFilter, ExtensionPoi...

FILE: api/src/main/java/run/halo/app/security/FormLoginSecurityWebFilter.java
  type FormLoginSecurityWebFilter (line 11) | public interface FormLoginSecurityWebFilter extends WebFilter, Extension...

FILE: api/src/main/java/run/halo/app/security/HttpBasicSecurityWebFilter.java
  type HttpBasicSecurityWebFilter (line 12) | public interface HttpBasicSecurityWebFilter extends WebFilter, Extension...

FILE: api/src/main/java/run/halo/app/security/LoginHandlerEnhancer.java
  type LoginHandlerEnhancer (line 17) | public interface LoginHandlerEnhancer {
    method onLoginSuccess (line 25) | Mono<Void> onLoginSuccess(ServerWebExchange exchange, Authentication s...
    method onLoginFailure (line 33) | Mono<Void> onLoginFailure(ServerWebExchange exchange, AuthenticationEx...

FILE: api/src/main/java/run/halo/app/security/OAuth2AuthorizationCodeSecurityWebFilter.java
  type OAuth2AuthorizationCodeSecurityWebFilter (line 12) | public interface OAuth2AuthorizationCodeSecurityWebFilter extends WebFil...

FILE: api/src/main/java/run/halo/app/security/PersonalAccessToken.java
  class PersonalAccessToken (line 14) | @Data
    class Spec (line 27) | @Data

FILE: api/src/main/java/run/halo/app/security/authentication/CryptoService.java
  type CryptoService (line 6) | public interface CryptoService {
    method decrypt (line 14) | Mono<byte[]> decrypt(byte[] encryptedMessage);
    method readPublicKey (line 21) | Mono<byte[]> readPublicKey();
    method getKeyId (line 28) | String getKeyId();
    method getJwk (line 35) | JWK getJwk();

FILE: api/src/main/java/run/halo/app/security/authentication/login/UsernamePasswordAuthenticationManager.java
  type UsernamePasswordAuthenticationManager (line 15) | public interface UsernamePasswordAuthenticationManager

FILE: api/src/main/java/run/halo/app/security/authentication/oauth2/HaloOAuth2AuthenticationToken.java
  class HaloOAuth2AuthenticationToken (line 20) | public class HaloOAuth2AuthenticationToken extends AbstractAuthenticatio...
    method HaloOAuth2AuthenticationToken (line 35) | public HaloOAuth2AuthenticationToken(UserDetails userDetails,
    method getName (line 43) | @Override
    method getAuthorities (line 48) | @Override
    method getCredentials (line 60) | @Override
    method getPrincipal (line 65) | @Override
    method authenticated (line 78) | public static HaloOAuth2AuthenticationToken authenticated(
    method combineAuthorities (line 84) | private static Collection<? extends GrantedAuthority> combineAuthorities(

FILE: api/src/main/java/run/halo/app/security/device/DeviceService.java
  type DeviceService (line 7) | public interface DeviceService {
    method loginSuccess (line 9) | Mono<Void> loginSuccess(ServerWebExchange exchange, Authentication suc...
    method changeSessionId (line 11) | Mono<Void> changeSessionId(ServerWebExchange exchange);
    method revoke (line 13) | Mono<Void> revoke(String principalName, String deviceId);
    method revoke (line 15) | Mono<Void> revoke(String username);

FILE: api/src/main/java/run/halo/app/theme/Constant.java
  type Constant (line 8) | public enum Constant {

FILE: api/src/main/java/run/halo/app/theme/ReactivePostContentHandler.java
  type ReactivePostContentHandler (line 20) | public interface ReactivePostContentHandler extends ExtensionPoint {
    method handle (line 30) | Mono<PostContentContext> handle(@NonNull PostContentContext postContent);
    class PostContentContext (line 32) | @Data

FILE: api/src/main/java/run/halo/app/theme/ReactiveSinglePageContentHandler.java
  type ReactiveSinglePageContentHandler (line 18) | public interface ReactiveSinglePageContentHandler extends ExtensionPoint {
    method handle (line 28) | Mono<SinglePageContentContext> handle(@NonNull SinglePageContentContex...
    class SinglePageContentContext (line 30) | @Data

FILE: api/src/main/java/run/halo/app/theme/TemplateNameResolver.java
  type TemplateNameResolver (line 15) | public interface TemplateNameResolver {
    method resolveTemplateNameOrDefault (line 24) | Mono<String> resolveTemplateNameOrDefault(ServerWebExchange exchange, ...
    method resolveTemplateNameOrDefault (line 34) | Mono<String> resolveTemplateNameOrDefault(ServerWebExchange exchange, ...
    method isTemplateAvailableInTheme (line 44) | Mono<Boolean> isTemplateAvailableInTheme(ServerWebExchange exchange, S...

FILE: api/src/main/java/run/halo/app/theme/dialect/CommentWidget.java
  type CommentWidget (line 14) | public interface CommentWidget extends ExtensionPoint {
    method render (line 18) | void render(ITemplateContext context, IProcessableElementTag tag,

FILE: api/src/main/java/run/halo/app/theme/dialect/ElementTagPostProcessor.java
  type ElementTagPostProcessor (line 14) | public interface ElementTagPostProcessor extends ExtensionPoint {
    method process (line 36) | Mono<IProcessableElementTag> process(

FILE: api/src/main/java/run/halo/app/theme/dialect/TemplateFooterProcessor.java
  type TemplateFooterProcessor (line 16) | public interface TemplateFooterProcessor extends ExtensionPoint {
    method process (line 18) | Mono<Void> process(ITemplateContext context, IProcessableElementTag tag,

FILE: api/src/main/java/run/halo/app/theme/dialect/TemplateHeadProcessor.java
  type TemplateHeadProcessor (line 18) | @FunctionalInterface
    method process (line 21) | Mono<Void> process(ITemplateContext context, IModel model,

FILE: api/src/main/java/run/halo/app/theme/finders/vo/ExtensionVoOperator.java
  type ExtensionVoOperator (line 12) | public interface ExtensionVoOperator {
    method getMetadata (line 14) | @NonNull

FILE: api/src/main/java/run/halo/app/theme/router/ModelConst.java
  type ModelConst (line 9) | public enum ModelConst {

FILE: api/src/main/java/run/halo/app/theme/router/PageUrlUtils.java
  class PageUrlUtils (line 17) | public class PageUrlUtils {
    method pageNum (line 20) | public static int pageNum(ServerRequest request) {
    method isPageUrl (line 28) | public static boolean isPageUrl(String path) {
    method totalPage (line 37) | public static long totalPage(ListResult<?> list) {
    method nextPageUrl (line 47) | public static String nextPageUrl(String path, long total) {
    method prevPageUrl (line 69) | public static String prevPageUrl(String path) {
    method appendPagePart (line 90) | private static String appendPagePart(String path, long page) {
    method toNextPage (line 94) | private static String toNextPage(String pageStr, long total) {
    method toPrevPage (line 99) | private static int toPrevPage(String pageStr) {
    method parseInt (line 103) | private static int parseInt(String pageStr) {

FILE: api/src/main/java/run/halo/app/theme/router/UrlContextListResult.java
  class UrlContextListResult (line 15) | @Getter
    method UrlContextListResult (line 21) | public UrlContextListResult(int page, int size, long total, List<T> it...
    class Builder (line 28) | public static class Builder<T> {
      method page (line 36) | public Builder<T> page(int page) {
      method size (line 41) | public Builder<T> size(int size) {
      method total (line 46) | public Builder<T> total(long total) {
      method items (line 51) | public Builder<T> items(List<T> items) {
      method nextUrl (line 56) | public Builder<T> nextUrl(String nextUrl) {
      method prevUrl (line 61) | public Builder<T> prevUrl(String prevUrl) {
      method listResult (line 72) | public Builder<T> listResult(ListResult<T> listResult) {
      method build (line 80) | public UrlContextListResult<T> build() {

FILE: api/src/test/java/run/halo/app/core/extension/content/PostTest.java
  class PostTest (line 14) | class PostTest {
    method isRecycledTest (line 16) | @ParameterizedTest
    method isRecycledProvider (line 22) | static Stream<Arguments> isRecycledProvider() {

FILE: api/src/test/java/run/halo/app/core/extension/notification/SubscriptionTest.java
  class SubscriptionTest (line 14) | class SubscriptionTest {
    method reasonSubjectToStringTest (line 16) | @Test

FILE: api/src/test/java/run/halo/app/extension/ExtensionUtilTest.java
  class ExtensionUtilTest (line 16) | class ExtensionUtilTest {
    method testIsNotDeleted (line 18) | @Test
    method addFinalizers (line 34) | @Test
    method removeFinalizers (line 49) | @Test
    method hasDoNotOverwriteLabelTests (line 60) | @Test

FILE: api/src/test/java/run/halo/app/extension/FakeExtension.java
  class FakeExtension (line 3) | @GVK(group = "fake.halo.run",
    method createFake (line 10) | public static FakeExtension createFake(String name) {

FILE: api/src/test/java/run/halo/app/extension/ListOptionsTest.java
  class ListOptionsTest (line 15) | class ListOptionsTest {
    class ListOptionsBuilderTest (line 17) | @Nested
      method shouldBuildWithFieldAndLabelSelectors (line 20) | @Test
      method shouldBuildLabelSelectorOnly (line 39) | @Test
      method shouldBuildFieldSelectorOnly (line 51) | @Test

FILE: api/src/test/java/run/halo/app/extension/PageRequestImplTest.java
  class PageRequestImplTest (line 9) | class PageRequestImplTest {
    method shouldBeCompatibleZeroAndNegativePageNumber (line 11) | @ParameterizedTest
    method shouldBeCompatibleNegativePageSize (line 21) | @ParameterizedTest

FILE: api/src/test/java/run/halo/app/extension/SecretTest.java
  class SecretTest (line 19) | class SecretTest {
    method serialize (line 21) | @Test
    method deserialize (line 32) | @Test
    method deserializeWithUnstructured (line 42) | @Test
    method deserializeYamlWithStringData (line 50) | @Test
    method testJsonString (line 69) | private String testJsonString() {

FILE: api/src/test/java/run/halo/app/extension/controller/ControllerBuilderTest.java
  class ControllerBuilderTest (line 15) | @ExtendWith(MockitoExtension.class)
    method buildWithNullReconciler (line 21) | @Test
    method buildWithNullClient (line 27) | @Test
    method buildTest (line 33) | @Test
    method invalidMinDelayAndMaxDelay (line 60) | @Test
    method fakeBuilder (line 88) | ControllerBuilder fakeBuilder() {
    class FakeReconciler (line 93) | static class FakeReconciler implements Reconciler<Reconciler.Request> {
      method reconcile (line 95) | @Override
      method setupWith (line 100) | @Override

FILE: api/src/test/java/run/halo/app/extension/controller/DefaultControllerTest.java
  class DefaultControllerTest (line 31) | @ExtendWith(MockitoExtension.class)
    method setUp (line 54) | @BeforeEach
    method createController (line 62) | DefaultController<Request> createController(int workerCount) {
    method shouldReturnRightName (line 67) | @Test
    class WorkerTest (line 72) | @Nested
      method shouldCreateCorrectName (line 75) | @Test
      method shouldRunCorrectlyIfReconcilerReturnsNoReEnqueue (line 85) | @Test
      method shouldRunCorrectlyIfReconcilerReturnsReEnqueue (line 102) | @Test
      method shouldReRunIfReconcilerThrowException (line 122) | @Test
      method canReRunIfReconcilerThrowRequeueException (line 142) | @Test
      method doNotReRunIfReconcilerThrowsRequeueExceptionWithoutRequeue (line 163) | @Test
      method shouldSetMinRetryAfterWhenTakeZeroDelayedEntry (line 183) | @Test
      method shouldSetMaxRetryAfterWhenTakeGreaterThanMaxRetryAfterDelayedEntry (line 203) | @Test
    method shouldDisposeCorrectlyIfShutdownInTime (line 226) | @Test
    method shouldDisposeCorrectlyIfNotShutdownInTime (line 242) | @Test
    method shouldDisposeCorrectlyEvenIfTimeoutAwaitTermination (line 260) | @Test
    method shouldStartCorrectly (line 278) | @Test
    method shouldNotStartWhenDisposed (line 297) | @Test
    method shouldCreateMultiWorkers (line 308) | @Test
    method shouldFailToCreateControllerDueToInvalidWorkerCount (line 315) | @Test

FILE: api/src/test/java/run/halo/app/extension/controller/DefaultDelayQueueTest.java
  class DefaultDelayQueueTest (line 16) | class DefaultDelayQueueTest {
    method setUp (line 24) | @BeforeEach
    method addImmediatelyTest (line 29) | @Test
    method addWithDelaySmallerThanMinDelay (line 42) | @Test
    method addWithDelayGreaterThanMinDelay (line 55) | @Test
    method shouldNotAddAfterDisposing (line 69) | @Test
    method shouldNotAddRepeatedlyIfNotDone (line 80) | @Test
    method shouldNotAddIfHavingEarlierEntryInQueue (line 101) | @Test
    method shouldAddIfHavingLaterEntryInQueue (line 117) | @Test
    method newRequest (line 133) | Request newRequest(String name) {

FILE: api/src/test/java/run/halo/app/extension/controller/DelayedEntryTest.java
  class DelayedEntryTest (line 12) | class DelayedEntryTest {
    method createDelayedEntry (line 16) | @Test
    method compareWithGreaterDelay (line 29) | @Test
    method compareWithSameDelay (line 37) | @Test
    method compareWithLessDelay (line 45) | @Test
    method shouldBeEqualWithNameOnly (line 53) | @Test

FILE: api/src/test/java/run/halo/app/extension/controller/ExtensionWatcherTest.java
  class ExtensionWatcherTest (line 23) | @ExtendWith(MockitoExtension.class)
    method getEmptyMatcher (line 38) | private DefaultExtensionMatcher getEmptyMatcher() {
    method shouldAddExtensionWhenAddPredicateAlwaysTrue (line 44) | @Test
    method shouldNotAddExtensionWhenAddPredicateAlwaysFalse (line 55) | @Test
    method shouldNotAddExtensionWhenWatcherIsDisposed (line 67) | @Test
    method shouldUpdateExtensionWhenUpdatePredicateAlwaysTrue (line 77) | @Test
    method shouldUpdateExtensionWhenUpdatePredicateAlwaysFalse (line 88) | @Test
    method shouldNotUpdateExtensionWhenWatcherIsDisposed (line 100) | @Test
    method shouldDeleteExtensionWhenDeletePredicateAlwaysTrue (line 110) | @Test
    method shouldDeleteExtensionWhenDeletePredicateAlwaysFalse (line 121) | @Test
    method shouldNotDeleteExtensionWhenWatcherIsDisposed (line 133) | @Test
    method shouldInvokeDisposeHookIfRegistered (line 143) | @Test

FILE: api/src/test/java/run/halo/app/extension/controller/RequestSynchronizerTest.java
  class RequestSynchronizerTest (line 25) | @ExtendWith(MockitoExtension.class)
    method setUp (line 36) | @BeforeEach
    method shouldStartCorrectlyWhenSyncingAllOnStart (line 44) | @Test
    method shouldStartCorrectlyWhenNotSyncingAllOnStart (line 58) | @Test
    method shouldDisposeCorrectly (line 75) | @Test
    method shouldNotStartAfterDisposing (line 88) | @Test

FILE: api/src/test/java/run/halo/app/extension/index/IndexAttributeFactoryTest.java
  class IndexAttributeFactoryTest (line 20) | class IndexAttributeFactoryTest {
    method shouldCreateMultiValueAttribute (line 22) | @Test
    method shouldCreateSingleValueAttribute (line 38) | @Test
    class FakeExtension (line 54) | @Data

FILE: api/src/test/java/run/halo/app/extension/index/IndexSpecTest.java
  class IndexSpecTest (line 22) | class IndexSpecTest {
    method equalsVerifier (line 24) | @Test
    method equalAnotherObject (line 68) | @Test
    method shouldNormalizeToSingleValueIndexSpec (line 75) | @Test
    method shouldNormalizeToMultiValueIndexSpec (line 93) | @Test
    class FakeExtension (line 110) | @Data

FILE: api/src/test/java/run/halo/app/extension/index/KeyComparatorTest.java
  class KeyComparatorTest (line 20) | class KeyComparatorTest {
    method keyComparator (line 23) | @Test
    method keyComparator2 (line 40) | @Test
    method complexStringTest (line 84) | @Test
    method complexButSkewedStringTest (line 115) | @Test
    method mixLetterCaseStringTest (line 150) | @Test
    method mixLetterCaseAndNumberTest (line 163) | @Test
    method sortingWithComplexStringsTest (line 219) | @Test
    method sortingWithDecimalStringsTest (line 226) | @Test
    method treeSetWithComparatorTest (line 235) | @Test
    method testTreeMap_WithComparator (line 246) | @Test
    method integerPartDifferentTest (line 257) | @Test
    method integerPartDifferentWithDecimalTest (line 268) | @Test
    class ComparatorCharacteristicTest (line 296) | @Nested
      method reflexiveTest (line 298) | @Test
      method symmetricTest (line 307) | @Test
      method transitiveTest (line 317) | @Test
      method consistencyTest (line 325) | @RepeatedTest(50)
      method withNumbersTest (line 334) | @Test
      method mixedContentTest (line 342) | @Test
      method nullHandlingTest (line 350) | @Test
      method lengthDifferenceTest (line 358) | @Test
      method specialCharactersTest (line 365) | @Test
      method emptyStringsTest (line 373) | @Test
    class ComparatorEdgeTest (line 382) | @Nested
      method pureNumbersTest (line 384) | @Test
      method mumbersWithOverflowTest (line 400) | @Test
      method decimalStringsTest (line 433) | @Test
      method lettersAndNumbersTest (line 443) | @Test
      method pureLettersTest (line 451) | @Test
      method dateStringsTest (line 460) | @Test
      method booleanStringsTest (line 489) | @Test
      method complexMixedStringsTest (line 497) | @Test

FILE: api/src/test/java/run/halo/app/extension/index/MultiValueBuilderTest.java
  class MultiValueBuilderTest (line 14) | class MultiValueBuilderTest {
    method throwIfNoNameProvided (line 16) | @Test
    method throwIfNoKeyTypeProvided (line 23) | @Test
    method throwIfNoIndexFuncProvided (line 30) | @Test
    method shouldBuildCorrectly (line 36) | @Test

FILE: api/src/test/java/run/halo/app/extension/index/SingleValueBuilderTest.java
  class SingleValueBuilderTest (line 13) | class SingleValueBuilderTest {
    method throwIfNoNameProvided (line 15) | @Test
    method throwIfNoKeyTypeProvided (line 22) | @Test
    method throwIfNoIndexFuncProvided (line 29) | @Test
    method shouldBuildCorrectly (line 35) | @Test

FILE: api/src/test/java/run/halo/app/extension/index/UnknownKeyTest.java
  class UnknownKeyTest (line 10) | class UnknownKeyTest {
    method shouldEqualsWorkCorrectly (line 12) | @ParameterizedTest
    method shouldCompareCorrectly (line 28) | @ParameterizedTest

FILE: api/src/test/java/run/halo/app/extension/index/query/QueriesTest.java
  class QueriesTest (line 8) | class QueriesTest {
    method shouldBuildAndConditionStaticMethod (line 10) | @Test
    method shouldBuildOrConditionStaticMethod (line 19) | @Test
    method shouldBuildNotConditionStaticMethod (line 28) | @Test
    method shouldBuildBetweenCondition (line 34) | @Test
    method shouldBuildEqualCondition (line 40) | @Test
    method shouldBuildInCondition (line 46) | @Test
    method shouldRefineInConditionWithSingleValueToEqualCondition (line 55) | @Test
    method shouldBuildGreaterThanCondition (line 61) | @Test
    method shouldBuildLessThanCondition (line 67) | @Test
    method shouldBuildLessThanConditionExclusive (line 73) | @Test
    method shouldBuildEmptyCondition (line 79) | @Test
    method shouldBuildAllCondition (line 85) | @Test
    method shouldBuildNotEqualCondition (line 91) | @Test
    method shouldBuildNotBetweenCondition (line 97) | @Test
    method shouldBuildNotInCondition (line 103) | @Test
    method shouldBuildNotAllCondition (line 109) | @Test
    method shouldBuildStartsWithCondition (line 115) | @Test
    method shouldBuildNotStartsWithCondition (line 121) | @Test
    method shouldBuildEndsWithCondition (line 127) | @Test
    method shouldBuildNotEndsWithCondition (line 133) | @Test
    method shouldBuildContainsCondition (line 139) | @Test
    method shouldBuildNotContainsCondition (line 145) | @Test
    method shouldBuildAndCondition (line 151) | @Test
    method shouldBuildOrCondition (line 158) | @Test
    method shouldBuildNotCondition (line 166) | @Test
    method shouldBuildLabelExistsCondition (line 172) | @Test
    method shouldBuildLabelNotExistsCondition (line 178) | @Test
    method shouldBuildLabelEqualCondition (line 184) | @Test
    method shouldBuildLabelNotEqualCondition (line 190) | @Test
    method shouldBuildLabelInCondition (line 196) | @Test
    method shouldBuildLabelNotInCondition (line 202) | @Test
    method shouldBuildChainedConditions (line 208) | @Test
    method shouldBuildComplexCondition (line 218) | @Test

FILE: api/src/test/java/run/halo/app/extension/indexer/DefaultIndexEngineTest.java
  class DefaultIndexEngineTest (line 9) | class DefaultIndexEngineTest {
    method priorityQueueTest (line 11) | @Test

FILE: api/src/test/java/run/halo/app/extension/indexer/LabelIndexImplTest.java
  class LabelIndexImplTest (line 6) | class LabelIndexImplTest {
    method stringPrefixTest (line 8) | @Test

FILE: api/src/test/java/run/halo/app/extension/router/selector/LabelSelectorTest.java
  class LabelSelectorTest (line 13) | class LabelSelectorTest {
    method builderTest (line 15) | @Test

FILE: api/src/test/java/run/halo/app/extension/router/selector/OperatorTest.java
  class OperatorTest (line 15) | @Slf4j
    method shouldConvertCorrectly (line 18) | @Test

FILE: api/src/test/java/run/halo/app/extension/router/selector/SelectorConverterTest.java
  class SelectorConverterTest (line 11) | @Slf4j
    method shouldConvertCorrectly (line 16) | @Test

FILE: api/src/test/java/run/halo/app/infra/utils/GenericClassUtilsTest.java
  class GenericClassUtilsTest (line 9) | class GenericClassUtilsTest {
    method generateConcreteClass (line 11) | @Test

FILE: api/src/test/java/run/halo/app/infra/utils/JsonUtilsTest.java
  class JsonUtilsTest (line 16) | public class JsonUtilsTest {
    method serializerTime (line 18) | @Test
    method deserializerArrayString (line 28) | @Test

FILE: api/src/test/java/run/halo/app/infra/utils/PathUtilsTest.java
  class PathUtilsTest (line 15) | class PathUtilsTest {
    method combinePath (line 17) | @Test
    method getCombinePathCases (line 29) | private Map<String, String> getCombinePathCases() {
    method appendPathSeparatorIfMissing (line 38) | @Test
    method simplifyPathPattern (line 50) | @Test
    method isAbsoluteUri (line 63) | @Test

FILE: application/src/main/java/run/halo/app/Application.java
  class Application (line 18) | @EnableScheduling
    method main (line 24) | public static void main(String[] args) {

FILE: application/src/main/java/run/halo/app/content/AbstractContentService.java
  class AbstractContentService (line 33) | @Slf4j
    method getContent (line 39) | public Mono<ContentWrapper> getContent(String snapshotName, String bas...
    method checkBaseSnapshot (line 61) | protected void checkBaseSnapshot(Snapshot snapshot) {
    method draftContent (line 70) | protected Mono<ContentWrapper> draftContent(@Nullable String baseSnaps...
    method draftContent (line 81) | protected Mono<ContentWrapper> draftContent(String baseSnapshotName, C...
    method create (line 85) | private Mono<Snapshot> create(@Nullable String baseSnapshotName,
    method updateContent (line 108) | protected Mono<ContentWrapper> updateContent(String baseSnapshotName,
    method listSnapshotsBy (line 139) | protected Flux<Snapshot> listSnapshotsBy(Ref ref) {
    method hasConflict (line 148) | boolean hasConflict(Long oldVersion, Long newVersion) {
    method restoredContent (line 152) | protected Mono<ContentWrapper> restoredContent(String baseSnapshotName...
    method determineRawAndContentPatch (line 158) | protected Snapshot determineRawAndContentPatch(Snapshot snapshotToUse,
    method getContextUsername (line 186) | protected Mono<String> getContextUsername() {

FILE: application/src/main/java/run/halo/app/content/AbstractEventReconciler.java
  class AbstractEventReconciler (line 20) | public abstract class AbstractEventReconciler<E> implements Reconciler<E...
    method AbstractEventReconciler (line 29) | protected AbstractEventReconciler(String controllerName) {
    method setupWith (line 35) | @Override
    method start (line 47) | @Override
    method stop (line 53) | @Override
    method isRunning (line 59) | @Override
    method getPhase (line 64) | @Override

FILE: application/src/main/java/run/halo/app/content/CategoryPostCountUpdater.java
  class CategoryPostCountUpdater (line 35) | @Component
    method CategoryPostCountUpdater (line 42) | public CategoryPostCountUpdater(ExtensionClient client) {
    method reconcile (line 48) | @Override
    class CategoryPostCountService (line 68) | static class CategoryPostCountService {
      method CategoryPostCountService (line 72) | public CategoryPostCountService(ExtensionClient client) {
      method recalculatePostCount (line 76) | public void recalculatePostCount(Collection<String> categoryNames) {
      method recalculatePostCount (line 82) | public void recalculatePostCount(String categoryName) {
      method countTotalPosts (line 93) | private int countTotalPosts(String categoryName) {
      method countVisiblePosts (line 102) | private int countVisiblePosts(String categoryName) {
      method basePostQuery (line 115) | private static Condition basePostQuery(String categoryName) {
    method onPostUpdated (line 125) | @EventListener(PostUpdatedEvent.class)
    method onPostDeleted (line 132) | @EventListener(PostDeletedEvent.class)
    method calcCategoriesToUpdate (line 140) | private Set<String> calcCategoriesToUpdate(String postName) {

FILE: application/src/main/java/run/halo/app/content/CategoryService.java
  type CategoryService (line 8) | public interface CategoryService {
    method listChildren (line 10) | Flux<Category> listChildren(@NonNull String categoryName);
    method getParentByName (line 12) | Mono<Category> getParentByName(@NonNull String categoryName);
    method isCategoryHidden (line 14) | Mono<Boolean> isCategoryHidden(@NonNull String categoryName);

FILE: application/src/main/java/run/halo/app/content/ContentRequest.java
  method toSnapshot (line 26) | public Snapshot toSnapshot() {
  method rawPatchFrom (line 44) | public String rawPatchFrom(String originalRaw) {
  method contentPatchFrom (line 49) | public String contentPatchFrom(String originalContent) {

FILE: application/src/main/java/run/halo/app/content/ContentUpdateParam.java
  method from (line 11) | public static ContentUpdateParam from(Content content) {

FILE: application/src/main/java/run/halo/app/content/Contributor.java
  class Contributor (line 11) | @Data

FILE: application/src/main/java/run/halo/app/content/ListedPost.java
  class ListedPost (line 20) | @Data

FILE: application/src/main/java/run/halo/app/content/ListedSinglePage.java
  class ListedSinglePage (line 18) | @Data

FILE: application/src/main/java/run/halo/app/content/ListedSnapshotDto.java
  class ListedSnapshotDto (line 12) | @Data
    class Spec (line 21) | @Data
    method from (line 34) | public static ListedSnapshotDto from(Snapshot snapshot) {

FILE: application/src/main/java/run/halo/app/content/NotificationReasonConst.java
  type NotificationReasonConst (line 9) | public enum NotificationReasonConst {

FILE: application/src/main/java/run/halo/app/content/PostContentServiceImpl.java
  class PostContentServiceImpl (line 16) | @Component
    method PostContentServiceImpl (line 20) | public PostContentServiceImpl(ReactiveExtensionClient client) {
    method getHeadContent (line 25) | @Override
    method getReleaseContent (line 34) | @Override
    method getSpecifiedContent (line 43) | @Override
    method listSnapshots (line 52) | @Override

FILE: application/src/main/java/run/halo/app/content/PostHideFromListStateUpdater.java
  class PostHideFromListStateUpdater (line 23) | @Component
    method PostHideFromListStateUpdater (line 30) | protected PostHideFromListStateUpdater(ReactiveExtensionClient client,
    method reconcile (line 37) | @Override
    method onApplicationEvent (line 54) | @EventListener(CategoryHiddenStateChangeEvent.class)

FILE: application/src/main/java/run/halo/app/content/PostQuery.java
  class PostQuery (line 28) | public class PostQuery extends SortableRequest {
    method PostQuery (line 32) | public PostQuery(ServerRequest request) {
    method PostQuery (line 36) | public PostQuery(ServerRequest request, @Nullable String username) {
    method getPublishPhase (line 41) | @Nullable
    method getCategoryWithChildren (line 46) | @Nullable
    method getKeyword (line 52) | @Nullable
    method toListOptions (line 62) | @Override
    method buildParameters (line 97) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/content/PostRequest.java
  method contentRequest (line 19) | public ContentRequest contentRequest() {

FILE: application/src/main/java/run/halo/app/content/PostService.java
  type PostService (line 17) | public interface PostService {
    method listPost (line 19) | Mono<ListResult<ListedPost>> listPost(PostQuery query);
    method draftPost (line 21) | Mono<Post> draftPost(PostRequest postRequest);
    method updatePost (line 23) | Mono<Post> updatePost(PostRequest postRequest);
    method updateBy (line 25) | Mono<Post> updateBy(@NonNull Post post);
    method getHeadContent (line 27) | Mono<ContentWrapper> getHeadContent(String postName);
    method getHeadContent (line 29) | Mono<ContentWrapper> getHeadContent(Post post);
    method getReleaseContent (line 31) | Mono<ContentWrapper> getReleaseContent(String postName);
    method getReleaseContent (line 33) | Mono<ContentWrapper> getReleaseContent(Post post);
    method getContent (line 35) | Mono<ContentWrapper> getContent(String snapshotName, String baseSnapsh...
    method listSnapshots (line 37) | Flux<ListedSnapshotDto> listSnapshots(String name);
    method publish (line 39) | Mono<Post> publish(Post post);
    method unpublish (line 41) | Mono<Post> unpublish(Post post);
    method getByUsername (line 50) | Mono<Post> getByUsername(String postName, String username);
    method revertToSpecifiedSnapshot (line 52) | Mono<Post> revertToSpecifiedSnapshot(String postName, String snapshotN...
    method deleteContent (line 54) | Mono<ContentWrapper> deleteContent(String postName, String snapshotName);
    method recycleBy (line 56) | Mono<Post> recycleBy(String postName, String username);
    method listCategories (line 58) | Flux<Category> listCategories(List<String> categories);

FILE: application/src/main/java/run/halo/app/content/PostSorter.java
  type PostSorter (line 16) | public enum PostSorter {
    method from (line 29) | public static Comparator<Post> from(PostSorter sorter, Boolean ascendi...
    method from (line 42) | public static Comparator<Post> from(PostSorter sorter) {
    method convertFrom (line 63) | static PostSorter convertFrom(String sort) {
    method defaultComparator (line 72) | static Comparator<Post> defaultComparator() {

FILE: application/src/main/java/run/halo/app/content/SinglePageQuery.java
  class SinglePageQuery (line 30) | public class SinglePageQuery extends SortableRequest {
    method SinglePageQuery (line 32) | public SinglePageQuery(ServerRequest request) {
    method toListOptions (line 36) | @Override
    method getSort (line 76) | @Override
    method buildParameters (line 93) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/content/SinglePageRequest.java
  method contentRequest (line 18) | public ContentRequest contentRequest() {

FILE: application/src/main/java/run/halo/app/content/SinglePageService.java
  type SinglePageService (line 14) | public interface SinglePageService {
    method getHeadContent (line 16) | Mono<ContentWrapper> getHeadContent(String singlePageName);
    method getReleaseContent (line 18) | Mono<ContentWrapper> getReleaseContent(String singlePageName);
    method getContent (line 20) | Mono<ContentWrapper> getContent(String snapshotName, String baseSnapsh...
    method listSnapshots (line 22) | Flux<ListedSnapshotDto> listSnapshots(String pageName);
    method list (line 24) | Mono<ListResult<ListedSinglePage>> list(SinglePageQuery listRequest);
    method draft (line 26) | Mono<SinglePage> draft(SinglePageRequest pageRequest);
    method update (line 28) | Mono<SinglePage> update(SinglePageRequest pageRequest);
    method revertToSpecifiedSnapshot (line 30) | Mono<SinglePage> revertToSpecifiedSnapshot(String pageName, String sna...
    method deleteContent (line 32) | Mono<ContentWrapper> deleteContent(String postName, String snapshotName);

FILE: application/src/main/java/run/halo/app/content/SnapshotService.java
  type SnapshotService (line 8) | public interface SnapshotService {
    method getBy (line 10) | Mono<Snapshot> getBy(String snapshotName);
    method getPatchedBy (line 12) | Mono<Snapshot> getPatchedBy(String snapshotName, String baseSnapshotNa...
    method patchAndCreate (line 14) | Mono<Snapshot> patchAndCreate(@NonNull Snapshot snapshot,
    method patchAndUpdate (line 18) | Mono<Snapshot> patchAndUpdate(@NonNull Snapshot snapshot,

FILE: application/src/main/java/run/halo/app/content/Stats.java
  class Stats (line 12) | @Data
    method Stats (line 23) | public Stats() {
    method Stats (line 26) | @Builder
    method empty (line 34) | public static Stats empty() {

FILE: application/src/main/java/run/halo/app/content/comment/AbstractCommentService.java
  class AbstractCommentService (line 21) | @RequiredArgsConstructor
    method fetchCurrentUser (line 36) | protected Mono<User> fetchCurrentUser() {
    method hasCommentManagePermission (line 42) | Mono<Boolean> hasCommentManagePermission() {
    method toCommentOwner (line 52) | protected Comment.CommentOwner toCommentOwner(User user) {
    method getOwnerInfo (line 60) | protected Mono<OwnerInfo> getOwnerInfo(Comment.CommentOwner owner) {
    method fetchCommentStats (line 71) | protected Mono<CommentStats> fetchCommentStats(String commentName) {
    method fetchReplyStats (line 75) | protected Mono<CommentStats> fetchReplyStats(String replyName) {
    method fetchStats (line 79) | private Mono<CommentStats> fetchStats(String meterName) {
    method isSafeHtml (line 95) | protected boolean isSafeHtml(@NonNull String html) {

FILE: application/src/main/java/run/halo/app/content/comment/CommentEmailOwner.java
  method toCommentOwner (line 30) | public Comment.CommentOwner toCommentOwner() {

FILE: application/src/main/java/run/halo/app/content/comment/CommentNotificationReasonPublisher.java
  class CommentNotificationReasonPublisher (line 45) | @Component
    method onNewComment (line 61) | @Async
    method onNewReply (line 75) | @Async
    method isPostComment (line 84) | boolean isPostComment(Comment comment) {
    method isPageComment (line 88) | boolean isPageComment(Comment comment) {
    class CommentContentConverter (line 95) | @Component
      method convertRelativeLinks (line 106) | public String convertRelativeLinks(String content) {
    class NewCommentOnPostReasonPublisher (line 116) | @Component
      method publishReasonBy (line 125) | public void publishReasonBy(Comment comment) {
      method doNotEmitReason (line 160) | boolean doNotEmitReason(Comment comment, Post post) {
      method isPostOwner (line 165) | boolean isPostOwner(Post post, Comment.CommentOwner commentOwner) {
    class NewCommentOnPageReasonPublisher (line 184) | @Component
      method publishReasonBy (line 192) | public void publishReasonBy(Comment comment) {
      method doNotEmitReason (line 230) | public boolean doNotEmitReason(Comment comment, SinglePage page) {
      method isPageOwner (line 235) | boolean isPageOwner(SinglePage page, Comment.CommentOwner commentOwn...
    class ReasonDataConverter (line 254) | @UtilityClass
      method toAttributeMap (line 256) | public static <T> Map<String, Object> toAttributeMap(T data) {
    class NewReplyReasonPublisher (line 263) | @Component
      method publishReasonBy (line 271) | public void publishReasonBy(Reply reply, Comment comment) {
      method getCommentSubjectDisplay (line 346) | @SuppressWarnings("unchecked")
      method doNotEmitReason (line 355) | boolean doNotEmitReason(Reply currentReply, Reply quoteReply, Commen...

FILE: application/src/main/java/run/halo/app/content/comment/CommentQuery.java
  class CommentQuery (line 28) | public class CommentQuery extends SortableRequest {
    method CommentQuery (line 30) | public CommentQuery(ServerRequest request) {
    method getKeyword (line 34) | @Nullable
    method getOwnerKind (line 39) | @Nullable
    method getOwnerName (line 44) | @Nullable
    method getSort (line 49) | @Override
    method toListOptions (line 58) | @Override
    method buildParameters (line 80) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/content/comment/CommentRequest.java
  class CommentRequest (line 18) | @Data
    method toComment (line 43) | public Comment toComment() {

FILE: application/src/main/java/run/halo/app/content/comment/CommentService.java
  type CommentService (line 15) | public interface CommentService {
    method listComment (line 17) | Mono<ListResult<ListedComment>> listComment(CommentQuery query);
    method create (line 19) | Mono<Comment> create(Comment comment);
    method removeBySubject (line 21) | Mono<Void> removeBySubject(@NonNull Ref subjectRef);

FILE: application/src/main/java/run/halo/app/content/comment/CommentServiceImpl.java
  class CommentServiceImpl (line 42) | @Component
    method CommentServiceImpl (line 48) | public CommentServiceImpl(RoleService roleService, ReactiveExtensionCl...
    method listComment (line 56) | @Override
    method create (line 70) | @Override
    method populateApproveState (line 123) | private Mono<Void> populateApproveState(Comment comment) {
    method populateOwner (line 133) | Mono<Void> populateOwner(Comment comment) {
    method removeBySubject (line 144) | @Override
    method cleanupComments (line 150) | private Mono<Void> cleanupComments(Ref subjectRef, int batchSize) {
    method deleteWithRetry (line 162) | private Mono<Comment> deleteWithRetry(Comment item) {
    method attemptToDelete (line 168) | private Mono<Comment> attemptToDelete(String name) {
    method listCommentsByRef (line 176) | Mono<ListResult<Comment>> listCommentsByRef(Ref subjectRef, PageReques...
    method checkCommentOwner (line 187) | private boolean checkCommentOwner(Comment comment, Boolean onlySystemU...
    method toListedComment (line 195) | private Mono<ListedComment> toListedComment(Comment comment) {
    method getCommentSubject (line 208) | @SuppressWarnings("unchecked")

FILE: application/src/main/java/run/halo/app/content/comment/CommentStats.java
  class CommentStats (line 12) | @Value
    method empty (line 18) | public static CommentStats empty() {

FILE: application/src/main/java/run/halo/app/content/comment/ListedComment.java
  class ListedComment (line 17) | @Data

FILE: application/src/main/java/run/halo/app/content/comment/ListedReply.java
  class ListedReply (line 16) | @Data

FILE: application/src/main/java/run/halo/app/content/comment/OwnerInfo.java
  class OwnerInfo (line 14) | @Value
    method from (line 34) | public static OwnerInfo from(Comment.CommentOwner owner) {
    method from (line 53) | public static OwnerInfo from(User user) {

FILE: application/src/main/java/run/halo/app/content/comment/PostCommentSubject.java
  class PostCommentSubject (line 19) | @Component
    method get (line 26) | @Override
    method getSubjectDisplay (line 31) | @Override
    method supports (line 41) | @Override

FILE: application/src/main/java/run/halo/app/content/comment/ReplyNotificationSubscriptionHelper.java
  class ReplyNotificationSubscriptionHelper (line 22) | @Component
    method subscribeNewReplyReasonForComment (line 35) | public void subscribeNewReplyReasonForComment(Comment comment) {
    method subscribeNewReplyReasonForReply (line 44) | public void subscribeNewReplyReasonForReply(Reply reply) {
    method subscribeReply (line 49) | void subscribeReply(UserIdentity identity) {
    method createSubscriber (line 60) | @Nullable
    method identityFrom (line 71) | public static UserIdentity identityFrom(Comment.CommentOwner owner) {

FILE: application/src/main/java/run/halo/app/content/comment/ReplyQuery.java
  class ReplyQuery (line 26) | public class ReplyQuery extends SortableRequest {
    method ReplyQuery (line 28) | public ReplyQuery(ServerWebExchange exchange) {
    method getCommentName (line 32) | @Schema(description = "Replies filtered by commentName.")
    method toListOptions (line 44) | public ListOptions toListOptions() {
    method toPageRequest (line 53) | public PageRequest toPageRequest() {
    method buildParameters (line 58) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/content/comment/ReplyRequest.java
  class ReplyRequest (line 17) | @Data
    method toReply (line 41) | public Reply toReply() {

FILE: application/src/main/java/run/halo/app/content/comment/ReplyService.java
  type ReplyService (line 13) | public interface ReplyService {
    method create (line 15) | Mono<Reply> create(String commentName, Reply reply);
    method list (line 17) | Mono<ListResult<ListedReply>> list(ReplyQuery query);
    method removeAllByComment (line 19) | Mono<Void> removeAllByComment(String commentName);

FILE: application/src/main/java/run/halo/app/content/comment/ReplyServiceImpl.java
  class ReplyServiceImpl (line 43) | @Service
    method ReplyServiceImpl (line 49) | public ReplyServiceImpl(RoleService roleService, ReactiveExtensionClie...
    method create (line 54) | @Override
    method doCreateReply (line 71) | private Mono<Reply> doCreateReply(Reply prepared) {
    method approveComment (line 85) | private Mono<Comment> approveComment(Comment comment) {
    method doApproveComment (line 95) | private Mono<Comment> doApproveComment(Comment comment) {
    method approveReply (line 106) | private Mono<Reply> approveReply(String replyName) {
    method doApproveReply (line 116) | private Mono<Reply> doApproveReply(String replyName) {
    method updateCommentWithRetry (line 128) | private Mono<Comment> updateCommentWithRetry(String name, UnaryOperato...
    method prepareReply (line 137) | private Mono<Reply> prepareReply(Comment comment, Reply reply) {
    method list (line 176) | @Override
    method removeAllByComment (line 188) | @Override
    method cleanupComments (line 194) | private Mono<Void> cleanupComments(String commentName, int batchSize) {
    method deleteWithRetry (line 206) | private Mono<Reply> deleteWithRetry(Reply item) {
    method attemptToDelete (line 212) | private Mono<Reply> attemptToDelete(String name) {
    method listRepliesByComment (line 220) | Mono<ListResult<Reply>> listRepliesByComment(String commentName, PageR...
    method toListedReply (line 231) | private Mono<ListedReply> toListedReply(Reply reply) {

FILE: application/src/main/java/run/halo/app/content/comment/SinglePageCommentSubject.java
  class SinglePageCommentSubject (line 19) | @Component
    method get (line 27) | @Override
    method getSubjectDisplay (line 32) | @Override
    method supports (line 42) | @Override

FILE: application/src/main/java/run/halo/app/content/impl/CategoryServiceImpl.java
  class CategoryServiceImpl (line 20) | @Component
    method listChildren (line 25) | @Override
    method getParentByName (line 39) | @Override
    method isCategoryHidden (line 54) | @Override
    method defaultSort (line 62) | static Sort defaultSort() {
    method isNotIndependent (line 68) | private boolean isNotIndependent(Category category) {

FILE: application/src/main/java/run/halo/app/content/impl/PostServiceImpl.java
  class PostServiceImpl (line 58) | @Slf4j
    method PostServiceImpl (line 66) | public PostServiceImpl(ReactiveExtensionClient client, CounterService ...
    method listPost (line 75) | @Override
    method buildListOptions (line 92) | Mono<ListOptions> buildListOptions(PostQuery query) {
    method fetchStats (line 112) | Mono<Stats> fetchStats(Post post) {
    method getListedPost (line 126) | private Mono<ListedPost> getListedPost(Post post) {
    method listTags (line 158) | private Flux<Tag> listTags(List<String> tagNames) {
    method listCategories (line 167) | @Override
    method listContributors (line 180) | private Flux<Contributor> listContributors(List<String> usernames) {
    method draftPost (line 195) | @Override
    method waitForPostToDraftConcludingWork (line 224) | private Mono<Post> waitForPostToDraftConcludingWork(String postName,
    method updatePost (line 249) | @Override
    method updateBy (line 271) | @Override
    method getHeadContent (line 276) | @Override
    method getHeadContent (line 282) | @Override
    method getReleaseContent (line 288) | @Override
    method getReleaseContent (line 294) | @Override
    method listSnapshots (line 300) | @Override
    method publish (line 307) | @Override
    method unpublish (line 318) | @Override
    method getByUsername (line 324) | @Override
    method revertToSpecifiedSnapshot (line 331) | @Override
    method deleteContent (line 357) | @Override
    method recycleBy (line 389) | @Override
    method updatePostWithRetry (line 398) | private Mono<Post> updatePostWithRetry(Post post, UnaryOperator<Post> ...
    method publishPostWithRetry (line 410) | Mono<Post> publishPostWithRetry(Post post) {

FILE: application/src/main/java/run/halo/app/content/impl/SinglePageServiceImpl.java
  class SinglePageServiceImpl (line 46) | @Slf4j
    method SinglePageServiceImpl (line 54) | public SinglePageServiceImpl(ReactiveExtensionClient client, CounterSe...
    method getHeadContent (line 62) | @Override
    method getReleaseContent (line 71) | @Override
    method listSnapshots (line 80) | @Override
    method list (line 87) | @Override
    method draft (line 102) | @Override
    method waitForPageToDraftConcludingWork (line 129) | private Mono<SinglePage> waitForPageToDraftConcludingWork(String pageN...
    method update (line 155) | @Override
    method revertToSpecifiedSnapshot (line 177) | @Override
    method deleteContent (line 203) | @Override
    method updatePageWithRetry (line 235) | private Mono<SinglePage> updatePageWithRetry(SinglePage page, UnaryOpe...
    method publish (line 247) | private Mono<SinglePage> publish(SinglePage singlePage) {
    method publishPageWithRetry (line 257) | Mono<SinglePage> publishPageWithRetry(SinglePage page) {
    method getListedSinglePage (line 267) | private Mono<ListedSinglePage> getListedSinglePage(SinglePage singlePa...
    method fetchStats (line 292) | Mono<Stats> fetchStats(SinglePage singlePage) {
    method listContributors (line 306) | private Flux<Contributor> listContributors(List<String> usernames) {

FILE: application/src/main/java/run/halo/app/content/impl/SnapshotServiceImpl.java
  class SnapshotServiceImpl (line 17) | @Service
    method SnapshotServiceImpl (line 24) | public SnapshotServiceImpl(ReactiveExtensionClient client) {
    method getBy (line 29) | @Override
    method getPatchedBy (line 34) | @Override
    method patchAndCreate (line 76) | @Override
    method patchAndUpdate (line 85) | @Override
    method patch (line 94) | private void patch(@NonNull Snapshot snapshot,

FILE: application/src/main/java/run/halo/app/content/permalinks/CategoryPermalinkPolicy.java
  class CategoryPermalinkPolicy (line 24) | @Component
    method permalink (line 34) | @Override
    method pattern (line 46) | public String pattern() {

FILE: application/src/main/java/run/halo/app/content/permalinks/ExtensionLocator.java
  method equals (line 28) | @Override
  method hashCode (line 40) | @Override

FILE: application/src/main/java/run/halo/app/content/permalinks/PermalinkPolicy.java
  type PermalinkPolicy (line 10) | public interface PermalinkPolicy<T extends AbstractExtension> {
    method permalink (line 15) | String permalink(T extension);

FILE: application/src/main/java/run/halo/app/content/permalinks/PostPermalinkPolicy.java
  class PostPermalinkPolicy (line 31) | @Component
    method permalink (line 46) | @Override
    method pattern (line 54) | public String pattern() {
    method createPermalink (line 61) | private String createPermalink(Post post, String pattern) {

FILE: application/src/main/java/run/halo/app/content/permalinks/TagPermalinkPolicy.java
  class TagPermalinkPolicy (line 23) | @Component
    method permalink (line 34) | @Override
    method pattern (line 47) | public String pattern() {

FILE: application/src/main/java/run/halo/app/content/stats/PostStatsUpdater.java
  class PostStatsUpdater (line 22) | @Component
    method PostStatsUpdater (line 32) | public PostStatsUpdater(ExtensionClient client) {
    method reconcile (line 38) | @Override
    method setupWith (line 48) | @Override
    method start (line 59) | @Override
    method stop (line 65) | @Override
    method isRunning (line 71) | @Override
    method getPhase (line 76) | @Override
    method onReplyEvent (line 81) | @EventListener(PostStatsChangedEvent.class)

FILE: application/src/main/java/run/halo/app/content/stats/ReplyEventReconciler.java
  class ReplyEventReconciler (line 41) | @Slf4j
    method ReplyEventReconciler (line 51) | public ReplyEventReconciler(ExtensionClient client) {
    method reconcile (line 57) | @Override
    method of (line 115) | public static CommentName of(String name) {
    method listOptionsWithFieldQuery (line 120) | static ListOptions listOptionsWithFieldQuery(Condition query) {
    method setupWith (line 126) | @Override
    method start (line 137) | @Override
    method stop (line 143) | @Override
    method isRunning (line 149) | @Override
    method getPhase (line 154) | @Override
    method onReplyEvent (line 159) | @EventListener(ReplyEvent.class)
    method onUnreadReplyCountChangedEvent (line 165) | @EventListener(CommentUnreadReplyCountChangedEvent.class)

FILE: application/src/main/java/run/halo/app/content/stats/TagPostCountUpdater.java
  class TagPostCountUpdater (line 36) | @Component
    method TagPostCountUpdater (line 41) | public TagPostCountUpdater(ExtensionClient client) {
    method reconcile (line 46) | @Override
    method onPostUpdated (line 70) | @EventListener(PostEvent.class)
    method calcTagsToUpdate (line 86) | private Set<String> calcTagsToUpdate(String postName) {
    method updateTagRelatedPostCount (line 105) | private void updateTagRelatedPostCount(String tagName) {

FILE: application/src/main/java/run/halo/app/content/stats/VisitedEventReconciler.java
  class VisitedEventReconciler (line 39) | @Slf4j
    method VisitedEventReconciler (line 50) | public VisitedEventReconciler(ExtensionClient client) {
    method reconcile (line 56) | @Override
    method createOrUpdateVisits (line 62) | private void createOrUpdateVisits(String name, Integer visits) {
    method queuedVisitBucketTask (line 78) | @Scheduled(cron = "0 0/1 * * * ?")
    method setupWith (line 88) | @Override
    method start (line 99) | @Override
    method stop (line 105) | @Override
    method isRunning (line 122) | @Override
    method getPhase (line 127) | @Override
    class VisitedEventListener (line 135) | @Component
      method onVisited (line 140) | @Async
      method mergeVisits (line 146) | private void mergeVisits(VisitedEvent event) {
      method checkVisitSubject (line 163) | private boolean checkVisitSubject(GroupPluralName groupPluralName) {

FILE: application/src/main/java/run/halo/app/content/stats/VotedEventReconciler.java
  class VotedEventReconciler (line 36) | @Slf4j
    method VotedEventReconciler (line 45) | public VotedEventReconciler(ExtensionClient client) {
    method reconcile (line 51) | @Override
    method setupWith (line 77) | @Override
    method start (line 88) | @Override
    method stop (line 94) | @Override
    method isRunning (line 100) | @Override
    method getPhase (line 105) | @Override
    class VotedEventListener (line 110) | @Component
      method onVoted (line 118) | @Async
      method checkSubject (line 129) | private boolean checkSubject(

FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentChangedEvent.java
  class AttachmentChangedEvent (line 12) | public class AttachmentChangedEvent extends ApplicationEvent {
    method AttachmentChangedEvent (line 17) | public AttachmentChangedEvent(Object source, Attachment attachment) {

FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentLister.java
  type AttachmentLister (line 7) | public interface AttachmentLister {
    method listBy (line 9) | Mono<ListResult<Attachment>> listBy(SearchRequest searchRequest);

FILE: application/src/main/java/run/halo/app/core/attachment/AttachmentRootGetter.java
  type AttachmentRootGetter (line 9) | public interface AttachmentRootGetter extends Supplier<Path> {

FILE: application/src/main/java/run/halo/app/core/attachment/PolicyConfigChangeDetector.java
  class PolicyConfigChangeDetector (line 37) | @Component
    method reconcile (line 45) | @Override
    method setupWith (line 66) | @Override
    class AttachmentUpdateTrigger (line 82) | @Component
      method AttachmentUpdateTrigger (line 92) | public AttachmentUpdateTrigger(ExtensionClient client) {
      method reconcile (line 98) | @Override
      method addAll (line 108) | void addAll(List<String> names) {
      method setupWith (line 114) | @Override
      method start (line 126) | @Override
      method stop (line 132) | @Override
      method isRunning (line 138) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/SearchRequest.java
  class SearchRequest (line 27) | public class SearchRequest extends SortableRequest {
    method SearchRequest (line 29) | public SearchRequest(ServerRequest request) {
    method getKeyword (line 33) | public Optional<String> getKeyword() {
    method getUngrouped (line 38) | public Optional<Boolean> getUngrouped() {
    method getAccepts (line 43) | public Optional<List<String>> getAccepts() {
    method toListOptions (line 51) | public ListOptions toListOptions(List<String> hiddenGroups) {
    method buildParameters (line 78) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/AttachmentEndpoint.java
  class AttachmentEndpoint (line 36) | @Slf4j
    method endpoint (line 45) | @Override
    method search (line 111) | Mono<ServerResponse> search(ServerRequest request) {
    type IUploadRequest (line 137) | @Schema(types = "object")
      method getFile (line 140) | @Schema(requiredMode = REQUIRED, description = "Attachment file")
      method getPolicyName (line 143) | @Schema(requiredMode = REQUIRED, description = "Storage policy name")
      method getGroupName (line 146) | @Schema(description = "The name of the group to which the attachment...
    method getFile (line 153) | public FilePart getFile() {
    method getPolicyName (line 160) | public String getPolicyName() {
    method getGroupName (line 167) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/LocalAttachmentUploadHandler.java
  class LocalAttachmentUploadHandler (line 66) | @Slf4j
    method setClock (line 84) | void setClock(Clock clock) {
    method upload (line 88) | @Override
    method validateFile (line 176) | private Mono<Void> validateFile(FilePart file, PolicySetting setting) {
    method handleFileTypeError (line 216) | private static void handleFileTypeError(SynchronousSink<Object> sink, ...
    method detectMimeType (line 224) | @NonNull
    method delete (line 234) | @Override
    method getPermalink (line 256) | @Override
    method getSharedURL (line 264) | @Override
    method getThumbnailLinks (line 272) | @Override
    method doGetPermalink (line 282) | protected Optional<URI> doGetPermalink(Attachment attachment) {
    method doGetThumbnailLinks (line 292) | private Map<ThumbnailSize, URI> doGetThumbnailLinks(Attachment attachm...
    method deleteAttachmentFile (line 318) | private void deleteAttachmentFile(Path attachmentPath) {
    method deleteThumbnails (line 329) | private void deleteThumbnails(Path attachmentPath) {
    method shouldHandle (line 333) | private boolean shouldHandle(Policy policy) {
    method writeContent (line 350) | private Mono<Path> writeContent(Flux<DataBuffer> content,
    method getFilename (line 378) | private String getFilename(String filename, PolicySetting setting) {
    class PolicySetting (line 428) | @Data
      method setMaxFileSize (line 441) | public void setMaxFileSize(String maxFileSize) {
    type RenameMethod (line 449) | public enum RenameMethod {
    class RenameStrategy (line 455) | @Data

FILE: application/src/main/java/run/halo/app/core/attachment/endpoint/PolicyEndpoint.java
  class PolicyEndpoint (line 33) | @Component
    method endpoint (line 43) | @Override
    method updatePolicyConfigByGroup (line 99) | private Mono<ServerResponse> updatePolicyConfigByGroup(ServerRequest s...
    method getPolicyConfigByGroup (line 158) | private Mono<ServerResponse> getPolicyConfigByGroup(ServerRequest serv...
    method groupVersion (line 174) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/extension/LocalThumbnail.java
  class LocalThumbnail (line 17) | @Data
    method setStatus (line 33) | public void setStatus(Status status) {
    class Spec (line 37) | @Data
    class Status (line 76) | @Data
    type Phase (line 82) | public enum Phase {
    method uniqueImageAndSize (line 86) | public static String uniqueImageAndSize(LocalThumbnail localThumbnail) {
    method uniqueImageAndSize (line 91) | public static String uniqueImageAndSize(String imageSignature, Thumbna...

FILE: application/src/main/java/run/halo/app/core/attachment/extension/Thumbnail.java
  class Thumbnail (line 13) | @Data
    class Spec (line 25) | @Data
    method idIndexFunc (line 42) | public static String idIndexFunc(Thumbnail thumbnail) {
    method idIndexFunc (line 47) | public static String idIndexFunc(String imageHash, String size) {

FILE: application/src/main/java/run/halo/app/core/attachment/impl/AttachmentListerImpl.java
  class AttachmentListerImpl (line 16) | @Component
    method listBy (line 21) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/impl/AttachmentRootGetterImpl.java
  class AttachmentRootGetterImpl (line 9) | @Component
    method get (line 14) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/AttachmentReconciler.java
  class AttachmentReconciler (line 27) | @Slf4j
    method reconcile (line 38) | @Override
    method setupWith (line 87) | @Override
    method cleanUpResources (line 94) | void cleanUpResources(Attachment attachment) {

FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/LocalThumbnailsReconciler.java
  class LocalThumbnailsReconciler (line 21) | @Slf4j
    method reconcile (line 33) | @Override
    method setupWith (line 53) | @Override
    method cleanUpThumbnailFile (line 60) | private void cleanUpThumbnailFile(LocalThumbnail thumbnail) {

FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/PolicyReconciler.java
  class PolicyReconciler (line 13) | @Component
    method reconcile (line 18) | @Override
    method checkOwnerLabel (line 25) | private void checkOwnerLabel(Policy policy) {
    method setupWith (line 36) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/reconciler/ThumbnailReconciler.java
  class ThumbnailReconciler (line 12) | @Slf4j
    method ThumbnailReconciler (line 19) | ThumbnailReconciler(ExtensionClient client) {
    method reconcile (line 23) | @Override
    method setupWith (line 36) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/DefaultLocalThumbnailService.java
  class DefaultLocalThumbnailService (line 38) | @Slf4j
    method DefaultLocalThumbnailService (line 61) | public DefaultLocalThumbnailService(AttachmentRootGetter attachmentRoo...
    method setExecutorService (line 77) | void setExecutorService(ExecutorService executorService) {
    method destroy (line 81) | @Override
    method generate (line 86) | @Override
    method delete (line 121) | @Override
    method resolveThumbnailPath (line 141) | Optional<Path> resolveThumbnailPath(Path source, ThumbnailSize size) {
    method generateThumbnail (line 160) | private Path generateThumbnail(Path sourcePath, Path thumbnailPath, Th...

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/DefaultThumbnailService.java
  class DefaultThumbnailService (line 35) | @Slf4j
    method DefaultThumbnailService (line 47) | public DefaultThumbnailService(ReactiveExtensionClient client,
    method handleAttachmentChangedEvent (line 57) | @EventListener
    method updateCache (line 62) | void updateCache(Attachment attachment) {
    method get (line 93) | @Override
    method get (line 98) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/LocalThumbnailService.java
  type LocalThumbnailService (line 14) | public interface LocalThumbnailService {
    method generate (line 24) | Mono<Resource> generate(Path source, ThumbnailSize size);
    method delete (line 31) | void delete(Path source);

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailImgTagPostProcessor.java
  class ThumbnailImgTagPostProcessor (line 21) | @Slf4j
    method ThumbnailImgTagPostProcessor (line 36) | public ThumbnailImgTagPostProcessor(ThumbnailService thumbnailService) {
    method process (line 43) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailResourceTransformer.java
  class ThumbnailResourceTransformer (line 20) | @Slf4j
    method ThumbnailResourceTransformer (line 25) | public ThumbnailResourceTransformer(LocalThumbnailService localThumbna...
    method transform (line 29) | @Override

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailService.java
  type ThumbnailService (line 14) | public interface ThumbnailService {
    method get (line 23) | Mono<URI> get(URI permalink, ThumbnailSize size);
    method get (line 31) | Mono<Map<ThumbnailSize, URI>> get(URI permalink);

FILE: application/src/main/java/run/halo/app/core/attachment/thumbnail/ThumbnailUtils.java
  type ThumbnailUtils (line 16) | public enum ThumbnailUtils {
    method isSupportedImage (line 36) | public static boolean isSupportedImage(@Nullable String fileSuffix) {
    method isSupportedImage (line 43) | public static boolean isSupportedImage(@Nullable MimeType mimeType) {
    method buildSrcsetMap (line 54) | public static Map<ThumbnailSize, URI> buildSrcsetMap(URI permalink) {

FILE: application/src/main/java/run/halo/app/core/counter/CounterService.java
  type CounterService (line 12) | public interface CounterService {
    method getByName (line 14) | Mono<Counter> getByName(String counterName);
    method getByNames (line 16) | Flux<Counter> getByNames(Collection<String> names);
    method deleteByName (line 18) | Mono<Counter> deleteByName(String counterName);

FILE: application/src/main/java/run/halo/app/core/counter/CounterServiceImpl.java
  class CounterServiceImpl (line 20) | @Service
    method CounterServiceImpl (line 25) | public CounterServiceImpl(ReactiveExtensionClient client) {
    method getByName (line 29) | @Override
    method getByNames (line 34) | @Override
    method deleteByName (line 45) | @Override

FILE: application/src/main/java/run/halo/app/core/counter/MeterUtils.java
  class MeterUtils (line 17) | public class MeterUtils {
    method nameOf (line 35) | public static String nameOf(String group, String plural, String name) {
    method nameOf (line 42) | public static <T extends AbstractExtension> String nameOf(Class<T> cla...
    method visitCounter (line 47) | public static Counter visitCounter(MeterRegistry registry, String name) {
    method upvoteCounter (line 51) | public static Counter upvoteCounter(MeterRegistry registry, String nam...
    method downvoteCounter (line 55) | public static Counter downvoteCounter(MeterRegistry registry, String n...
    method totalCommentCounter (line 59) | public static Counter totalCommentCounter(MeterRegistry registry, Stri...
    method approvedCommentCounter (line 63) | public static Counter approvedCommentCounter(MeterRegistry registry, S...
    method isVisitCounter (line 67) | public static boolean isVisitCounter(Counter counter) {
    method isUpvoteCounter (line 75) | public static boolean isUpvoteCounter(Counter counter) {
    method isDownvoteCounter (line 83) | public static boolean isDownvoteCounter(Counter counter) {
    method isTotalCommentCounter (line 91) | public static boolean isTotalCommentCounter(Counter counter) {
    method isApprovedCommentCounter (line 99) | public static boolean isApprovedCommentCounter(Counter counter) {
    method counter (line 114) | private static Counter counter(MeterRegistry registry, String name, Ta...

FILE: application/src/main/java/run/halo/app/core/endpoint/AttachmentHandler.java
  class AttachmentHandler (line 30) | @Slf4j
    method buildDoc (line 42) | public void buildDoc(Builder builder) {
    method handleUpload (line 59) | public Mono<ServerResponse> handleUpload(ServerRequest serverRequest,
    class UploadForm (line 120) | @Data

FILE: application/src/main/java/run/halo/app/core/endpoint/WebSocketEndpointManager.java
  type WebSocketEndpointManager (line 10) | public interface WebSocketEndpointManager {
    method register (line 12) | void register(Collection<WebSocketEndpoint> endpoints);
    method unregister (line 14) | void unregister(Collection<WebSocketEndpoint> endpoints);

FILE: application/src/main/java/run/halo/app/core/endpoint/WebSocketHandlerMapping.java
  class WebSocketHandlerMapping (line 24) | public class WebSocketHandlerMapping extends AbstractHandlerMapping
    method WebSocketHandlerMapping (line 31) | public WebSocketHandlerMapping() {
    method getHandlerInternal (line 36) | @Override
    method register (line 93) | @Override
    method unregister (line 114) | @Override
    method afterPropertiesSet (line 129) | @Override
    method getEndpointMap (line 137) | BiMap<PathPattern, WebSocketEndpoint> getEndpointMap() {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/AttachmentConsoleEndpoint.java
  class AttachmentConsoleEndpoint (line 23) | @Slf4j
    method groupVersion (line 32) | @Override
    method endpoint (line 37) | @Override
    method handleUpload (line 55) | private Mono<ServerResponse> handleUpload(ServerRequest serverRequest) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/AuthProviderEndpoint.java
  class AuthProviderEndpoint (line 25) | @Component
    method endpoint (line 31) | @Override
    method enableAuthProvider (line 71) | private Mono<ServerResponse> enableAuthProvider(ServerRequest request) {
    method disableAuthProvider (line 77) | private Mono<ServerResponse> disableAuthProvider(ServerRequest request) {
    method listAuthProviders (line 83) | Mono<ServerResponse> listAuthProviders(ServerRequest request) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/CommentEndpoint.java
  class CommentEndpoint (line 38) | @Component
    method CommentEndpoint (line 44) | public CommentEndpoint(CommentService commentService, ReplyService rep...
    method endpoint (line 49) | @Override
    method listComments (line 98) | Mono<ServerResponse> listComments(ServerRequest request) {
    method createComment (line 104) | Mono<ServerResponse> createComment(ServerRequest request) {
    method createReply (line 115) | Mono<ServerResponse> createReply(ServerRequest request) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/ConsoleUserEndpoint.java
  class ConsoleUserEndpoint (line 30) | @Component
    method ConsoleUserEndpoint (line 35) | ConsoleUserEndpoint(UserService userService) {
    method endpoint (line 39) | @Override
    method handleEnableUser (line 78) | private Mono<ServerResponse> handleEnableUser(ServerRequest request) {
    method handleDisableUser (line 86) | private Mono<ServerResponse> handleDisableUser(ServerRequest request) {
    method groupVersion (line 105) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/console/CustomEndpointsBuilder.java
  class CustomEndpointsBuilder (line 15) | public class CustomEndpointsBuilder {
    method CustomEndpointsBuilder (line 19) | public CustomEndpointsBuilder() {
    method add (line 23) | public CustomEndpointsBuilder add(CustomEndpoint customEndpoint) {
    method build (line 30) | public RouterFunction<ServerResponse> build() {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/PluginEndpoint.java
  class PluginEndpoint (line 76) | @Slf4j
    method PluginEndpoint (line 96) | public PluginEndpoint(ReactiveExtensionClient client,
    method endpoint (line 108) | @Override
    method fetchPluginJsonConfig (line 281) | private Mono<ServerResponse> fetchPluginJsonConfig(ServerRequest reque...
    method updatePluginJsonConfig (line 289) | private Mono<ServerResponse> updatePluginJsonConfig(ServerRequest requ...
    method changePluginRunningState (line 310) | Mono<ServerResponse> changePluginRunningState(ServerRequest request) {
    method afterPropertiesSet (line 321) | @Override
    class RunningStateRequest (line 331) | @Data
    method fetchJsBundle (line 338) | private Mono<ServerResponse> fetchJsBundle(ServerRequest request) {
    method fetchCssBundle (line 367) | private Mono<ServerResponse> fetchCssBundle(ServerRequest request) {
    method buildJsBundleUri (line 396) | URI buildJsBundleUri(String type, String version) {
    method upgradeFromUri (line 401) | private Mono<ServerResponse> upgradeFromUri(ServerRequest request) {
    method installFromUri (line 414) | private Mono<ServerResponse> installFromUri(ServerRequest request) {
    method reload (line 433) | private Mono<ServerResponse> reload(ServerRequest serverRequest) {
    method fetchPluginConfig (line 438) | private Mono<ServerResponse> fetchPluginConfig(ServerRequest request) {
    method fetchPluginSetting (line 446) | private Mono<ServerResponse> fetchPluginSetting(ServerRequest request) {
    method updatePluginConfig (line 454) | private Mono<ServerResponse> updatePluginConfig(ServerRequest request) {
    method resetSettingConfig (line 491) | private Mono<ServerResponse> resetSettingConfig(ServerRequest request) {
    method updateConfigMapData (line 507) | private Mono<ConfigMap> updateConfigMapData(String configMapName, Map<...
    method install (line 518) | private Mono<ServerResponse> install(ServerRequest request) {
    method upgrade (line 534) | private Mono<ServerResponse> upgrade(ServerRequest request) {
    method installFromFile (line 552) | private Mono<Plugin> installFromFile(FilePart filePart,
    class ListRequest (line 560) | public static class ListRequest extends SortableRequest {
      method ListRequest (line 562) | public ListRequest(ServerRequest request) {
      method getKeyword (line 566) | @Schema(name = "keyword", description = "Keyword of plugin name or d...
      method getEnabled (line 571) | @Schema(name = "enabled", description = "Whether the plugin is enabl...
      method getSort (line 577) | @Override
      method toListOptions (line 590) | @Override
      method buildParameters (line 608) | public static void buildParameters(Builder builder) {
    method list (line 626) | Mono<ServerResponse> list(ServerRequest request) {
    class InstallRequest (line 637) | @Schema(name = "PluginInstallRequest", types = "object")
      method InstallRequest (line 642) | public InstallRequest(MultiValueMap<String, Part> multipartData) {
      method getFile (line 646) | @Schema(requiredMode = NOT_REQUIRED, description = "Plugin Jar file.")
      method getPresetName (line 661) | @Schema(requiredMode = NOT_REQUIRED,
      method getSource (line 679) | @Schema(requiredMode = NOT_REQUIRED, description = "Install source. ...
    type InstallSource (line 694) | public enum InstallSource {
    method deleteFileIfExists (line 700) | Mono<Void> deleteFileIfExists(Path path) {
    method writeToTempFile (line 704) | private Mono<Path> writeToTempFile(Publisher<DataBuffer> content) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/PostEndpoint.java
  class PostEndpoint (line 50) | @Slf4j
    method endpoint (line 59) | @Override
    method deleteContent (line 249) | private Mono<ServerResponse> deleteContent(ServerRequest request) {
    method revertToSpecifiedSnapshot (line 256) | private Mono<ServerResponse> revertToSpecifiedSnapshot(ServerRequest r...
    method fetchContent (line 270) | private Mono<ServerResponse> fetchContent(ServerRequest request) {
    method listSnapshots (line 281) | private Mono<ServerResponse> listSnapshots(ServerRequest request) {
    method fetchReleaseContent (line 287) | private Mono<ServerResponse> fetchReleaseContent(ServerRequest request) {
    method fetchHeadContent (line 293) | private Mono<ServerResponse> fetchHeadContent(ServerRequest request) {
    method draftPost (line 299) | Mono<ServerResponse> draftPost(ServerRequest request) {
    method updateContent (line 305) | Mono<ServerResponse> updateContent(ServerRequest request) {
    method updatePost (line 319) | Mono<ServerResponse> updatePost(ServerRequest request) {
    method publishPost (line 325) | Mono<ServerResponse> publishPost(ServerRequest request) {
    method awaitPostPublished (line 352) | private Mono<Post> awaitPostPublished(String postName) {
    method unpublishPost (line 373) | private Mono<ServerResponse> unpublishPost(ServerRequest request) {
    method recyclePost (line 386) | private Mono<ServerResponse> recyclePost(ServerRequest request) {
    method listPost (line 399) | Mono<ServerResponse> listPost(ServerRequest request) {
    method setMaxAttemptsWaitForPublish (line 408) | void setMaxAttemptsWaitForPublish(int maxAttempts) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/ReplyEndpoint.java
  class ReplyEndpoint (line 24) | @Component
    method ReplyEndpoint (line 29) | public ReplyEndpoint(ReplyService replyService) {
    method endpoint (line 33) | @Override
    method listReplies (line 50) | Mono<ServerResponse> listReplies(ServerRequest request) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/SinglePageEndpoint.java
  class SinglePageEndpoint (line 46) | @Slf4j
    method endpoint (line 54) | @Override
    method deleteContent (line 218) | private Mono<ServerResponse> deleteContent(ServerRequest request) {
    method revertToSpecifiedSnapshot (line 225) | private Mono<ServerResponse> revertToSpecifiedSnapshot(ServerRequest r...
    method fetchContent (line 240) | private Mono<ServerResponse> fetchContent(ServerRequest request) {
    method listSnapshots (line 250) | private Mono<ServerResponse> listSnapshots(ServerRequest request) {
    method fetchReleaseContent (line 256) | private Mono<ServerResponse> fetchReleaseContent(ServerRequest request) {
    method fetchHeadContent (line 262) | private Mono<ServerResponse> fetchHeadContent(ServerRequest request) {
    method draftSinglePage (line 268) | Mono<ServerResponse> draftSinglePage(ServerRequest request) {
    method updateContent (line 274) | Mono<ServerResponse> updateContent(ServerRequest request) {
    method updateSinglePage (line 288) | Mono<ServerResponse> updateSinglePage(ServerRequest request) {
    method publishSinglePage (line 294) | Mono<ServerResponse> publishSinglePage(ServerRequest request) {
    method listSinglePage (line 339) | Mono<ServerResponse> listSinglePage(ServerRequest request) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/StatsEndpoint.java
  class StatsEndpoint (line 29) | @Component
    method StatsEndpoint (line 34) | public StatsEndpoint(ReactiveExtensionClient client) {
    method endpoint (line 38) | @Override
    method getStats (line 52) | Mono<ServerResponse> getStats(ServerRequest request) {
    class DashboardStats (line 103) | @Data
      method emptyStats (line 117) | public static DashboardStats emptyStats() {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/SystemConfigEndpoint.java
  class SystemConfigEndpoint (line 29) | @Component
    method endpoint (line 35) | @Override
    method updateConfigByGroup (line 74) | private Mono<ServerResponse> updateConfigByGroup(ServerRequest request) {
    method getConfigByGroup (line 91) | private Mono<ServerResponse> getConfigByGroup(ServerRequest request) {
    method groupVersion (line 98) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/console/TagEndpoint.java
  class TagEndpoint (line 35) | @Slf4j
    method endpoint (line 42) | @Override
    method listTag (line 60) | Mono<ServerResponse> listTag(ServerRequest request) {
    class TagQuery (line 68) | public static class TagQuery extends SortableRequest {
      method TagQuery (line 70) | public TagQuery(ServerRequest request) {
      method getKeyword (line 74) | public Optional<String> getKeyword() {
      method toListOptions (line 79) | @Override
      method buildParameters (line 91) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/core/endpoint/console/TrackerEndpoint.java
  class TrackerEndpoint (line 31) | @AllArgsConstructor
    method endpoint (line 37) | @Override
    method increaseVisit (line 86) | private Mono<ServerResponse> increaseVisit(ServerRequest request) {
    method upvote (line 97) | private Mono<ServerResponse> upvote(ServerRequest request) {
    method downvote (line 108) | private Mono<ServerResponse> downvote(ServerRequest request) {
    method groupVersion (line 135) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/console/UserEndpoint.java
  class UserEndpoint (line 97) | @Component
    method endpoint (line 114) | @Override
    method verifyEmail (line 258) | private Mono<ServerResponse> verifyEmail(ServerRequest request) {
    method doVerifyCode (line 267) | private Mono<Void> doVerifyCode(VerifyCodeRequest verifyCodeRequest) {
    method verifyPasswordAndCode (line 274) | private Mono<Void> verifyPasswordAndCode(String username, VerifyCodeRe...
    method verifyEmailCode (line 282) | private Mono<Void> verifyEmailCode(String username, String code) {
    method sendEmailVerificationCode (line 301) | private Mono<ServerResponse> sendEmailVerificationCode(ServerRequest r...
    method verificationEmailRateLimiter (line 328) | <T> RateLimiterOperator<T> verificationEmailRateLimiter(String usernam...
    method sendEmailVerificationCodeRateLimiter (line 335) | <T> RateLimiterOperator<T> sendEmailVerificationCodeRateLimiter(String...
    method deleteUserAvatar (line 342) | private Mono<ServerResponse> deleteUserAvatar(ServerRequest request) {
    method getUserOrSelf (line 354) | private Mono<User> getUserOrSelf(String name) {
    method uploadUserAvatar (line 362) | private Mono<ServerResponse> uploadUserAvatar(ServerRequest request) {
    type IAvatarUploadRequest (line 380) | @Schema(types = "object")
      method getFile (line 382) | @Schema(requiredMode = REQUIRED, description = "Avatar file")
    method getFile (line 387) | public FilePart getFile() {
    method uploadAvatar (line 404) | private Mono<Attachment> uploadAvatar(AvatarUploadRequest uploadReques...
    method maxSizeCheck (line 429) | private Flux<DataBuffer> maxSizeCheck(Flux<DataBuffer> content) {
    method createUser (line 440) | private Mono<ServerResponse> createUser(ServerRequest request) {
    method getUserByName (line 462) | private Mono<ServerResponse> getUserByName(ServerRequest request) {
    method from (line 492) | public static User from(CreateUserRequest userRequest) {
    method updateProfile (line 512) | private Mono<ServerResponse> updateProfile(ServerRequest request) {
    method getAuthenticatedUserName (line 567) | private static Mono<String> getAuthenticatedUserName() {
    method changeAnyonePasswordForAdmin (line 573) | Mono<ServerResponse> changeAnyonePasswordForAdmin(ServerRequest reques...
    method changeOwnPassword (line 591) | Mono<ServerResponse> changeOwnPassword(ServerRequest request) {
    method me (line 639) | @NonNull
    method grantPermission (line 660) | @NonNull
    method getUserPermission (line 673) | @NonNull
    method uiPermissions (line 701) | private List<String> uiPermissions(Collection<Role> roles) {
    class UserPermission (line 716) | @Data
    class ListRequest (line 729) | public static class ListRequest extends SortableRequest {
      method ListRequest (line 731) | public ListRequest(ServerRequest request) {
      method getKeyword (line 735) | @Schema(name = "keyword")
      method getRole (line 740) | @Schema(name = "role")
      method toListOptions (line 748) | public ListOptions toListOptions() {
      method buildParameters (line 769) | public static void buildParameters(Builder builder) {
    method list (line 791) | Mono<ServerResponse> list(ServerRequest request) {
    method toListedUser (line 803) | private Mono<ListResult<ListedUser>> toListedUser(ListResult<User> lis...
    method convertFrom (line 832) | <T> ListResult<T> convertFrom(ListResult<?> listResult, List<T> items) {
    method isDisplayNameAllowed (line 839) | private boolean isDisplayNameAllowed(SystemSetting.User setting, Strin...

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/CategoryQueryEndpoint.java
  class CategoryQueryEndpoint (line 35) | @Component
    method endpoint (line 42) | @Override
    method listPostsByCategoryName (line 91) | private Mono<ServerResponse> listPostsByCategoryName(ServerRequest req...
    method getByName (line 105) | private Mono<ServerResponse> getByName(ServerRequest request) {
    method listCategories (line 115) | private Mono<ServerResponse> listCategories(ServerRequest request) {
    class CategoryPublicQuery (line 125) | public static class CategoryPublicQuery extends SortableRequest {
      method CategoryPublicQuery (line 126) | public CategoryPublicQuery(ServerWebExchange exchange) {
      method buildParameters (line 130) | public static void buildParameters(Builder builder) {
    method groupVersion (line 135) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/CommentFinderEndpoint.java
  class CommentFinderEndpoint (line 64) | @Component
    method endpoint (line 74) | @Override
    method groupVersion (line 147) | @Override
    method createComment (line 152) | Mono<ServerResponse> createComment(ServerRequest request) {
    method createIpBasedRateLimiter (line 165) | private <T> RateLimiterOperator<T> createIpBasedRateLimiter(ServerRequ...
    method createReply (line 172) | Mono<ServerResponse> createReply(ServerRequest request) {
    method checkReplyOwner (line 207) | private boolean checkReplyOwner(Reply reply, Boolean onlySystemUser) {
    method listComments (line 215) | Mono<ServerResponse> listComments(ServerRequest request) {
    method getComment (line 228) | Mono<ServerResponse> getComment(ServerRequest request) {
    method listCommentReplies (line 235) | Mono<ServerResponse> listCommentReplies(ServerRequest request) {
    class CommentQuery (line 244) | public static class CommentQuery extends PageableRequest {
      method CommentQuery (line 248) | public CommentQuery(ServerRequest request) {
      method getGroup (line 253) | @Schema(description = "The comment subject group.")
      method getVersion (line 258) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
      method getKind (line 268) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
      method getName (line 282) | @Schema(requiredMode = REQUIRED, description = "The comment subject ...
      method getWithReplies (line 291) | @Schema(description = "Whether to include replies. Default is false.",
      method getReplySize (line 298) | @Schema(description = "Reply size of the comment, default is 10, onl...
      method getSort (line 305) | @ArraySchema(uniqueItems = true,
      method toRef (line 316) | Ref toRef() {
      method toPageRequest (line 325) | public PageRequest toPageRequest() {
      method emptyToNull (line 329) | String emptyToNull(String str) {
      method buildParameters (line 333) | public static void buildParameters(Builder builder) {
    class PageableRequest (line 377) | public static class PageableRequest extends IListRequest.QueryListRequ...
      method PageableRequest (line 379) | public PageableRequest(MultiValueMap<String, String> queryParams) {
      method getLabelSelector (line 383) | @Override
      method getFieldSelector (line 389) | @Override
      method buildParameters (line 395) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/MenuQueryEndpoint.java
  class MenuQueryEndpoint (line 30) | @Component
    method endpoint (line 37) | @Override
    method getByName (line 66) | private Mono<ServerResponse> getByName(ServerRequest request) {
    method determineMenuName (line 75) | private Mono<String> determineMenuName(ServerRequest request) {
    method groupVersion (line 88) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PluginQueryEndpoint.java
  class PluginQueryEndpoint (line 25) | @Component
    method endpoint (line 31) | @Override
    method availableByName (line 52) | private Mono<ServerResponse> availableByName(ServerRequest request) {
    method groupVersion (line 58) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PostPublicQuery.java
  class PostPublicQuery (line 13) | public class PostPublicQuery extends SortableRequest {
    method PostPublicQuery (line 15) | public PostPublicQuery(ServerWebExchange exchange) {
    method buildParameters (line 19) | public static void buildParameters(Builder builder) {

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PostQueryEndpoint.java
  class PostQueryEndpoint (line 32) | @Component
    method endpoint (line 39) | @Override
    method getPostNavigationByName (line 85) | private Mono<ServerResponse> getPostNavigationByName(ServerRequest req...
    method getPostByName (line 91) | private Mono<ServerResponse> getPostByName(ServerRequest request) {
    method listPosts (line 100) | private Mono<ServerResponse> listPosts(ServerRequest request) {
    method groupVersion (line 108) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/PublicApiUtils.java
  class PublicApiUtils (line 21) | @UtilityClass
    method groupVersion (line 31) | public static GroupVersion groupVersion(Extension extension) {
    method toAnotherListResult (line 46) | public static <T, R> ListResult<R> toAnotherListResult(ListResult<T> l...
    method containsElement (line 63) | public static <T> boolean containsElement(@Nullable Collection<T> coll...

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/SinglePageQueryEndpoint.java
  class SinglePageQueryEndpoint (line 33) | @Component
    method endpoint (line 41) | @Override
    method getByName (line 74) | private Mono<ServerResponse> getByName(ServerRequest request) {
    method listSinglePages (line 83) | private Mono<ServerResponse> listSinglePages(ServerRequest request) {
    class SinglePagePublicQuery (line 89) | static class SinglePagePublicQuery extends SortableRequest {
      method SinglePagePublicQuery (line 91) | public SinglePagePublicQuery(ServerWebExchange exchange) {
      method buildParameters (line 95) | public static void buildParameters(Builder builder) {
    method groupVersion (line 100) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/SiteStatsQueryEndpoint.java
  class SiteStatsQueryEndpoint (line 24) | @Component
    method endpoint (line 30) | @Override
    method getStats (line 45) | private Mono<ServerResponse> getStats(ServerRequest request) {
    method groupVersion (line 53) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/TagQueryEndpoint.java
  class TagQueryEndpoint (line 35) | @Component
    method endpoint (line 43) | @Override
    method getTagByName (line 93) | private Mono<ServerResponse> getTagByName(ServerRequest request) {
    method listPostsByTagName (line 102) | private Mono<ServerResponse> listPostsByTagName(ServerRequest request) {
    method listTags (line 116) | private Mono<ServerResponse> listTags(ServerRequest request) {
    class TagPublicQuery (line 130) | static class TagPublicQuery extends SortableRequest {
      method TagPublicQuery (line 131) | public TagPublicQuery(ServerWebExchange exchange) {
      method buildParameters (line 135) | public static void buildParameters(Builder builder) {
    method groupVersion (line 140) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/theme/ThumbnailEndpoint.java
  class ThumbnailEndpoint (line 33) | @Component
    method endpoint (line 39) | @Override
    method getThumbnailByUri (line 82) | private Mono<ServerResponse> getThumbnailByUri(ServerRequest request) {
    method groupVersion (line 111) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/AnnotationSettingEndpoint.java
  class AnnotationSettingEndpoint (line 37) | @Component
    method endpoint (line 47) | @Override
    method listAvailableAnnotationSettings (line 77) | private Mono<ServerResponse> listAvailableAnnotationSettings(ServerReq...
    method groupVersion (line 118) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/AttachmentUcEndpoint.java
  class AttachmentUcEndpoint (line 55) | @Component
    method endpoint (line 72) | @Override
    method uploadAttachment (line 144) | private Mono<ServerResponse> uploadAttachment(ServerRequest request) {
    method listMyAttachments (line 168) | private Mono<ServerResponse> listMyAttachments(ServerRequest request) {
    class UcSearchRequest (line 180) | @Getter
      method UcSearchRequest (line 184) | public UcSearchRequest(ServerRequest request, String owner) {
      method toListOptions (line 190) | @Override
    method uploadFromUrlForPost (line 199) | private Mono<ServerResponse> uploadFromUrlForPost(ServerRequest reques...
    method createAttachmentForPost (line 224) | private Mono<ServerResponse> createAttachmentForPost(ServerRequest req...
    method waitForPermalink (line 248) | private Mono<Attachment> waitForPermalink(Mono<Attachment> createdAtta...
    method getPostSettingMono (line 263) | private Mono<SystemSetting.Post> getPostSettingMono() {
    method linkWith (line 275) | private Consumer<Attachment> linkWith(PostAttachmentRequest request) {
    method checkPostOwnership (line 291) | private Mono<Void> checkPostOwnership(Mono<PostAttachmentRequest> post...
    method getCurrentUser (line 303) | private Mono<String> getCurrentUser() {
    method groupVersion (line 309) | @Override
    method from (line 342) | public static PostAttachmentRequest from(MultiValueMap<String, Part> m...

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcPostEndpoint.java
  class UcPostEndpoint (line 38) | @Component
    method UcPostEndpoint (line 47) | public UcPostEndpoint(PostService postService, SnapshotService snapsho...
    method endpoint (line 52) | @Override
    method recycleMyPost (line 140) | private Mono<ServerResponse> recycleMyPost(ServerRequest request) {
    method getMyPostDraft (line 147) | private Mono<ServerResponse> getMyPostDraft(ServerRequest request) {
    method unpublishMyPost (line 165) | private Mono<ServerResponse> unpublishMyPost(ServerRequest request) {
    method publishMyPost (line 173) | private Mono<ServerResponse> publishMyPost(ServerRequest request) {
    method updateMyPostDraft (line 182) | private Mono<ServerResponse> updateMyPostDraft(ServerRequest request) {
    method updateMyPost (line 255) | private Mono<ServerResponse> updateMyPost(ServerRequest request) {
    method createMyPost (line 285) | private Mono<ServerResponse> createMyPost(ServerRequest request) {
    method getContent (line 302) | private Content getContent(Post post) {
    method listMyPost (line 312) | private Mono<ServerResponse> listMyPost(ServerRequest request) {
    method getMyPost (line 319) | private Mono<ServerResponse> getMyPost(ServerRequest request) {
    method getMyPost (line 325) | private Mono<Post> getMyPost(String postName) {
    method getCurrentUser (line 334) | private Mono<String> getCurrentUser() {
    method groupVersion (line 340) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcSnapshotEndpoint.java
  class UcSnapshotEndpoint (line 27) | @Component
    method UcSnapshotEndpoint (line 34) | public UcSnapshotEndpoint(PostService postService, SnapshotService sna...
    method endpoint (line 39) | @Override
    method getSnapshot (line 74) | private Mono<ServerResponse> getSnapshot(ServerRequest request) {
    method getCurrentUser (line 110) | private Mono<String> getCurrentUser() {
    method groupVersion (line 117) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UcUserPreferenceEndpoint.java
  class UcUserPreferenceEndpoint (line 40) | @Component
    method endpoint (line 52) | @Override
    method updateMyPreference (line 95) | private Mono<ServerResponse> updateMyPreference(ServerRequest serverRe...
    method getMyPreference (line 133) | private Mono<ServerResponse> getMyPreference(ServerRequest serverReque...
    method authenticated (line 145) | private Mono<Authentication> authenticated() {
    method groupVersion (line 154) | @Override

FILE: application/src/main/java/run/halo/app/core/endpoint/uc/UserConnectionEndpoint.java
  class UserConnectionEndpoint (line 27) | @Component
    method UserConnectionEndpoint (line 35) | public UserConnectionEndpoint(UserConnectionService connectionService) {
    method endpoint (line 39) | @Override
    method groupVersion (line 70) | @Override

FILE: application/src/main/java/run/halo/app/core/reconciler/AnnotationSettingReconciler.java
  class AnnotationSettingReconciler (line 21) | @Component
    method reconcile (line 27) | @Override
    method populateDefaultLabels (line 33) | private void populateDefaultLabels(String name) {
    method setupWith (line 48) | @Override

FILE: application/src/main/java/run/halo/app/core/reconciler/AuthProviderReconciler.java
  class AuthProviderReconciler (line 22) | @Component
    method reconcile (line 29) | @Override
    method setupWith (line 36) | @Override
    method handlePrivileged (line 43) | private void handlePrivileged(AuthProvider authProvider) {
    method privileged (line 50) | private boolean privileged(AuthProvider authProvider) {

FILE: application/src/main/java/run/halo/app/core/reconciler/CategoryReconciler.java
  class CategoryReconciler (line 35) | @Component
    method reconcile (line 47) | @Override
    method checkHiddenState (line 70) | private void checkHiddenState(Category category) {
    method refreshHiddenState (line 80) | private void refreshHiddenState(Category category, boolean hidden) {
    method publishHiddenStateChangeEvent (line 101) | private void publishHiddenStateChangeEvent(Category category) {
    method isHiddenStateChanged (line 108) | boolean isHiddenStateChanged(Category category) {
    method setupWith (line 113) | @Override
    method populatePermalinkPattern (line 120) | void populatePermalinkPattern(Category category) {
    method populatePermalink (line 128) | void populatePermalink(Category category) {
    method updateCategoryForPost (line 133) | private void updateCategoryForPost(String categoryName) {

FILE: application/src/main/java/run/halo/app/core/reconciler/CommentReconciler.java
  class CommentReconciler (line 47) | @Component
    method reconcile (line 59) | @Override
    method setupWith (line 93) | @Override
    method compatibleCreationTime (line 108) | void compatibleCreationTime(Comment comment) {
    method updateUnReplyCountIfNecessary (line 117) | private void updateUnReplyCountIfNecessary(Comment comment) {
    method updateSameSubjectRefCommentCounter (line 135) | private void updateSameSubjectRefCommentCounter(Comment comment) {
    method countTotalComments (line 163) | int countTotalComments(Ref commentSubjectRef) {
    method countApprovedComments (line 170) | int countApprovedComments(Ref commentSubjectRef) {
    method getBaseQuery (line 180) | private static Condition getBaseQuery(Ref commentSubjectRef) {
    method cleanUpResources (line 185) | private void cleanUpResources(Comment comment) {

FILE: application/src/main/java/run/halo/app/core/reconciler/MenuItemReconciler.java
  class MenuItemReconciler (line 22) | @Slf4j
    method MenuItemReconciler (line 28) | public MenuItemReconciler(ExtensionClient client) {
    method reconcile (line 32) | @Override
    method setupWith (line 65) | @Override
    method handleCategoryRef (line 72) | private Result handleCategoryRef(String menuItemName, MenuItemStatus s...
    method handleTagRef (line 84) | private Result handleTagRef(String menuItemName, MenuItemStatus status...
    method handlePostRef (line 94) | private Result handlePostRef(String menuItemName, MenuItemStatus statu...
    method handleSinglePageSpec (line 105) | private Result handleSinglePageSpec(String menuItemName, MenuItemStatu...
    method handleMenuSpec (line 117) | private Result handleMenuSpec(String menuItemName, MenuItemStatus stat...
    method updateStatus (line 126) | private void updateStatus(String menuItemName, MenuItemStatus status) {

FILE: application/src/main/java/run/halo/app/core/reconciler/PluginReconciler.java
  class PluginReconciler (line 87) | @Slf4j
    method destroy (line 112) | @Override
    method setClock (line 123) | void setClock(Clock clock) {
    method setScheduler (line 133) | void setScheduler(Scheduler scheduler) {
    method reconcile (line 138) | @Override
    method removeUnusedAnnotations (line 215) | private void removeUnusedAnnotations(Plugin plugin) {
    method checkDependents (line 222) | private boolean checkDependents(Plugin plugin) {
    method syncPluginState (line 247) | private void syncPluginState(Plugin plugin) {
    method requestToUnload (line 257) | private static String requestToUnload(Plugin plugin) {
    method requestToReload (line 265) | private static boolean requestToReload(Plugin plugin) {
    method removeRequestToReload (line 270) | private static void removeRequestToReload(Plugin plugin) {
    method cleanupResources (line 277) | private void cleanupResources(Plugin plugin) {
    method enablePlugin (line 308) | private Result enablePlugin(Plugin plugin) {
    method requestToReloadPluginsOptionallyDependentOn (line 412) | void requestToReloadPluginsOptionallyDependentOn(String pluginName) {
    method disablePlugin (line 431) | private Result disablePlugin(Plugin plugin) {
    method requestToEnable (line 483) | private static boolean requestToEnable(Plugin plugin) {
    method resolveStaticResources (line 488) | private Result resolveStaticResources(Plugin plugin) {
    method loadOrReload (line 545) | private Result loadOrReload(Plugin plugin) {
    method createOrUpdateSetting (line 644) | private Result createOrUpdateSetting(Plugin plugin) {
    method resolveLoadLocation (line 699) | private Result resolveLoadLocation(Plugin plugin) {
    method setupWith (line 823) | @Override
    method removeStartTaskIfPresent (line 831) | private void removeStartTaskIfPresent(String pluginName) {
    method createOrUpdateReverseProxy (line 842) | private Result createOrUpdateReverseProxy(Plugin plugin) {
    method isInDevEnvironment (line 870) | private boolean isInDevEnvironment() {
    method buildReverseProxyName (line 874) | static String buildReverseProxyName(String pluginName) {
    method requestToUnloadChildren (line 878) | private List<String> requestToUnloadChildren(String pluginName) {
    method cancelUnloadRequest (line 901) | private void cancelUnloadRequest(String pluginName) {
    method removeConditionBy (line 919) | private static void removeConditionBy(ConditionList conditions, String...
    class ConditionType (line 923) | public static class ConditionType {
    class ConditionReason (line 940) | public static class ConditionReason {

FILE: application/src/main/java/run/halo/app/core/reconciler/PostCounterReconciler.java
  class PostCounterReconciler (line 18) | @Component
    method reconcile (line 25) | @Override
    method setupWith (line 36) | @Override
    method isSameAsPost (line 47) | static boolean isSameAsPost(String name) {

FILE: application/src/main/java/run/halo/app/core/reconciler/PostReconciler.java
  class PostReconciler (line 85) | @Slf4j
    method reconcile (line 102) | @Override
    method computeHiddenState (line 208) | private void computeHiddenState(Post post) {
    method populateLabels (line 221) | private void populateLabels(Post post, Set<ApplicationEvent> events) {
    method shouldUnPublish (line 250) | private static boolean shouldUnPublish(Post post) {
    method setupWith (line 254) | @Override
    method schedulePublishIfNecessary (line 264) | void schedulePublishIfNecessary(Post post) {
    method subscribeNewCommentNotification (line 286) | void subscribeNewCommentNotification(Post post) {
    method publishPost (line 297) | private void publishPost(Post post, Set<ApplicationEvent> events) {
    method unPublishPost (line 346) | void unPublishPost(Post post, Set<ApplicationEvent> events) {
    method cleanUpResources (line 367) | private void cleanUpResources(Post post) {
    method getExcerpt (line 380) | private String getExcerpt(Post post) {
    method listTagDisplayNames (line 426) | private Set<String> listTagDisplayNames(Post post) {
    class DefaultExcerptGenerator (line 438) | static class DefaultExcerptGenerator implements ExcerptGenerator {
      method generate (line 439) | @Override
    method listSnapshots (line 447) | List<Snapshot> listSnapshots(Ref ref) {

FILE: application/src/main/java/run/halo/app/core/reconciler/ReplyReconciler.java
  class ReplyReconciler (line 28) | @Component
    method reconcile (line 38) | @Override
    method cleanUpResourcesAndRemoveFinalizer (line 71) | private void cleanUpResourcesAndRemoveFinalizer(String replyName) {
    method setupWith (line 83) | @Override

FILE: application/src/main/java/run/halo/app/core/reconciler/ReverseProxyReconciler.java
  class ReverseProxyReconciler (line 22) | @Component
    method ReverseProxyReconciler (line 28) | public ReverseProxyReconciler(ExtensionClient client,
    method reconcile (line 34) | @Override
    method setupWith (line 49) | @Override
    method registerReverseProxy (line 56) | private void registerReverseProxy(ReverseProxy reverseProxy) {
    method cleanUpResources (line 61) | private void cleanUpResources(ReverseProxy reverseProxy) {
    method addFinalizerIfNecessary (line 66) | private void addFinalizerIfNecessary(ReverseProxy oldReverseProxy) {
    method cleanUpResourcesAndRemoveFinalizer (line 83) | private void cleanUpResourcesAndRemoveFinalizer(String name) {
    method isDeleted (line 93) | private boolean isDeleted(ReverseProxy reverseProxy) {
    method getPluginId (line 97) | private String getPluginId(ReverseProxy reverseProxy) {

FILE: application/src/main/java/run/halo/app/core/reconciler/RoleReconciler.java
  class RoleReconciler (line 22) | @Slf4j
    method RoleReconciler (line 28) | public RoleReconciler(ExtensionClient client) {
    method reconcile (line 32) | @Override
    method setupWith (line 46) | @Override
    method updateLabelsAndAnnotations (line 53) | private void updateLabelsAndAnnotations(Role role) {

FILE: application/src/main/java/run/halo/app/core/reconciler/SinglePageReconciler.java
  class SinglePageReconciler (line 67) | @Slf4j
    method reconcile (line 83) | @Override
    method setupWith (line 107) | @Override
    method subscribeNewCommentNotification (line 114) | void subscribeNewCommentNotification(SinglePage page) {
    method reconcileSpec (line 125) | private void reconcileSpec(String name) {
    method publishPage (line 146) | private void publishPage(String name) {
    method unPublish (line 205) | private void unPublish(String name) {
    method publishFailed (line 227) | private void publishFailed(String name, Throwable error) {
    method cleanUpResources (line 255) | private void cleanUpResources(SinglePage singlePage) {
    method cleanUpResourcesAndRemoveFinalizer (line 269) | private void cleanUpResourcesAndRemoveFinalizer(String pageName) {
    method reconcileMetadata (line 279) | private void reconcileMetadata(String name) {
    method createPermalink (line 303) | String createPermalink(SinglePage page) {
    method reconcileStatus (line 309) | private void reconcileStatus(String name) {
    method getExcerpt (line 371) | private String getExcerpt(SinglePage singlePage) {
    class DefaultExcerptGenerator (line 408) | static class DefaultExce
Copy disabled (too large) Download .json
Condensed preview — 2670 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,757K chars).
[
  {
    "path": ".dockerignore",
    "chars": 15,
    "preview": "ui\n.github\n.git"
  },
  {
    "path": ".editorconfig",
    "chars": 22027,
    "preview": "root=true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = false\nmax_li"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.en.yml",
    "chars": 3159,
    "preview": "name: Bug Report\ndescription: File a bug report\nlabels: [bug]\nbody:\n  - type: checkboxes\n    id: preface\n    attributes:"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.zh.yml",
    "chars": 2209,
    "preview": "name: Bug 反馈\ndescription: 提交 Bug 反馈\nlabels: [bug]\nbody:\n  - type: checkboxes\n    id: preface\n    attributes:\n      label"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 255,
    "preview": "blank_issues_enabled: false\ncontact_links:\n  - name: 商业产品反馈\n    url: https://github.com/orgs/lxware-dev/discussions\n    "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.en.yml",
    "chars": 1639,
    "preview": "name: Feature Request\ndescription: File a feature request\nbody:\n  - type: checkboxes\n    id: preface\n    attributes:\n   "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.zh.yml",
    "chars": 1103,
    "preview": "name: 新特性建议\ndescription: 提交新特性建议\nbody:\n  - type: checkboxes\n    id: preface\n    attributes:\n      label: 前置条件\n      desc"
  },
  {
    "path": ".github/actions/docker-buildx-push/action.yaml",
    "chars": 3211,
    "preview": "name: \"Docker buildx and push\"\ndescription: \"Buildx and push the Docker image.\"\n\ninputs:\n  ghcr-token:\n    description: "
  },
  {
    "path": ".github/actions/setup-env/action.yaml",
    "chars": 905,
    "preview": "name: Setup Environment\ndescription: Setup environment to check and build Halo, including console and core projects.\n\nin"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 1998,
    "preview": "<!--  Thanks for sending a pull request!  Here are some tips for you:\n1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-d"
  },
  {
    "path": ".github/workflows/halo.yaml",
    "chars": 5415,
    "preview": "name: Halo Workflow\n\non:\n  pull_request:\n    branches:\n      - main\n      - release-*\n    paths:\n      - \"**\"\n      - \"!"
  },
  {
    "path": ".github/workflows/openapi-check.yaml",
    "chars": 1469,
    "preview": "name: OpenAPI Check\n\non:\n  pull_request:\n    branches:\n      - main\n      - release-*\n    paths:\n      - 'application/sr"
  },
  {
    "path": ".github/workflows/packages-preview-release.yaml",
    "chars": 656,
    "preview": "name: \"Packages preview release\"\non:\n  push:\n    paths:\n      - \"ui/packages/**\"\n    branches:\n      - main\n  pull_reque"
  },
  {
    "path": ".github/workflows/release-ui-packages.yaml",
    "chars": 525,
    "preview": "name: Release UI Packages\n\non:\n  release:\n    types:\n      - published\n\npermissions:\n  contents: write\n  id-token: write"
  },
  {
    "path": ".github/workflows/stale-issues.yaml",
    "chars": 1092,
    "preview": "name: Close Stale Issues\n\non:\n  schedule:\n    - cron: \"30 1 * * *\"\n  workflow_dispatch:\n\npermissions:\n  issues: write\n\nj"
  },
  {
    "path": ".gitignore",
    "chars": 1256,
    "preview": "### Maven\ntarget/\nlogs/\n!.mvn/wrapper/maven-wrapper.jar\n\n### Gradle\n.gradle\nbuild/\nout/\n!gradle/wrapper/gradle-wrapper.j"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5213,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 3491,
    "preview": "# Contributing Guide\n\nThank you for your interest in contributing to Halo.\n\nThis document explains the recommended workf"
  },
  {
    "path": "Dockerfile",
    "chars": 908,
    "preview": "FROM eclipse-temurin:21-jre as builder\n\nWORKDIR application\nARG JAR_FILE=application/build/libs/*.jar\nCOPY ${JAR_FILE} a"
  },
  {
    "path": "LICENSE",
    "chars": 35147,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "OWNERS",
    "chars": 50,
    "preview": "approvers:\n- ruibaby\n- guqing\n- JohnNiang\n- LIlGG\n"
  },
  {
    "path": "README.md",
    "chars": 4083,
    "preview": "<p align=\"center\">\n    <a href=\"https://www.halo.run\" target=\"_blank\" rel=\"noopener noreferrer\">\n        <img width=\"100"
  },
  {
    "path": "SECURITY.md",
    "chars": 1556,
    "preview": "# Security Policy\n\n## Supported Versions\n\nHalo currently supports the versions listed below, where as:\n\n- :white_check_m"
  },
  {
    "path": "api/build.gradle",
    "chars": 4381,
    "preview": "plugins {\n    id 'checkstyle'\n    id 'java-library'\n    id 'halo.publish'\n    id 'jacoco'\n    alias(libs.plugins.lombok)"
  },
  {
    "path": "api/src/main/java/run/halo/app/content/ContentWrapper.java",
    "chars": 1641,
    "preview": "package run.halo.app.content;\n\nimport lombok.Builder;\nimport lombok.Data;\nimport org.apache.commons.lang3.StringUtils;\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/content/ExcerptGenerator.java",
    "chars": 757,
    "preview": "package run.halo.app.content;\n\nimport java.util.Set;\nimport lombok.Data;\nimport lombok.experimental.Accessors;\nimport or"
  },
  {
    "path": "api/src/main/java/run/halo/app/content/PatchUtils.java",
    "chars": 3227,
    "preview": "package run.halo.app.content;\n\nimport com.fasterxml.jackson.core.type.TypeReference;\nimport com.github.difflib.DiffUtils"
  },
  {
    "path": "api/src/main/java/run/halo/app/content/PostContentService.java",
    "chars": 400,
    "preview": "package run.halo.app.content;\n\nimport reactor.core.publisher.Flux;\nimport reactor.core.publisher.Mono;\n\npublic interface"
  },
  {
    "path": "api/src/main/java/run/halo/app/content/comment/CommentSubject.java",
    "chars": 572,
    "preview": "package run.halo.app.content.comment;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run.ha"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/attachment/ThumbnailProvider.java",
    "chars": 1294,
    "preview": "package run.halo.app.core.attachment;\n\nimport java.net.URI;\nimport java.net.URL;\nimport lombok.Builder;\nimport lombok.Da"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/attachment/ThumbnailSize.java",
    "chars": 1502,
    "preview": "package run.halo.app.core.attachment;\n\nimport java.util.Arrays;\nimport java.util.Optional;\nimport lombok.Getter;\n\n@Gette"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/endpoint/WebSocketEndpoint.java",
    "chars": 640,
    "preview": "package run.halo.app.core.endpoint;\n\nimport org.springframework.web.reactive.socket.WebSocketHandler;\nimport run.halo.ap"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/AnnotationSetting.java",
    "chars": 1165,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/AuthProvider.java",
    "chars": 2655,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Counter.java",
    "chars": 1050,
    "preview": "package run.halo.app.core.extension;\n\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport run.halo.app.extension"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Device.java",
    "chars": 1824,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Menu.java",
    "chars": 1188,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/MenuItem.java",
    "chars": 2434,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Plugin.java",
    "chars": 4093,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/RememberMeToken.java",
    "chars": 1103,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/ReverseProxy.java",
    "chars": 855,
    "preview": "package run.halo.app.core.extension;\n\nimport java.util.List;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Role.java",
    "chars": 6513,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/RoleBinding.java",
    "chars": 4998,
    "preview": "package run.halo.app.core.extension;\n\nimport static run.halo.app.core.extension.RoleBinding.GROUP;\nimport static run.hal"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Setting.java",
    "chars": 1367,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/Theme.java",
    "chars": 3532,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_REQUIRED"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/User.java",
    "chars": 2381,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\nim"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/UserConnection.java",
    "chars": 1554,
    "preview": "package run.halo.app.core.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/Attachment.java",
    "chars": 2156,
    "preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/Constant.java",
    "chars": 890,
    "preview": "package run.halo.app.core.extension.attachment;\n\nimport run.halo.app.core.extension.attachment.endpoint.AttachmentHandle"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/Group.java",
    "chars": 1345,
    "preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/Policy.java",
    "chars": 1260,
    "preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/PolicyTemplate.java",
    "chars": 951,
    "preview": "package run.halo.app.core.extension.attachment;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.R"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/AttachmentHandler.java",
    "chars": 3151,
    "preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport java.net.URI;\nimport java.time.Duration;\nimport java.ut"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/DeleteOption.java",
    "chars": 349,
    "preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport run.halo.app.core.extension.attachment.Attachment;\nimpo"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/SimpleFilePart.java",
    "chars": 1180,
    "preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport java.nio.file.Path;\nimport org.springframework.core.io."
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/attachment/endpoint/UploadOption.java",
    "chars": 1020,
    "preview": "package run.halo.app.core.extension.attachment.endpoint;\n\nimport lombok.Builder;\nimport org.jspecify.annotations.Nullabl"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Category.java",
    "chars": 3971,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.NOT_"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Comment.java",
    "chars": 4780,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Constant.java",
    "chars": 523,
    "preview": "package run.halo.app.core.extension.content;\n\npublic enum Constant {\n    ;\n\n    public static final String GROUP = \"cont"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Post.java",
    "chars": 7311,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static java.lang.Boolean.parseBoolean;\n\nimport com.fasterxml.jackso"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Reply.java",
    "chars": 1548,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/SinglePage.java",
    "chars": 3607,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Snapshot.java",
    "chars": 2943,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/content/Tag.java",
    "chars": 2443,
    "preview": "package run.halo.app.core.extension.content;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQU"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/endpoint/CustomEndpoint.java",
    "chars": 529,
    "preview": "package run.halo.app.core.extension.endpoint;\n\nimport org.springframework.web.reactive.function.server.RouterFunction;\ni"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/endpoint/SortResolver.java",
    "chars": 977,
    "preview": "package run.halo.app.core.extension.endpoint;\n\nimport org.springframework.core.MethodParameter;\nimport org.springframewo"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/Notification.java",
    "chars": 1772,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/NotificationTemplate.java",
    "chars": 1826,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/NotifierDescriptor.java",
    "chars": 1684,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/Reason.java",
    "chars": 2091,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/ReasonType.java",
    "chars": 1642,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/notification/Subscription.java",
    "chars": 5129,
    "preview": "package run.halo.app.core.extension.notification;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/extension/service/AttachmentService.java",
    "chars": 4034,
    "preview": "package run.halo.app.core.extension.service;\n\nimport java.net.URI;\nimport java.net.URL;\nimport java.time.Duration;\nimpor"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/user/service/RoleService.java",
    "chars": 1416,
    "preview": "package run.halo.app.core.user.service;\n\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.Set;\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/user/service/SignUpData.java",
    "chars": 2391,
    "preview": "package run.halo.app.core.user.service;\n\nimport jakarta.validation.Constraint;\nimport jakarta.validation.ConstraintValid"
  },
  {
    "path": "api/src/main/java/run/halo/app/core/user/service/UserPostCreatingHandler.java",
    "chars": 499,
    "preview": "package run.halo.app.core.user.service;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run."
  },
  {
    "path": "api/src/main/java/run/halo/app/core/user/service/UserPreCreatingHandler.java",
    "chars": 507,
    "preview": "package run.halo.app.core.user.service;\n\nimport org.pf4j.ExtensionPoint;\nimport reactor.core.publisher.Mono;\nimport run."
  },
  {
    "path": "api/src/main/java/run/halo/app/core/user/service/UserService.java",
    "chars": 1647,
    "preview": "package run.halo.app.core.user.service;\n\nimport java.util.Collection;\nimport java.util.Set;\nimport reactor.core.publishe"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostDeletedEvent.java",
    "chars": 496,
    "preview": "package run.halo.app.event.post;\n\nimport run.halo.app.core.extension.content.Post;\nimport run.halo.app.plugin.SharedEven"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostEvent.java",
    "chars": 505,
    "preview": "package run.halo.app.event.post;\n\nimport org.springframework.context.ApplicationEvent;\n\n/**\n * An abstract class for pos"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostPublishedEvent.java",
    "chars": 247,
    "preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostPublishedEvent "
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostUnpublishedEvent.java",
    "chars": 251,
    "preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostUnpublishedEven"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostUpdatedEvent.java",
    "chars": 243,
    "preview": "package run.halo.app.event.post;\n\nimport run.halo.app.plugin.SharedEvent;\n\n@SharedEvent\npublic class PostUpdatedEvent ex"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/post/PostVisibleChangedEvent.java",
    "chars": 783,
    "preview": "package run.halo.app.event.post;\n\nimport org.springframework.lang.Nullable;\nimport run.halo.app.core.extension.content.P"
  },
  {
    "path": "api/src/main/java/run/halo/app/event/user/UserConnectionDisconnectedEvent.java",
    "chars": 643,
    "preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
  },
  {
    "path": "api/src/main/java/run/halo/app/event/user/UserLoginEvent.java",
    "chars": 462,
    "preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
  },
  {
    "path": "api/src/main/java/run/halo/app/event/user/UserLogoutEvent.java",
    "chars": 465,
    "preview": "package run.halo.app.event.user;\n\nimport lombok.Getter;\nimport org.springframework.context.ApplicationEvent;\nimport run."
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/AbstractExtension.java",
    "chars": 722,
    "preview": "package run.halo.app.extension;\n\nimport lombok.Data;\n\n/**\n * AbstractExtension contains basic structure of Extension and"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Comparators.java",
    "chars": 1297,
    "preview": "package run.halo.app.extension;\n\nimport java.time.Instant;\nimport java.util.Comparator;\n\npublic enum Comparators {\n    ;"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ConfigMap.java",
    "chars": 871,
    "preview": "package run.halo.app.extension;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport lombok.Data;\nimport lombok"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/DefaultExtensionMatcher.java",
    "chars": 2039,
    "preview": "package run.halo.app.extension;\n\nimport lombok.Builder;\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimp"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Extension.java",
    "chars": 669,
    "preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.Objects;\n\n/**\n * Extension is an interfac"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ExtensionClient.java",
    "chars": 3582,
    "preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Optional;\nimport j"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ExtensionMatcher.java",
    "chars": 134,
    "preview": "package run.halo.app.extension;\n\n@FunctionalInterface\npublic interface ExtensionMatcher {\n\n    boolean match(Extension e"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ExtensionOperator.java",
    "chars": 2322,
    "preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ExtensionUtil.java",
    "chars": 2742,
    "preview": "package run.halo.app.extension;\n\nimport static org.springframework.data.domain.Sort.Order.asc;\nimport static org.springf"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/GVK.java",
    "chars": 770,
    "preview": "package run.halo.app.extension;\n\nimport java.lang.annotation.ElementType;\nimport java.lang.annotation.Retention;\nimport "
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/GroupKind.java",
    "chars": 254,
    "preview": "package run.halo.app.extension;\n\n/**\n * GroupKind contains group and kind data only.\n *\n * @param group is group name of"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/GroupVersion.java",
    "chars": 1374,
    "preview": "package run.halo.app.extension;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/GroupVersionKind.java",
    "chars": 1929,
    "preview": "package run.halo.app.extension;\n\nimport org.springframework.util.Assert;\nimport org.springframework.util.StringUtils;\n\n/"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/JsonExtension.java",
    "chars": 8533,
    "preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.Json"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ListOptions.java",
    "chars": 5897,
    "preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.function.Function;\nimport lombok.Data;\nimport l"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ListResult.java",
    "chars": 5107,
    "preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Metadata.java",
    "chars": 1089,
    "preview": "package run.halo.app.extension;\n\nimport java.time.Instant;\nimport java.util.Map;\nimport java.util.Set;\nimport lombok.Dat"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/MetadataOperator.java",
    "chars": 3585,
    "preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/MetadataUtil.java",
    "chars": 1640,
    "preview": "package run.halo.app.extension;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport org.springframework.util.Assert;"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/PageRequest.java",
    "chars": 1878,
    "preview": "package run.halo.app.extension;\n\nimport org.springframework.data.domain.Sort;\nimport org.springframework.util.Assert;\n\n/"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/PageRequestImpl.java",
    "chars": 2654,
    "preview": "package run.halo.app.extension;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimport lombok.extern"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/ReactiveExtensionClient.java",
    "chars": 3564,
    "preview": "package run.halo.app.extension;\n\nimport java.util.Comparator;\nimport java.util.function.Predicate;\nimport org.springfram"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Ref.java",
    "chars": 2420,
    "preview": "package run.halo.app.extension;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Scheme.java",
    "chars": 3347,
    "preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.databind.node.ObjectNode;\nimport io.swagger.v3.core.conver"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/SchemeManager.java",
    "chars": 1712,
    "preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Secret.java",
    "chars": 1978,
    "preview": "package run.halo.app.extension;\n\nimport java.util.Map;\nimport lombok.Data;\nimport lombok.EqualsAndHashCode;\n\n/**\n * Secr"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Unstructured.java",
    "chars": 10861,
    "preview": "package run.halo.app.extension;\n\nimport com.fasterxml.jackson.core.JsonGenerator;\nimport com.fasterxml.jackson.core.Json"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/Watcher.java",
    "chars": 2523,
    "preview": "package run.halo.app.extension;\n\nimport java.util.List;\nimport java.util.concurrent.CopyOnWriteArrayList;\nimport reactor"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/WatcherExtensionMatchers.java",
    "chars": 2325,
    "preview": "package run.halo.app.extension;\n\nimport java.util.Objects;\nimport lombok.Builder;\nimport lombok.Getter;\nimport org.sprin"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/WatcherPredicates.java",
    "chars": 3418,
    "preview": "package run.halo.app.extension;\n\nimport java.util.function.BiPredicate;\nimport java.util.function.Predicate;\n\npublic cla"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/Controller.java",
    "chars": 171,
    "preview": "package run.halo.app.extension.controller;\n\nimport reactor.core.Disposable;\n\npublic interface Controller extends Disposa"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/ControllerBuilder.java",
    "chars": 4334,
    "preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.functi"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/DefaultController.java",
    "chars": 10550,
    "preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.concur"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/DefaultQueue.java",
    "chars": 4578,
    "preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.HashSe"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/ExtensionWatcher.java",
    "chars": 2046,
    "preview": "package run.halo.app.extension.controller;\n\nimport run.halo.app.extension.Extension;\nimport run.halo.app.extension.Watch"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/Reconciler.java",
    "chars": 522,
    "preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\n\npublic interface Reconciler<R> {\n\n    Result rec"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/RequestQueue.java",
    "chars": 2383,
    "preview": "package run.halo.app.extension.controller;\n\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.Object"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/RequestSynchronizer.java",
    "chars": 2728,
    "preview": "package run.halo.app.extension.controller;\n\nimport static org.springframework.data.domain.Sort.Direction.ASC;\n\nimport lo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/RequeueException.java",
    "chars": 671,
    "preview": "package run.halo.app.extension.controller;\n\nimport run.halo.app.extension.controller.Reconciler.Result;\n\n\n/**\n * Requeue"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/controller/Synchronizer.java",
    "chars": 153,
    "preview": "package run.halo.app.extension.controller;\n\nimport reactor.core.Disposable;\n\npublic interface Synchronizer<R> extends Di"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/exception/ExtensionException.java",
    "chars": 889,
    "preview": "package run.halo.app.extension.exception;\n\nimport org.springframework.http.HttpStatus;\nimport org.springframework.http.H"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/exception/NotImplementedException.java",
    "chars": 399,
    "preview": "package run.halo.app.extension.exception;\n\n/**\n * Exception thrown to indicate that the requested operation is not imple"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/exception/SchemeNotFoundException.java",
    "chars": 508,
    "preview": "package run.halo.app.extension.exception;\n\nimport org.springframework.http.HttpStatus;\nimport run.halo.app.extension.Gro"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/AbstractValueIndexSpecBuilder.java",
    "chars": 1163,
    "preview": "package run.halo.app.extension.index;\n\nimport org.springframework.util.Assert;\nimport run.halo.app.extension.Extension;\n"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/DefaultIndexAttribute.java",
    "chars": 1670,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Functi"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexAttribute.java",
    "chars": 1156,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport run.halo.app.extension.Extension;\n\n/**\n *\n * An attr"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexAttributeFactory.java",
    "chars": 1920,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.function.Functi"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexSpec.java",
    "chars": 2186,
    "preview": "package run.halo.app.extension.index;\n\nimport com.google.common.base.Objects;\nimport java.util.Set;\nimport lombok.Data;\n"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexSpecBuilder.java",
    "chars": 957,
    "preview": "package run.halo.app.extension.index;\n\nimport run.halo.app.extension.Extension;\n\n/**\n * Index specification builder.\n *\n"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexSpecs.java",
    "chars": 2181,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.List;\nimport run.halo.app.extension.Extension;\n\n/**\n * An interf"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/IndexedQueryEngine.java",
    "chars": 2196,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.List;\nimport org.springframework.data.domain.Sort;\nimport run.ha"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/KeyComparator.java",
    "chars": 5541,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Comparator;\nimport org.springframework.lang.Nullable;\n\n@Deprecat"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/MultiValueBuilder.java",
    "chars": 1737,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport java.util.function.Function;\nimport org.springframew"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpec.java",
    "chars": 654,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport org.springframework.lang.Nullable;\nimport run.halo.a"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/MultiValueIndexSpecBuilder.java",
    "chars": 680,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Set;\nimport java.util.function.Function;\nimport run.halo.app.ext"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/SingleValueBuilder.java",
    "chars": 1697,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.function.Function;\nimport org.springframework.util.Assert;\nimpor"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpec.java",
    "chars": 635,
    "preview": "package run.halo.app.extension.index;\n\nimport org.springframework.lang.Nullable;\nimport run.halo.app.extension.Extension"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/SingleValueIndexSpecBuilder.java",
    "chars": 657,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.function.Function;\nimport run.halo.app.extension.Extension;\n\n/**"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/UnknownKey.java",
    "chars": 943,
    "preview": "package run.halo.app.extension.index;\n\nimport java.util.Objects;\nimport org.jetbrains.annotations.NotNull;\nimport org.sp"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/ValueIndexSpec.java",
    "chars": 890,
    "preview": "package run.halo.app.extension.index;\n\nimport run.halo.app.extension.Extension;\n\n/**\n * Specification for a value index "
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/AllCondition.java",
    "chars": 347,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord AllCondition(String index"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/And.java",
    "chars": 610,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\n/**\n * This condition is only fo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/AndCondition.java",
    "chars": 581,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/BetweenCondition.java",
    "chars": 638,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord BetweenCondition(\n    Str"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/Condition.java",
    "chars": 1174,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.springframework.data.relational.core.sql.Visitable;\n\n/**\n * A co"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/EmptyCondition.java",
    "chars": 227,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord EmptyCondition() implemen"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/EqualCondition.java",
    "chars": 528,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/GreaterThanCondition.java",
    "chars": 464,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord GreaterThanCondition(Stri"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/InCondition.java",
    "chars": 699,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\nimport org"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/IndexCondition.java",
    "chars": 308,
    "preview": "package run.halo.app.extension.index.query;\n\n/**\n * Index condition interface for index-based queries.\n *\n * @author joh"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/IsNotNullCondition.java",
    "chars": 368,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord IsNotNullCondition(String"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/IsNullCondition.java",
    "chars": 363,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord IsNullCondition(String in"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelCondition.java",
    "chars": 390,
    "preview": "package run.halo.app.extension.index.query;\n\n/**\n * Label condition interface for label-based queries.\n *\n * @author joh"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelEqualsCondition.java",
    "chars": 443,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelEqualsCondition(Stri"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelExistsCondition.java",
    "chars": 402,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelExistsCondition(Stri"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelInCondition.java",
    "chars": 731,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport org.jetbrains.annotations.NotNull;\nimpo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotEqualsCondition.java",
    "chars": 445,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelNotEqualsCondition(S"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotExistsCondition.java",
    "chars": 406,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LabelNotExistsCondition(S"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LabelNotInCondition.java",
    "chars": 742,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport org.jetbrains.annotations.NotNull;\nimpo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/LessThanCondition.java",
    "chars": 464,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord LessThanCondition(String "
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/NoneCondition.java",
    "chars": 352,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord NoneCondition(String inde"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/NotBetweenCondition.java",
    "chars": 642,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord NotBetweenCondition(\n    "
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/NotCondition.java",
    "chars": 475,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/NotEqualCondition.java",
    "chars": 533,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/NotInCondition.java",
    "chars": 706,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.Collection;\nimport java.util.stream.Collectors;\nimport org"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/OrCondition.java",
    "chars": 578,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.springframework.util.A"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/Queries.java",
    "chars": 10252,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Colle"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/Query.java",
    "chars": 358,
    "preview": "package run.halo.app.extension.index.query;\n\n/**\n * A {@link Query} is used to build queries for searching indexed objec"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/QueryFactory.java",
    "chars": 6574,
    "preview": "package run.halo.app.extension.index.query;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.C"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringContainsCondition.java",
    "chars": 416,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringContainsCondition(S"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringEndsWithCondition.java",
    "chars": 414,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringEndsWithCondition(S"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringNotContainsCondition.java",
    "chars": 421,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotContainsConditio"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringNotEndsWithCondition.java",
    "chars": 418,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotEndsWithConditio"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringNotStartsWithCondition.java",
    "chars": 424,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringNotStartsWithCondit"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/index/query/StringStartsWithCondition.java",
    "chars": 420,
    "preview": "package run.halo.app.extension.index.query;\n\nimport org.jetbrains.annotations.NotNull;\n\nrecord StringStartsWithCondition"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/IListRequest.java",
    "chars": 3428,
    "preview": "package run.halo.app.extension.router;\n\nimport static org.springdoc.core.fn.builders.parameter.Builder.parameterBuilder;"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/QueryParamBuildUtil.java",
    "chars": 979,
    "preview": "package run.halo.app.extension.router;\n\nimport static org.springdoc.core.fn.builders.arrayschema.Builder.arraySchemaBuil"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/SortableRequest.java",
    "chars": 3585,
    "preview": "package run.halo.app.extension.router;\n\nimport static run.halo.app.extension.Comparators.compareCreationTimestamp;\nimpor"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/FieldSelector.java",
    "chars": 983,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Objects;\nimport org.springframework.lang.Nullable;\nimp"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/FieldSelectorConverter.java",
    "chars": 1652,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimpo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/LabelSelector.java",
    "chars": 3272,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.L"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/LabelSelectorConverter.java",
    "chars": 1672,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport static org.apache.commons.lang3.ObjectUtils.defaultIfNull;\n\nimpo"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/Operator.java",
    "chars": 3459,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Set;\nimport org.springframework.core.convert.converter"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorConverter.java",
    "chars": 845,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util."
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorCriteria.java",
    "chars": 159,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.Set;\n\npublic record SelectorCriteria(String key, Opera"
  },
  {
    "path": "api/src/main/java/run/halo/app/extension/router/selector/SelectorUtil.java",
    "chars": 1927,
    "preview": "package run.halo.app.extension.router.selector;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optio"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/AnonymousUserConst.java",
    "chars": 247,
    "preview": "package run.halo.app.infra;\n\npublic interface AnonymousUserConst {\n    String PRINCIPAL = \"anonymousUser\";\n\n    String R"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/BackupRootGetter.java",
    "chars": 243,
    "preview": "package run.halo.app.infra;\n\nimport java.nio.file.Path;\nimport java.util.function.Supplier;\n\n/**\n * Utility of getting b"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/Condition.java",
    "chars": 1889,
    "preview": "package run.halo.app.infra;\n\nimport static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;\n\nimport io."
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/ConditionList.java",
    "chars": 4457,
    "preview": "package run.halo.app.infra;\n\nimport java.util.AbstractCollection;\nimport java.util.Deque;\nimport java.util.Iterator;\nimp"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/ConditionStatus.java",
    "chars": 136,
    "preview": "package run.halo.app.infra;\n\n/**\n * @author guqing\n * @since 2.0.0\n */\npublic enum ConditionStatus {\n    TRUE,\n    FALSE"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/ExternalLinkProcessor.java",
    "chars": 1052,
    "preview": "package run.halo.app.infra;\n\nimport java.net.URI;\nimport org.springframework.http.HttpRequest;\nimport reactor.core.publi"
  },
  {
    "path": "api/src/main/java/run/halo/app/infra/ExternalUrlSupplier.java",
    "chars": 1150,
    "preview": "package run.halo.app.infra;\n\nimport java.net.URI;\nimport java.net.URL;\nimport java.util.function.Supplier;\nimport javax."
  }
]

// ... and 2470 more files (download for full content)

About this extraction

This page contains the full source code of the halo-dev/halo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 2670 files (10.5 MB), approximately 2.9M tokens, and a symbol index with 10096 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!