Full Code of linuxserver/fleet for AI

master f331c22cd833 cached
287 files
2.1 MB
574.3k tokens
1302 symbols
1 requests
Download .txt
Showing preview only (2,302K chars total). Download the full file or copy to clipboard to get everything.
Repository: linuxserver/fleet
Branch: master
Commit: f331c22cd833
Files: 287
Total size: 2.1 MB

Directory structure:
gitextract_h6oaxvsz/

├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── config/
│   ├── example.fleet.properties
│   ├── log4j2.local.xml
│   └── log4j2.release.xml
├── gradle/
│   └── wrapper/
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── io/
    │   │       └── linuxserver/
    │   │           └── fleet/
    │   │               ├── auth/
    │   │               │   ├── AuthenticatedUser.java
    │   │               │   ├── AuthenticationDelegate.java
    │   │               │   ├── AuthenticationResult.java
    │   │               │   ├── DefaultAuthenticationDelegate.java
    │   │               │   ├── UserCredentials.java
    │   │               │   ├── authenticator/
    │   │               │   │   ├── DefaultUserAuthenticator.java
    │   │               │   │   └── UserAuthenticator.java
    │   │               │   └── security/
    │   │               │       ├── PBKDF2PasswordEncoder.java
    │   │               │       ├── PasswordEncoder.java
    │   │               │       └── util/
    │   │               │           └── SaltGenerator.java
    │   │               ├── core/
    │   │               │   ├── AbstractAppController.java
    │   │               │   ├── BaseRuntimeLoader.java
    │   │               │   ├── FleetAppController.java
    │   │               │   ├── FleetRuntime.java
    │   │               │   ├── Main.java
    │   │               │   ├── PropertiesLoader.java
    │   │               │   ├── ServiceProvider.java
    │   │               │   ├── config/
    │   │               │   │   ├── AppProperties.java
    │   │               │   │   ├── DatabaseConnectionProperties.java
    │   │               │   │   ├── Version.java
    │   │               │   │   ├── VersionProperties.java
    │   │               │   │   └── WebConfiguration.java
    │   │               │   └── db/
    │   │               │       ├── DatabaseConnection.java
    │   │               │       ├── DatabaseProvider.java
    │   │               │       └── DefaultDatabaseProvider.java
    │   │               ├── db/
    │   │               │   ├── DefaultDatabaseConnection.java
    │   │               │   ├── PoolingDatabaseConnection.java
    │   │               │   ├── dao/
    │   │               │   │   └── Utils.java
    │   │               │   ├── migration/
    │   │               │   │   └── DatabaseVersion.java
    │   │               │   └── query/
    │   │               │       ├── InsertUpdateResult.java
    │   │               │       ├── InsertUpdateStatus.java
    │   │               │       ├── LimitOffset.java
    │   │               │       └── LimitedResult.java
    │   │               ├── dockerhub/
    │   │               │   ├── DockerHubException.java
    │   │               │   ├── model/
    │   │               │   │   ├── DockerHubV2Image.java
    │   │               │   │   ├── DockerHubV2ImageListResult.java
    │   │               │   │   ├── DockerHubV2NamespaceLookupResult.java
    │   │               │   │   ├── DockerHubV2ScanResult.java
    │   │               │   │   ├── DockerHubV2Tag.java
    │   │               │   │   ├── DockerHubV2TagDigest.java
    │   │               │   │   └── DockerHubV2TagListResult.java
    │   │               │   └── util/
    │   │               │       └── DockerTagFinder.java
    │   │               ├── exception/
    │   │               │   └── SaveException.java
    │   │               └── v2/
    │   │                   ├── LoggerOwner.java
    │   │                   ├── Utils.java
    │   │                   ├── cache/
    │   │                   │   ├── AbstractItemCache.java
    │   │                   │   ├── BasicItemCache.java
    │   │                   │   ├── ImageCache.java
    │   │                   │   ├── ItemCache.java
    │   │                   │   ├── RepositoryCache.java
    │   │                   │   └── ScheduleCache.java
    │   │                   ├── client/
    │   │                   │   ├── docker/
    │   │                   │   │   ├── AbstractDockerApiClient.java
    │   │                   │   │   ├── DockerApiClient.java
    │   │                   │   │   ├── DockerImageNotFoundException.java
    │   │                   │   │   ├── converter/
    │   │                   │   │   │   ├── AbstractDockerResponseConverter.java
    │   │                   │   │   │   └── DockerResponseConverter.java
    │   │                   │   │   ├── dockerhub/
    │   │                   │   │   │   ├── DockerHubApiClient.java
    │   │                   │   │   │   ├── DockerHubAuthenticator.java
    │   │                   │   │   │   ├── DockerHubCredentials.java
    │   │                   │   │   │   ├── DockerHubImageConverter.java
    │   │                   │   │   │   ├── DockerHubTagConverter.java
    │   │                   │   │   │   ├── IDockerHubAuthenticator.java
    │   │                   │   │   │   └── NoOpDockerHubAuthenticator.java
    │   │                   │   │   ├── github/
    │   │                   │   │   │   ├── GitHubContainerRegistryClient.java
    │   │                   │   │   │   ├── GitHubImageConverter.java
    │   │                   │   │   │   ├── GitHubTagConverter.java
    │   │                   │   │   │   └── model/
    │   │                   │   │   │       ├── GitHubImage.java
    │   │                   │   │   │       └── GitHubTag.java
    │   │                   │   │   └── queue/
    │   │                   │   │       ├── AsyncDockerApiRequest.java
    │   │                   │   │       ├── AsyncDockerApiResponse.java
    │   │                   │   │       ├── DockerApiDelegate.java
    │   │                   │   │       ├── DockerApiTaskConsumer.java
    │   │                   │   │       ├── DockerImageMissingUpdateResponse.java
    │   │                   │   │       ├── DockerImageUpdateRequest.java
    │   │                   │   │       ├── DockerImageUpdateResponse.java
    │   │                   │   │       └── TaskQueue.java
    │   │                   │   └── rest/
    │   │                   │       ├── HttpException.java
    │   │                   │       ├── RestClient.java
    │   │                   │       ├── RestResponse.java
    │   │                   │       ├── marshalling/
    │   │                   │       │   ├── JacksonMarshallingStrategy.java
    │   │                   │       │   └── MarshallingStrategy.java
    │   │                   │       └── proxy/
    │   │                   │           ├── LazyLoadPayloadProxy.java
    │   │                   │           └── PayloadProxy.java
    │   │                   ├── db/
    │   │                   │   ├── AbstractDAO.java
    │   │                   │   ├── DbUpdateStatus.java
    │   │                   │   ├── DefaultImageDAO.java
    │   │                   │   ├── DefaultScheduleDAO.java
    │   │                   │   ├── DefaultUserDAO.java
    │   │                   │   ├── ImageDAO.java
    │   │                   │   ├── ImageTemplateFactory.java
    │   │                   │   ├── ScheduleDAO.java
    │   │                   │   ├── UserDAO.java
    │   │                   │   └── Utils.java
    │   │                   ├── file/
    │   │                   │   └── FileManager.java
    │   │                   ├── key/
    │   │                   │   ├── AbstractDatabaseKey.java
    │   │                   │   ├── AbstractHasKey.java
    │   │                   │   ├── AbstractLookupKey.java
    │   │                   │   ├── AlertKey.java
    │   │                   │   ├── HasKey.java
    │   │                   │   ├── ImageKey.java
    │   │                   │   ├── ImageLookupKey.java
    │   │                   │   ├── Key.java
    │   │                   │   ├── RepositoryKey.java
    │   │                   │   ├── ScheduleKey.java
    │   │                   │   ├── TagBranchKey.java
    │   │                   │   └── UserKey.java
    │   │                   ├── service/
    │   │                   │   ├── AbstractAppService.java
    │   │                   │   ├── ImageService.java
    │   │                   │   ├── ScheduleService.java
    │   │                   │   ├── SynchronisationService.java
    │   │                   │   ├── UserService.java
    │   │                   │   └── util/
    │   │                   │       └── TemplateMerger.java
    │   │                   ├── thread/
    │   │                   │   ├── AbstractAppTask.java
    │   │                   │   ├── AbstractAppThread.java
    │   │                   │   ├── AbstractTaskQueueConsumer.java
    │   │                   │   ├── AsyncTask.java
    │   │                   │   ├── AsyncTaskDelegate.java
    │   │                   │   ├── AsyncTaskResponse.java
    │   │                   │   ├── TaskExecutionException.java
    │   │                   │   ├── TaskResponseControllerProxy.java
    │   │                   │   ├── ThreadStatus.java
    │   │                   │   └── schedule/
    │   │                   │       ├── AbstractAppSchedule.java
    │   │                   │       ├── AppSchedule.java
    │   │                   │       ├── CheckAppVersionSchedule.java
    │   │                   │       ├── ScheduleSpec.java
    │   │                   │       ├── TidyHistoricDataSchedule.java
    │   │                   │       ├── TimeWithUnit.java
    │   │                   │       ├── cache/
    │   │                   │       │   └── RefreshCacheSchedule.java
    │   │                   │       └── sync/
    │   │                   │           ├── AllImagesSyncSchedule.java
    │   │                   │           ├── CleanRemovedImagesSchedule.java
    │   │                   │           └── GetMissingImagesSchedule.java
    │   │                   ├── types/
    │   │                   │   ├── AbstractSyncItem.java
    │   │                   │   ├── AppAlert.java
    │   │                   │   ├── FilePathDetails.java
    │   │                   │   ├── HasSyncSpec.java
    │   │                   │   ├── Image.java
    │   │                   │   ├── ImageCountData.java
    │   │                   │   ├── Repository.java
    │   │                   │   ├── Tag.java
    │   │                   │   ├── TagBranch.java
    │   │                   │   ├── TagDigest.java
    │   │                   │   ├── User.java
    │   │                   │   ├── api/
    │   │                   │   │   ├── AbstractApiWrapper.java
    │   │                   │   │   ├── ApiImagePullHistoryWrapper.java
    │   │                   │   │   ├── ApiImageWrapper.java
    │   │                   │   │   ├── ApiRepositoryWrapper.java
    │   │                   │   │   ├── ApiScheduleWrapper.java
    │   │                   │   │   └── external/
    │   │                   │   │       ├── AllImagesExternalApiResponse.java
    │   │                   │   │       ├── ExternalApiImage.java
    │   │                   │   │       ├── ExternalApiResponse.java
    │   │                   │   │       └── templates/
    │   │                   │   │           ├── ApiDeviceTemplate.java
    │   │                   │   │           ├── ApiEnvTemplate.java
    │   │                   │   │           ├── ApiPortTemplate.java
    │   │                   │   │           ├── ApiTemplateHolder.java
    │   │                   │   │           └── ApiVolumeTemplate.java
    │   │                   │   ├── docker/
    │   │                   │   │   ├── DockerCapability.java
    │   │                   │   │   ├── DockerImage.java
    │   │                   │   │   ├── DockerTag.java
    │   │                   │   │   └── DockerTagManifestDigest.java
    │   │                   │   ├── internal/
    │   │                   │   │   ├── AbstractParamRequest.java
    │   │                   │   │   ├── ImageAppLogo.java
    │   │                   │   │   ├── ImageGeneralInfoUpdateRequest.java
    │   │                   │   │   ├── ImageOutlineRequest.java
    │   │                   │   │   ├── ImageTemplateRequest.java
    │   │                   │   │   ├── ImageUrlsUpdateRequest.java
    │   │                   │   │   ├── RepositoryOutlineRequest.java
    │   │                   │   │   ├── TagBranchOutlineRequest.java
    │   │                   │   │   └── UserOutlineRequest.java
    │   │                   │   └── meta/
    │   │                   │       ├── ExternalUrl.java
    │   │                   │       ├── ExternalUrlKey.java
    │   │                   │       ├── ImageCoreMeta.java
    │   │                   │       ├── ImageMetaData.java
    │   │                   │       ├── ItemSyncSpec.java
    │   │                   │       ├── history/
    │   │                   │       │   ├── ImagePullHistory.java
    │   │                   │       │   └── ImagePullStatistic.java
    │   │                   │       └── template/
    │   │                   │           ├── AbstractTemplateItem.java
    │   │                   │           ├── DeviceTemplateItem.java
    │   │                   │           ├── EnvironmentTemplateItem.java
    │   │                   │           ├── ImageTemplateHolder.java
    │   │                   │           ├── PortTemplateItem.java
    │   │                   │           ├── TemplateItem.java
    │   │                   │           └── VolumeTemplateItem.java
    │   │                   └── web/
    │   │                       ├── ApiException.java
    │   │                       ├── AppRole.java
    │   │                       ├── LocationUtils.java
    │   │                       ├── Locations.java
    │   │                       ├── PageModelAttributes.java
    │   │                       ├── PageModelSpec.java
    │   │                       ├── SessionAttributes.java
    │   │                       ├── WebRouteController.java
    │   │                       ├── freemarker/
    │   │                       │   ├── CustomFreemarkerTemplate.java
    │   │                       │   └── Java8DateTimeMethod.java
    │   │                       ├── request/
    │   │                       │   └── json/
    │   │                       │       ├── NewRepositoryRequest.java
    │   │                       │       ├── UpdateImageSpecRequest.java
    │   │                       │       └── UpdateRepositoryRequest.java
    │   │                       └── routes/
    │   │                           ├── AbstractPageHandler.java
    │   │                           ├── AdminImageController.java
    │   │                           ├── AdminImageEditController.java
    │   │                           ├── AdminRepositoryController.java
    │   │                           ├── AdminScheduleController.java
    │   │                           ├── AdminUserController.java
    │   │                           ├── DefaultAccessManager.java
    │   │                           ├── HomeController.java
    │   │                           ├── ImageController.java
    │   │                           ├── InternalApiController.java
    │   │                           ├── LegacyExternalApiController.java
    │   │                           └── LoginController.java
    │   └── resources/
    │       ├── db/
    │       │   └── migration/
    │       │       ├── V1.0__CreateTables.sql
    │       │       ├── V1.10__UpdateImageViewWithRepository.sql
    │       │       ├── V1.1__CreateSprocs.sql
    │       │       ├── V1.2__CreateUserTable.sql
    │       │       ├── V1.3__CreateUserSprocs.sql
    │       │       ├── V1.4__AddDeprecationFields.sql
    │       │       ├── V1.5__UpdateImageSprocs.sql
    │       │       ├── V1.6__ExtendVersionColumn.sql
    │       │       ├── V1.7__RemoveCoalesce.sql
    │       │       ├── V1.8__PullHistoryAndImageMeta.sql
    │       │       ├── V1.9__ExtraTagFields.sql
    │       │       ├── V2.0__CreateV2TablesAndSprocs.sql
    │       │       ├── V2.1__MigrateToNewTables.sql
    │       │       ├── V2.2__MetaDataTables.sql
    │       │       ├── V2.3__UpdateImageViewForCoreMeta.sql
    │       │       ├── V2.4__UpdateUserSprocs.sql
    │       │       ├── V2.5__BranchRemovalSproc.sql
    │       │       ├── V2.6__AddCleanSchedule.sql
    │       │       ├── V2.7__UpdateImageTemplateSprocs.sql
    │       │       └── V2.8__FixStoreCoreMetaOutputBug.sql
    │       ├── static/
    │       │   └── assets/
    │       │       ├── css/
    │       │       │   ├── app.css
    │       │       │   ├── bootstrap.css
    │       │       │   └── prism.css
    │       │       └── js/
    │       │           ├── admin.js
    │       │           ├── app.js
    │       │           ├── fontawesome-all.js
    │       │           ├── jquery.tablesorter.js
    │       │           └── prism.js
    │       ├── version.properties
    │       └── views/
    │           ├── pages/
    │           │   ├── admin/
    │           │   │   ├── image-edit.ftl
    │           │   │   ├── images.ftl
    │           │   │   ├── repositories.ftl
    │           │   │   ├── schedules.ftl
    │           │   │   ├── template-components/
    │           │   │   │   ├── image-template-devices.ftl
    │           │   │   │   ├── image-template-environment.ftl
    │           │   │   │   ├── image-template-misc.ftl
    │           │   │   │   ├── image-template-ports.ftl
    │           │   │   │   └── image-template-volumes.ftl
    │           │   │   └── users.ftl
    │           │   ├── error.ftl
    │           │   ├── home.ftl
    │           │   ├── image.ftl
    │           │   └── login.ftl
    │           ├── prebuilt/
    │           │   ├── base.ftl
    │           │   ├── docker-example.ftl
    │           │   ├── fleet-title.ftl
    │           │   ├── image-list-item.ftl
    │           │   ├── image-list-table-item.ftl
    │           │   └── system-alert.ftl
    │           └── ui/
    │               ├── components/
    │               │   ├── dropdown.ftl
    │               │   ├── message.ftl
    │               │   ├── modal.ftl
    │               │   ├── navbar.ftl
    │               │   └── pagination.ftl
    │               ├── elements/
    │               │   ├── box.ftl
    │               │   ├── button.ftl
    │               │   ├── display-field.ftl
    │               │   ├── media.ftl
    │               │   ├── notification.ftl
    │               │   ├── table.ftl
    │               │   └── tag.ftl
    │               ├── form/
    │               │   └── input.ftl
    │               └── layout/
    │                   ├── container.ftl
    │                   ├── footer.ftl
    │                   ├── hero.ftl
    │                   └── section.ftl
    └── test/
        └── java/
            └── io/
                └── linuxserver/
                    └── fleet/
                        ├── auth/
                        │   └── security/
                        │       └── PBKDF2PasswordEncoderTest.java
                        ├── dockerhub/
                        │   └── util/
                        │       └── DockerTagFinderTest.java
                        └── v2/
                            └── thread/
                                └── schedule/
                                    └── TimeWithUnitTest.java

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

================================================
FILE: .gitignore
================================================
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

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

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

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

.idea/
bin/
build/
out/
*.iml
config/fleet.properties
/config/fleet_static/*
src/main/resources/assets/js/all*.js
src/main/resources/assets/css/all*.css
src/main/resources/log4j2.xml
.gradle/

.classpath
.project
.settings/
.vscode/

**/.DS_Store


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

 Copyright (C) 2007 Free Software Foundation, Inc. <https://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 <https://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
<https://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
<https://www.gnu.org/licenses/why-not-lgpl.html>.


================================================
FILE: README.md
================================================
# Fleet

Fleet is a Docker Hub repository and image management tool for organisations (or individuals) who wish to display a list of all currently available images, along with their latest version and build status. The idea for this application was borne out of a necessity for the LinuxServer team to be able to provide a mechanism for its users to see the current build version of the images they use.

Image information is retrieved via the Docker Hub API (v2) through a scheduled task, which runs at a given (configurable) interval. This task will synchronise all repositories owned by the user whose credentials are used to authorise the initial requests to Docker Hub. Fleet will store in memory a valid authorisation token and will reuse it until it expires, after which a new token will be requested.

## Management

For administrators of the application, Fleet provides a way to manage which repositories get synchronised, and how each image's latest versioned tag should be masked.

### Repositories

All repositories for the user are automatically retrieved upon start up, and by default not synchronised. The administration page allows you to toggle which repositories are synchronised (and thus displayed on the main page).

#### Version Mask

Depending on how an image gets built, its versioned tag may contain extraneous information, or wrap the inner application's version with build information. If you wish to represent the image's "version" as the wrapped application's version instead, you can apply a version mask using standard REGEX, which will pull out the specific part of the tag you wish to used for the version. Multiple capture groups are supported, and will be concatenated in match order.

### Images

Each image in a repository is by default shown on the main page, along with their current version and build status (which is a manually set flag). When logged in, users are able to manually configure the visiblity and status of each image:

#### Version Mask

A specific version mask can be applied to an image, which will override the default repository mask (which applies to all images). Useful if a certain image uses different tagging standards.

## Documentation

Full documentation can be found here: https://docs.linuxserver.io/general/fleet

# Thanks
A huge thank you to JetBrains who kindly provided us with a license for IntelliJ Ultimate. It is without question the best IDE for Java application development.


================================================
FILE: build.gradle
================================================
plugins {
    id 'java'
}

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

version = '2.3.3'

dependencies {

    // Logging
    implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
    implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
    implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.19.0'

    // HTTP Framework
    implementation 'io.javalin:javalin:3.6.0'
    implementation 'org.freemarker:freemarker:2.3.31'
    implementation 'org.apache.httpcomponents:httpclient:4.5.13'

    // JSON Mapping/Marshalling
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.6'
    implementation 'com.fasterxml.jackson.core:jackson-core:2.9.6'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.6'

    // Database
    runtimeOnly    'org.mariadb.jdbc:mariadb-java-client:3.0.6'
    implementation 'org.flywaydb:flyway-core:8.2.0'
    implementation 'com.zaxxer:HikariCP:5.0.1'

    // MISC
    implementation 'org.apache.commons:commons-lang3:3.12.0'

    // Unit Testing
    testImplementation 'junit:junit:4.11'
    testImplementation 'org.mockito:mockito-core:4.8.0'
}

jar {

    manifest {
        attributes "Main-Class": "io.linuxserver.fleet.core.Main"
    }

    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }

    duplicatesStrategy = DuplicatesStrategy.INCLUDE

    exclude 'META-INF/INDEX.LIST', 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
}

task configureLogConfiguration(type: Copy) {

    def logFile = project.hasProperty('env') ? "${env}" : 'local'

    from "config/log4j2.${logFile}.xml"
    into 'src/main/resources'
    rename "log4j2.${logFile}.xml", 'log4j2.xml'
}

task buildVersionProperties() {

    doFirst {

        def versionProperties = new Properties()
        def propFile          = new File("src/main/resources/version.properties")

        versionProperties.load(propFile.newDataInputStream());
        versionProperties.setProperty("app.version", project.version.toString())
        versionProperties.setProperty("app.build.user", System.getProperty("user.name"))
        versionProperties.setProperty("app.build.date", new Date().format("yyyy-MM-dd'T'HH:mm:ss"))
        versionProperties.setProperty("app.build.os", System.getProperty("os.name"))

        versionProperties.store(propFile.newWriter(), null)
    }
}

processResources.dependsOn configureLogConfiguration, buildVersionProperties


================================================
FILE: config/example.fleet.properties
================================================
# This is an example properties file for Fleet.
# You should fill in your own values here and rename the file to "fleet.properties".

# Runtime
fleet.app.port=8080

# Database Connectivity
fleet.database.driver=org.mariadb.jdbc.Driver
fleet.database.url=jdbc:mariadb://<IP_OR_URL>:3306/fleet
fleet.database.username=<fleet_sql_user>
fleet.database.password=<fleet_sql_password>

# DockerHub auth
fleet.dockerhub.auth.enabled=true
fleet.dockerhub.username=YOUR_USERNAME
fleet.dockerhub.password=YOUR_PASSWORD_OR_AUTH_TOKEN


================================================
FILE: config/log4j2.local.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>

    <Appenders>

        <Console name="Console" target="SYSTEM_OUT" follow="true">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - [%t] - %5p - [%c{1}] - %msg%n" />
        </Console>

    </Appenders>

    <Loggers>

        <Logger name="io.linuxserver.fleet" level="INFO" additivity="false">
            <AppenderRef ref="Console" />
        </Logger>

        <Root level="info">
            <AppenderRef ref="Console" />
        </Root>

    </Loggers>

</Configuration>

================================================
FILE: config/log4j2.release.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>

    <Appenders>

        <RollingFile name="File" fileName="${sys:fleet.config.base}/logs/fleet.log" filePattern="${sys:fleet.config.base}/logs/${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} - %5p - [%c{1}] - %msg%n" />
            <Policies>
                <SizeBasedTriggeringPolicy size="50 MB" />
            </Policies>
        </RollingFile>

    </Appenders>

    <Loggers>

        <Logger name="io.linuxserver.fleet" level="info" additivity="false">
            <AppenderRef ref="File" />
        </Logger>

        <Root level="info">
            <AppenderRef ref="File" />
        </Root>

    </Loggers>

</Configuration>

================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradlew
================================================
#!/bin/sh

#
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

##############################################################################
#
#   Gradle start up script for POSIX generated by Gradle.
#
#   Important for running:
#
#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
#       noncompliant, but you have some other compliant shell such as ksh or
#       bash, then to run this script, type that shell name before the whole
#       command line, like:
#
#           ksh Gradle
#
#       Busybox and similar reduced shells will NOT work, because this script
#       requires all of these POSIX shell features:
#         * functions;
#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
#         * compound commands having a testable exit status, especially «case»;
#         * various built-in commands including «command», «set», and «ulimit».
#
#   Important for patching:
#
#   (2) This script targets any POSIX shell, so it avoids extensions provided
#       by Bash, Ksh, etc; in particular arrays are avoided.
#
#       The "traditional" practice of packing multiple parameters into a
#       space-separated string is a well documented source of bugs and security
#       problems, so this is (mostly) avoided, by progressively accumulating
#       options in "$@", and eventually passing that to Java.
#
#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
#       see the in-line comments for details.
#
#       There are tweaks for specific operating systems such as AIX, CygWin,
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################

# Attempt to set APP_HOME

# Resolve links: $0 may be a link
app_path=$0

# Need this for daisy-chained symlinks.
while
    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
    [ -h "$app_path" ]
do
    ls=$( ls -ld "$app_path" )
    link=${ls#*' -> '}
    case $link in             #(
      /*)   app_path=$link ;; #(
      *)    app_path=$APP_HOME$link ;;
    esac
done

APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

APP_NAME="Gradle"
APP_BASE_NAME=${0##*/}

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

warn () {
    echo "$*"
} >&2

die () {
    echo
    echo "$*"
    echo
    exit 1
} >&2

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$( uname )" in                #(
  CYGWIN* )         cygwin=true  ;; #(
  Darwin* )         darwin=true  ;; #(
  MSYS* | MINGW* )  msys=true    ;; #(
  NONSTOP* )        nonstop=true ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar


# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD=$JAVA_HOME/jre/sh/java
    else
        JAVACMD=$JAVA_HOME/bin/java
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD=java
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        ulimit -n "$MAX_FD" ||
            warn "Could not set maximum file descriptor limit to $MAX_FD"
    esac
fi

# Collect all arguments for the java command, stacking in reverse order:
#   * args from the command line
#   * the main class name
#   * -classpath
#   * -D...appname settings
#   * --module-path (only if needed)
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.

# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )

    JAVACMD=$( cygpath --unix "$JAVACMD" )

    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    for arg do
        if
            case $arg in                                #(
              -*)   false ;;                            # don't mess with options #(
              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
                    [ -e "$t" ] ;;                      #(
              *)    false ;;
            esac
        then
            arg=$( cygpath --path --ignore --mixed "$arg" )
        fi
        # Roll the args list around exactly as many times as the number of
        # args, so each arg winds up back in the position where it started, but
        # possibly modified.
        #
        # NB: a `for` loop captures its iteration list before it begins, so
        # changing the positional parameters here affects neither the number of
        # iterations, nor the values presented in `arg`.
        shift                   # remove old arg
        set -- "$@" "$arg"      # push replacement arg
    done
fi

# Collect all arguments for the java command;
#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
#     shell script including quotes and variable substitutions, so put them in
#     double quotes to make sure that they get re-expanded; and
#   * put everything else in single quotes, so that it's not re-expanded.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -classpath "$CLASSPATH" \
        org.gradle.wrapper.GradleWrapperMain \
        "$@"

# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
#   set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#

eval "set -- $(
        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
        xargs -n1 |
        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
        tr '\n' ' '
    )" '"$@"'

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem      https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem

@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto execute

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar


@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: settings.gradle
================================================
rootProject.name = 'fleet'

================================================
FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticatedUser.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth;

import io.linuxserver.fleet.v2.types.User;
import io.linuxserver.fleet.v2.web.AppRole;

import java.util.Collections;
import java.util.Set;

public class AuthenticatedUser {

    private final User user;

    public AuthenticatedUser(final User user) {
        this.user = user;
    }

    public final String getName() {
        return user.getUsername();
    }

    public final Set<AppRole> getRoles() {
        return Collections.singleton(user.getRole());
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticationDelegate.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth;

public interface AuthenticationDelegate {

    AuthenticationResult authenticate(String username, String password);

    String encodePassword(String rawPassword);
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticationResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth;

public class AuthenticationResult {

    private final boolean authenticated;
    private final AuthenticatedUser user;

    public AuthenticationResult(boolean authenticated, AuthenticatedUser user) {

        this.authenticated = authenticated;
        this.user = user;
    }

    public static AuthenticationResult notAuthenticated() {
        return new AuthenticationResult(false, null);
    }

    public boolean isAuthenticated() {
        return authenticated;
    }

    public AuthenticatedUser getUser() {
        return user;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/DefaultAuthenticationDelegate.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth;

import io.linuxserver.fleet.auth.authenticator.UserAuthenticator;
import io.linuxserver.fleet.auth.security.PasswordEncoder;

public class DefaultAuthenticationDelegate implements AuthenticationDelegate {

    private final UserAuthenticator authenticator;

    public DefaultAuthenticationDelegate(final UserAuthenticator authenticator) {
        this.authenticator   = authenticator;
    }

    @Override
    public AuthenticationResult authenticate(final String username, final String password) {
        return authenticator.authenticate(new UserCredentials(username, password));
    }

    @Override
    public String encodePassword(final String rawPassword) {
        return authenticator.getPasswordEncoder().encode(rawPassword);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/UserCredentials.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth;

public class UserCredentials {

    private final String username;
    private final String password;

    public UserCredentials(String username, String password) {

        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/authenticator/DefaultUserAuthenticator.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth.authenticator;

import io.linuxserver.fleet.auth.AuthenticatedUser;
import io.linuxserver.fleet.auth.AuthenticationResult;
import io.linuxserver.fleet.auth.UserCredentials;
import io.linuxserver.fleet.auth.security.PasswordEncoder;
import io.linuxserver.fleet.v2.service.UserService;
import io.linuxserver.fleet.v2.types.User;

public class DefaultUserAuthenticator implements UserAuthenticator {

    private final UserService     userService;
    private final PasswordEncoder passwordEncoder;

    public DefaultUserAuthenticator(final UserService userService,
                                    final PasswordEncoder passwordEncoder) {

        this.userService     = userService;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    public AuthenticationResult authenticate(final UserCredentials userCredentials) {

        final User user = userService.lookUpUser(userCredentials.getUsername());

        if (null != user && getPasswordEncoder().matches(userCredentials.getPassword(), user.getPassword())) {
            return new AuthenticationResult(true, new AuthenticatedUser(user));
        }

        return AuthenticationResult.notAuthenticated();
    }

    @Override
    public PasswordEncoder getPasswordEncoder() {
        return passwordEncoder;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/authenticator/UserAuthenticator.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth.authenticator;

import io.linuxserver.fleet.auth.AuthenticationResult;
import io.linuxserver.fleet.auth.UserCredentials;
import io.linuxserver.fleet.auth.security.PasswordEncoder;

/**
 * <p>
 * Provides a mechanism for the application to authenticate a login request
 * from a user.
 * </p>
 */
public interface UserAuthenticator {

    /**
     * <p>
     * Performs an authentication check against the provided credentials and the repository
     * of currently stored users.
     * </p>
     */
    AuthenticationResult authenticate(UserCredentials userCredentials);

    PasswordEncoder getPasswordEncoder();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/security/PBKDF2PasswordEncoder.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth.security;

import io.linuxserver.fleet.auth.security.util.SaltGenerator;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Base64;

/**
 * <p>
 * Uses the PBKDF2 crypto algorithm to encode and verify hashed passwords.
 * </p>
 */
public class PBKDF2PasswordEncoder implements PasswordEncoder {

    private static final int DEFAULT_HASH_WIDTH = 512;
    private static final int DEFAULT_ITERATIONS = 150051;

    private static final String PBKDF2 = "PBKDF2WithHmacSHA512";

    private final SaltGenerator saltGenerator = new SaltGenerator();

    private final byte[] secret;
    private final int hashWidth;
    private final int iterations;

    public PBKDF2PasswordEncoder(String secret) {
        this(secret, DEFAULT_HASH_WIDTH, DEFAULT_ITERATIONS);
    }

    public PBKDF2PasswordEncoder(String secret, int hashWidth, int iterations) {

        this.secret     = secret.getBytes(StandardCharsets.UTF_8);
        this.hashWidth  = hashWidth;
        this.iterations = iterations;
    }

    @Override
    public String encode(String rawPassword) {

        if (null == rawPassword) {
            throw new IllegalArgumentException("Password must not be null");
        }

        return toBase64(encode(rawPassword, saltGenerator.generateSalt()));
    }

    @Override
    public boolean matches(String rawPassword, String encodedPassword) {

        byte[] decodedHash  = fromBase64(encodedPassword);
        byte[] saltInHash   = extractSalt(decodedHash);
        byte[] hashToVerify = encode(rawPassword, saltInHash);

        return passwordsMatch(decodedHash, hashToVerify);
    }

    /**
     * <p>
     * Compares the two byte arrays by performing a bitwise equality check against each individual
     * element of both arrays.
     * </p>
     *
     * @implNote I looked at a couple of implementations for doing this, and I preferred how Spring had implemented it.
     */
    private boolean passwordsMatch(byte[] originalPassword, byte[] providedPassword) {

        if (originalPassword.length != providedPassword.length) {
            return false;
        }

        int result = 0;
        for (int i = 0; i < originalPassword.length; i++) {
            result |= originalPassword[i] ^ providedPassword[i];
        }

        return result == 0;
    }

    /**
     * <p>
     * Performs the cryptographic hash against the raw password and the randomly generated salt value. This
     * also concatenates the provided secret into the salt.
     * </p>
     */
    private byte[] encode(String rawPassword, byte[] salt) {

        try {

            PBEKeySpec spec = new PBEKeySpec(

                rawPassword.toCharArray(),
                joinArrays(salt, secret),
                iterations,
                hashWidth
            );

            return joinArrays(salt, SecretKeyFactory.getInstance(PBKDF2).generateSecret(spec).getEncoded());

        } catch (GeneralSecurityException e) {
            throw new IllegalStateException("Unable to create password hash", e);
        }
    }

    /**
     * <p>
     * Converts a byte array into a base-64 encoded string.
     * </p>
     */
    private String toBase64(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    /**
     * <p>
     * Converts a base64-encoded string into its raw byte value
     * </p>
     */
    private byte[] fromBase64(String input) {
        return Base64.getDecoder().decode(input);
    }

    /**
     * <p>
     * Obtains the specific bytes which represent the salt used in a previous hashed password. This is to
     * enable the comparision between the existing and new password.
     * </p>
     */
    private byte[] extractSalt(byte[] decodedHash) {
        return extractFromArray(decodedHash, 0, saltGenerator.getKeyLength());
    }

    /**
     * <p>
     * Combines two byte arrays together in order.
     * </p>
     */
    private byte[] joinArrays(byte[] first, byte[] second) {

        byte[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    /**
     * <p>
     * Extracts a sub-array from the provided array.
     * </p>
     */
    private byte[] extractFromArray(byte[] array, int begin, int end) {

        int length = end - begin;
        byte[] subarray = new byte[length];
        System.arraycopy(array, begin, subarray, 0, length);
        return subarray;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/security/PasswordEncoder.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth.security;

/**
 * <p>
 * Provides a mechanism for a password to be encoded using a strong cryptographic algorithm.
 * The general idea of this interface has been taken from Spring's own implementation of this.
 * <a href="https://docs.spring.io/spring-security/site/docs/4.2.4.RELEASE/apidocs/org/springframework/security/crypto/password/PasswordEncoder.html">PasswordEncoder</a>
 * </p>
 */
public interface PasswordEncoder {

    /**
     * <p>
     * Encodes the raw password into a one-way encrypted hash. The result of which should be stored.
     * </p>
     *
     * @param rawPassword
     *      The raw unencrypted password.
     *
     * @return
     *      The hashed result.
     */
    String encode(String rawPassword);

    /**
     * <p>
     * Determines if the provided raw password, when encoded, matches the stored encoded password.
     * </p>
     *
     * @param rawPassword
     *      The raw password to check
     * @param encodedPassword
     *      The originally encoded and stored password
     * @return
     *      true if the passwords match, false if not.
     */
    boolean matches(String rawPassword, String encodedPassword);
}


================================================
FILE: src/main/java/io/linuxserver/fleet/auth/security/util/SaltGenerator.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.auth.security.util;

import java.security.SecureRandom;

public class SaltGenerator {

    private static final int KEY_LENGTH = 16;

    public byte[] generateSalt() {

        SecureRandom sr = new SecureRandom();

        byte[] salt = new byte[KEY_LENGTH];
        sr.nextBytes(salt);

        return salt;
    }

    public int getKeyLength() {
        return KEY_LENGTH;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/AbstractAppController.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

import io.linuxserver.fleet.core.config.AppProperties;
import io.linuxserver.fleet.core.db.DatabaseProvider;
import io.linuxserver.fleet.core.db.DefaultDatabaseProvider;
import io.linuxserver.fleet.db.DefaultDatabaseConnection;
import io.linuxserver.fleet.v2.cache.BasicItemCache;
import io.linuxserver.fleet.v2.key.AlertKey;
import io.linuxserver.fleet.v2.types.AppAlert;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public abstract class AbstractAppController {

    private final AppProperties                      appProperties;
    private final DatabaseProvider                   databaseProvider;
    private final BasicItemCache<AlertKey, AppAlert> alertCache;

    public AbstractAppController() {

        this.appProperties    = new PropertiesLoader().getProperties();
        this.databaseProvider = new DefaultDatabaseProvider(new DefaultDatabaseConnection(appProperties.getDatabaseProperties()));
        this.alertCache       = new BasicItemCache<>();
    }

    public final DatabaseProvider getDatabaseProvider() {
        return databaseProvider;
    }

    public final AppProperties getAppProperties() {
        return appProperties;
    }

    public final List<AppAlert> getAlerts() {
        return new ArrayList<>(alertCache.getAllItems());
    }

    public final List<AppAlert> getSystemAlerts() {
        return getAlerts().stream().filter(AppAlert::isSystemAlert).collect(Collectors.toList());
    }

    public final void addAlert(final AppAlert appAlert) {
        alertCache.addItem(appAlert);
    }

    public final void clearAlert(final AlertKey alertKey) {
        alertCache.removeItem(alertKey);
    }

    protected void run() {

    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/BaseRuntimeLoader.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Prints out all runtime arguments passed in as JVM arguments (<i>-D</i>).
 * </p>
 *
 * @author Josh Stark
 */
abstract class BaseRuntimeLoader {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseRuntimeLoader.class);

    BaseRuntimeLoader() {

        LOGGER.info("Initalising...");
        LOGGER.info("Config base    : " + FleetRuntime.CONFIG_BASE);
        LOGGER.info("Show Passwords : " + FleetRuntime.SHOW_PASSWORDS);
        LOGGER.info("Nuke database  : " + FleetRuntime.NUKE_DATABASE);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/FleetAppController.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

import io.linuxserver.fleet.auth.AuthenticationResult;
import io.linuxserver.fleet.core.config.WebConfiguration;
import io.linuxserver.fleet.v2.client.docker.DockerApiClient;
import io.linuxserver.fleet.v2.client.docker.dockerhub.DockerHubApiClient;
import io.linuxserver.fleet.v2.client.docker.dockerhub.DockerHubAuthenticator;
import io.linuxserver.fleet.v2.client.docker.dockerhub.IDockerHubAuthenticator;
import io.linuxserver.fleet.v2.client.docker.dockerhub.NoOpDockerHubAuthenticator;
import io.linuxserver.fleet.v2.client.docker.queue.DockerApiDelegate;
import io.linuxserver.fleet.v2.client.rest.RestClient;
import io.linuxserver.fleet.v2.db.DefaultImageDAO;
import io.linuxserver.fleet.v2.db.DefaultScheduleDAO;
import io.linuxserver.fleet.v2.db.DefaultUserDAO;
import io.linuxserver.fleet.v2.file.FileManager;
import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.service.ImageService;
import io.linuxserver.fleet.v2.service.ScheduleService;
import io.linuxserver.fleet.v2.service.SynchronisationService;
import io.linuxserver.fleet.v2.service.UserService;
import io.linuxserver.fleet.v2.types.Image;
import io.linuxserver.fleet.v2.types.Repository;
import io.linuxserver.fleet.v2.types.internal.RepositoryOutlineRequest;
import io.linuxserver.fleet.v2.web.WebRouteController;

/**
 * <p>
 * Primary entry point for the application. All contexts and resources are loaded
 * through this class.
 * </p>
 */
public class FleetAppController extends AbstractAppController implements ServiceProvider {

    private final DockerApiDelegate      dockerApiDelegate;
    private final ImageService           imageService;
    private final ScheduleService        scheduleService;
    private final SynchronisationService syncService;
    private final UserService            userService;
    private final FileManager            fileManager;

    public FleetAppController() {

        fileManager       = new FileManager(this);
        imageService      = new ImageService(this, new DefaultImageDAO(getDatabaseProvider()));
        scheduleService   = new ScheduleService(this, new DefaultScheduleDAO(getDatabaseProvider()));
        dockerApiDelegate = new DockerApiDelegate(this, configureDockerApiClient());
        syncService       = new SynchronisationService(this);
        userService       = new UserService(this, new DefaultUserDAO(getDatabaseProvider()));
    }

    private static FleetAppController instance;

    public static FleetAppController instance() {

        if (null == instance) {

            synchronized (FleetAppController.class) {

                if (null == instance) {
                    instance = new FleetAppController();
                }
            }
        }

        return instance;
    }

    @Override
    protected final void run() {
        super.run();
        configureWeb();
        scheduleService.initialiseSchedules();
    }

    public final WebConfiguration getWebConfiguration() {
        return new WebConfiguration(getAppProperties());
    }

    private void configureWeb() {
        new WebRouteController(this);
    }

    public final void handleException(final Exception e) {

    }

    public final boolean synchroniseImage(final ImageKey imageKey) {
        return syncService.synchroniseImage(imageKey);
    }

    public final void synchroniseRepository(final Repository repository) {
        syncService.synchroniseCachedRepository(repository);
    }

    public final DockerApiDelegate getConfiguredDockerDelegate() {
        return dockerApiDelegate;
    }

    public final ImageService getImageService() {
        return imageService;
    }

    public final Image storeUpdatedImage(final Image updatedImage) {
        return imageService.storeImage(updatedImage);
    }

    @Override
    public ScheduleService getScheduleService() {
        return scheduleService;
    }

    public final Repository verifyRepositoryAndCreateOutline(final RepositoryOutlineRequest request) {

        if (getConfiguredDockerDelegate().isRepositoryValid(request.getRepositoryName())) {

            final Repository repositoryOutline = getImageService()
                    .createRepositoryOutline(new RepositoryOutlineRequest(request.getRepositoryName()));

            getSynchronisationService().synchroniseUpstreamRepository(repositoryOutline);
            return repositoryOutline;

        }

        throw new IllegalArgumentException("Repository " + request.getRepositoryName() + " does not exist upstream");
    }

    @Override
    public final SynchronisationService getSynchronisationService() {
        return syncService;
    }

    @Override
    public final UserService getUserService() {
        return userService;
    }

    @Override
    public FileManager getFileManager() {
        return fileManager;
    }

    public final AuthenticationResult authenticateCredentials(final String username, final String password) {
        return userService.authenticateCredentials(username, password);
    }

    public final void trackBranch(final ImageKey imageKey, final String branchName) {

        getImageService().trackBranchOnImage(imageKey, branchName);
        synchroniseImage(imageKey);
    }

    private DockerApiClient configureDockerApiClient() {

        final RestClient dockerHubApiRestClient = new RestClient();
        final IDockerHubAuthenticator dockerHubAuthenticator;
        if (getAppProperties().isDockerHubAuthEnabled()) {
            dockerHubAuthenticator = new DockerHubAuthenticator(getAppProperties().getDockerHubCredentials(), dockerHubApiRestClient);
        } else {
            dockerHubAuthenticator = new NoOpDockerHubAuthenticator();
        }
        return new DockerHubApiClient(dockerHubApiRestClient, dockerHubAuthenticator);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/FleetRuntime.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

public interface FleetRuntime {

    /**
     * If set will switch specific properties to allow more streamlined development
     */
    boolean DEV_MODE                = System.getProperty("enable.dev") != null;

    /**
     * Base directory for the config file.
     */
    String CONFIG_BASE              = System.getProperty("fleet.config.base");

    /**
     * Whether or not logs should show passwords
     */
    boolean SHOW_PASSWORDS          = System.getProperty("fleet.show.passwords") != null;

    /**
     * Tells Fleet to completely wipe the database and recreate it.
     */
    boolean NUKE_DATABASE           = System.getProperty("fleet.nuke.database") != null;
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/Main.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

public class Main {

    public static void main(String[] args) {
        FleetAppController.instance().run();
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/PropertiesLoader.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

import io.linuxserver.fleet.core.config.AppProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Objects;
import java.util.Properties;

/**
 * <p>
 * Loads in the application properties from disk. Properties must be provided as JVM arguments
 * as these will be used to create a connection to the underlying database, and any other
 * required connections.
 * </p>
 *
 * @author Josh Stark
 */
class PropertiesLoader extends BaseRuntimeLoader {

    private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesLoader.class);

    private final AppProperties properties;

    PropertiesLoader() {

        super();

        try {

            createConfigFileIfNotProvided();

            Properties properties = new Properties();
            properties.load(new FileInputStream(FleetRuntime.CONFIG_BASE + "/fleet.properties"));
            properties.load(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("version.properties")));
            properties.setProperty("fleet.static.dirname", "fleet_static");

            this.properties = new AppProperties(properties);

            printProperties();

            if (!createStaticFileDirectory() || !createLogsDirectory()) {
                throw new RuntimeException("Unable to create config sub directories for Fleet. Check permissions");
            }

        } catch (IOException e) {

            LOGGER.error("Unable to load config! Check JVM args and config directory", e);
            throw new RuntimeException(e);
        }
    }

    private void createConfigFileIfNotProvided() {

        try {

            File configFile = new File(FleetRuntime.CONFIG_BASE + "/fleet.properties");
            if (!configFile.exists()) {

                if (!configFile.createNewFile()) {
                    throw new RuntimeException("Unable to create base config for fleet.");
                }
            }

        } catch (IOException e) {
            throw new RuntimeException("Unable to create base config for fleet.", e);
        }
    }

    private boolean createStaticFileDirectory() {

        File staticFilesDir = new File(properties.getStaticFilesPath().toString());

        if (staticFilesDir.exists()) {
            return true;
        }

        return staticFilesDir.mkdir();
    }

    private boolean createLogsDirectory() {

        File logsDirectory = new File(FleetRuntime.CONFIG_BASE + "/logs");

        if (logsDirectory.exists()) {
            return true;
        }

        return logsDirectory.mkdir();
    }

    /**
     * <p>
     * The loaded properties, with accessible fields.
     * </p>
     *
     * @return
     *      All application properties.
     */
    AppProperties getProperties() {
        return properties;
    }

    /**
     * <p>
     * Prints out the loaded properties to the log. Useful when the application loads up for the first time.
     * </p>
     */
    private void printProperties() {

        LOGGER.info("fleet.app.port           : " + properties.getAppPort());
        LOGGER.info("fleet.database.url       : " + properties.getDatabaseProperties().getDatabaseUrl());
        LOGGER.info("fleet.database.username  : " + properties.getDatabaseProperties().getDatabaseUsername());
        LOGGER.info("fleet.database.password  : " + (showPasswords() ? properties.getDatabaseProperties().getDatabasePassword() : "***"));
        LOGGER.info("app.version              : " + getProperties().getVersionProperties());
    }

    /**
     * <p>
     * Ideally in a production environment you don't want to log passwords or keys.
     * </p>
     *
     * @return
     *      true if passwords can be logged to the terminal.
     */
    private boolean showPasswords() {
        return FleetRuntime.SHOW_PASSWORDS;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/ServiceProvider.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core;

import io.linuxserver.fleet.v2.file.FileManager;
import io.linuxserver.fleet.v2.service.ImageService;
import io.linuxserver.fleet.v2.service.ScheduleService;
import io.linuxserver.fleet.v2.service.SynchronisationService;
import io.linuxserver.fleet.v2.service.UserService;

public interface ServiceProvider {

    SynchronisationService getSynchronisationService();

    ImageService getImageService();

    ScheduleService getScheduleService();

    UserService getUserService();

    FileManager getFileManager();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/config/AppProperties.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.config;

import io.linuxserver.fleet.core.FleetRuntime;
import io.linuxserver.fleet.v2.client.docker.dockerhub.DockerHubCredentials;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;

public class AppProperties {

    private Properties properties;

    public AppProperties(final Properties properties) {
        this.properties = properties;
    }

    public DatabaseConnectionProperties getDatabaseProperties() {

        return new DatabaseConnectionProperties(getDatabaseDriverClassName(),
                                                getDatabaseUrl(),
                                                getDatabaseUsername(),
                                                getDatabasePassword());
    }

    public final VersionProperties getVersionProperties() {

        return new VersionProperties(getStringProperty("app.version"),
                                     getStringProperty("app.build.user"),
                                     getStringProperty("app.build.date"),
                                     getStringProperty("app.build.os"));
    }

    private String getDatabaseDriverClassName() {
        return getStringProperty("fleet.database.driver");
    }

    private String getDatabaseUrl() {
        return getStringProperty("fleet.database.url");
    }

    private String getDatabaseUsername() {
        return getStringProperty("fleet.database.username");
    }

    private String getDatabasePassword() {
        return getStringProperty("fleet.database.password");
    }

    public final Path getStaticFilesPath() {
        return Paths.get(FleetRuntime.CONFIG_BASE, getStringProperty("fleet.static.dirname")).toAbsolutePath();
    }

    public String getAppSecret() {

        String secret = getStringProperty("fleet.admin.secret");
        return null == secret ? "" : secret;
    }

    public int getAppPort() {
        return Integer.parseInt(getStringProperty("fleet.app.port"));
    }

    public boolean isDockerHubAuthEnabled() {
        return "true".equalsIgnoreCase(getStringProperty("fleet.dockerhub.auth.enabled"));
    }

    public DockerHubCredentials getDockerHubCredentials() {

        final String username = getStringProperty("fleet.dockerhub.username");
        final String password = getStringProperty("fleet.dockerhub.password");

        return new DockerHubCredentials(username, password);
    }

    /**
     * <p>
     * Obtains the property value from three separate sources: first from the config file. If not present, it will look
     * at the JVM runtime. If that is not present, it will finally check the system environment.
     * </p>
     */
    private String getStringProperty(String propertyKey) {

        String property = properties.getProperty(propertyKey);
        if (null == property) {

            property = System.getProperty(propertyKey);
            if (null == property) {
                property = System.getenv(propertyKey.replace(".", "_"));
            }
        }

        return property;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/config/DatabaseConnectionProperties.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.config;

public class DatabaseConnectionProperties {

    private final String driverClass;
    private final String url;
    private final String username;
    private final String password;

    public DatabaseConnectionProperties(final String driverClass,
                                        final String url,
                                        final String username,
                                        final String password) {
        this.driverClass = driverClass;
        this.url         = url;
        this.username    = username;
        this.password    = password;
    }

    public final String getDatabaseDriverClass() {
        return driverClass;
    }

    public final String getDatabaseUrl() {
        return url;
    }

    public final String getDatabaseUsername() {
        return username;
    }

    public final String getDatabasePassword() {
        return password;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/config/Version.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.config;

public class Version {

    private int major;
    private int minor;
    private int patch;

    public Version(int major, int minor, int patch) {

        this.major = major;
        this.minor = minor;
        this.patch = patch;
    }

    public Version(String version) {

        String[] bits = version.split("\\.");

        this.major = Integer.parseInt(bits[0]);
        this.minor = Integer.parseInt(bits[1]);
        this.patch = Integer.parseInt(bits[2]);
    }

    public int getMajor() {
        return major;
    }

    public int getMinor() {
        return minor;
    }

    public int getPatch() {
        return patch;
    }

    public boolean isNewerThan(Version version) {

        if (this.major > version.major) {
            return true;
        } if (this.minor > version.minor) {
            return true;
        } else if (this.minor < version.minor) {
            return false;
        }

        return this.patch > version.patch;
    }

    @Override
    public String toString() {
        return major + "." + minor + "." + patch;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/config/VersionProperties.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.config;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class VersionProperties {

    private final Version       version;
    private final String        buildUser;
    private final LocalDateTime buildDate;
    private final String        buildPlatform;

    public VersionProperties(final String version,
                             final String buildUser,
                             final String buildDate,
                             final String buildPlatform) {

        this.version       = new Version(version);
        this.buildUser     = buildUser;
        this.buildDate     = LocalDateTime.parse(buildDate, DateTimeFormatter.ISO_DATE_TIME);
        this.buildPlatform = buildPlatform;
    }

    public final Version getVersion() {
        return version;
    }

    public final String getBuildUser() {
        return buildUser;
    }

    public final LocalDateTime getBuildDate() {
        return buildDate;
    }

    public final String getBuildPlatform() {
        return buildPlatform;
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/config/WebConfiguration.java
================================================
/*
 * Copyright (c) 2019 Wallett
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.config;

public class WebConfiguration {

    private final AppProperties appProperties;

    public WebConfiguration(final AppProperties properties) {
        appProperties = properties;
    }

    public final int getPort() {
        return appProperties.getAppPort();
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/db/DatabaseConnection.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.db;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public interface DatabaseConnection  {

    DataSource getDataSource();

    Connection getConnection() throws SQLException;
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/db/DatabaseProvider.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.db;

import io.linuxserver.fleet.db.migration.DatabaseVersion;

public interface DatabaseProvider {

    DatabaseConnection getDatabaseConnection();

    DatabaseVersion getVersionHandler();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/core/db/DefaultDatabaseProvider.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.core.db;

import io.linuxserver.fleet.db.migration.DatabaseVersion;

public class DefaultDatabaseProvider implements DatabaseProvider {

    private final DatabaseConnection databaseConnection;
    private final DatabaseVersion    databaseVersion;

    public DefaultDatabaseProvider(final DatabaseConnection databaseConnection) {
        this.databaseConnection = databaseConnection;
        this.databaseVersion    = new DatabaseVersion(databaseConnection);
    }

    @Override
    public DatabaseConnection getDatabaseConnection() {
        return databaseConnection;
    }

    @Override
    public DatabaseVersion getVersionHandler() {
        return databaseVersion;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/DefaultDatabaseConnection.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db;

import io.linuxserver.fleet.core.config.DatabaseConnectionProperties;

public class DefaultDatabaseConnection extends PoolingDatabaseConnection {

    public DefaultDatabaseConnection(final DatabaseConnectionProperties properties) {
        super(properties);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/PoolingDatabaseConnection.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 LicensedatabaseConnection.getDataSource(
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db;

import com.zaxxer.hikari.HikariDataSource;
import io.linuxserver.fleet.core.config.DatabaseConnectionProperties;
import io.linuxserver.fleet.core.db.DatabaseConnection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public abstract class PoolingDatabaseConnection implements DatabaseConnection {

    private static final Logger LOGGER = LoggerFactory.getLogger(PoolingDatabaseConnection.class);

    private final HikariDataSource dataSource;

    PoolingDatabaseConnection(final DatabaseConnectionProperties properties) {

        dataSource = new HikariDataSource();
        dataSource.setDriverClassName(properties.getDatabaseDriverClass());
        dataSource.setJdbcUrl(properties.getDatabaseUrl());
        dataSource.setUsername(properties.getDatabaseUsername());
        dataSource.setPassword(properties.getDatabasePassword());

        LOGGER.info("DataSource established: " + dataSource.getJdbcUrl());
    }

    @Override
    public DataSource getDataSource() {
        return dataSource;
    }

    @Override
    public final Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/dao/Utils.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.dao;

import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDateTime;

class Utils {

    static void setNullableInt(CallableStatement call, int position, Integer value) throws SQLException {

        if (null == value)
            call.setNull(position, Types.INTEGER);

        else
            call.setInt(position, value);
    }

    static void setNullableLong(CallableStatement call, int position, Long value) throws SQLException {

        if (null == value)
            call.setNull(position, Types.BIGINT);

        else
            call.setLong(position, value);
    }

    static void setNullableString(CallableStatement call, int position, String value) throws SQLException {

        if (null == value)
            call.setNull(position, Types.VARCHAR);

        else
            call.setString(position, value);
    }

    static void setNullableTimestamp(CallableStatement call, int position, LocalDateTime localDateTime) throws SQLException {

        if (null == localDateTime) {
            call.setNull(position, Types.TIMESTAMP);
        } else {
            call.setTimestamp(position, Timestamp.valueOf(localDateTime));
        }
    }

    static void safeClose(CallableStatement call) {

        try {

            if (null != call)
                call.close();

        } catch (SQLException e) {
            throw new RuntimeException("Unable to close call", e);
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/migration/DatabaseVersion.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.migration;

import io.linuxserver.fleet.core.FleetRuntime;
import io.linuxserver.fleet.core.db.DatabaseConnection;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.FlywayException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Manages versioning of the database to ensure it is kept up-to-date
 * </p>
 */
public class DatabaseVersion {

    private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseVersion.class);

    private final Flyway flyway;

    public DatabaseVersion(final DatabaseConnection databaseConnection) {
        flyway = Flyway.configure().dataSource(databaseConnection.getDataSource()).load();
        migrate();
    }

    /**
     * <p>
     * Runs the migration process which runs any necessary scripts to get the database configured.
     * </p>
     */
    public void migrate() {

        try {

            if (FleetRuntime.NUKE_DATABASE) {
                flyway.clean();
            }

            flyway.migrate();

        } catch (FlywayException e) {

            LOGGER.error(e.getMessage());
            throw new RuntimeException("Unable to start application because the database has gone out of sync.", e);
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/query/InsertUpdateResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.query;

public class InsertUpdateResult<T> {

    private final T         result;
    private final int       status;
    private final String    statusMessage;

    public InsertUpdateResult(T result) {
        this(result, InsertUpdateStatus.OK, "OK");
    }

    public InsertUpdateResult(T result, int status, String statusMessage) {

        this.result = result;
        this.status = status;
        this.statusMessage = statusMessage;
    }

    public InsertUpdateResult(int status, String statusMessage) {
        this(null, status, statusMessage);
    }

    public final T getResult() {
        return result;
    }

    public final int getStatus() {
        return status;
    }

    public final String getStatusMessage() {
        return statusMessage;
    }

    public final boolean isError() {
        return status != InsertUpdateStatus.OK;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/query/InsertUpdateStatus.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.query;

public interface InsertUpdateStatus {

    int OK      = 0;
    int FAILED  = 1;
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/query/LimitOffset.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.query;

public class LimitOffset {

    private final int limit;
    private final int offset;

    public LimitOffset(int limit, int offset) {

        this.limit = limit;
        this.offset = offset;
    }

    public int getLimit() {
        return limit;
    }

    public int getOffset() {
        return offset;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/db/query/LimitedResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.db.query;

import java.util.List;

public class LimitedResult<T> {

    private final List<T>       results;
    private final LimitOffset   next;
    private final int           totalCount;

    public LimitedResult(List<T> results, int totalCount) {
        this(results, totalCount,null);
    }

    public LimitedResult(List<T> results, int totalCount, LimitOffset next) {

        this.results    = results;
        this.totalCount = totalCount;
        this.next       = next;
    }

    public List<T> getResults() {
        return results;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public LimitOffset getNext() {
        return next;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/DockerHubException.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub;

public class DockerHubException extends RuntimeException {

    public DockerHubException(String message) {
        super(message);
    }

    public DockerHubException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Image.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class DockerHubV2Image {

    @JsonProperty("user")
    private String user;

    @JsonProperty("name")
    private String name;

    @JsonProperty("namespace")
    private String namespace;

    @JsonProperty("description")
    private String description;

    @JsonProperty("star_count")
    private int starCount;

    @JsonProperty("pull_count")
    private long pullCount;

    @JsonProperty("last_updated")
    private String lastUpdated;

    public final String getUser() {
        return user;
    }

    public final String getName() {
        return name;
    }

    public final String getNamespace() {
        return namespace;
    }

    public String getDescription() {
        return description;
    }

    public final int getStarCount() {
        return starCount;
    }

    public final long getPullCount() {
        return pullCount;
    }

    public final String getLastUpdated() {
        return lastUpdated;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ImageListResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

public class DockerHubV2ImageListResult extends DockerHubV2ScanResult<DockerHubV2Image> {
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2NamespaceLookupResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.List;

public class DockerHubV2NamespaceLookupResult {

    @JsonProperty("namespaces")
    private List<String> namespaces = new ArrayList<>();

    public List<String> getNamespaces() {
        return namespaces;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ScanResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public class DockerHubV2ScanResult<T> {

    @JsonProperty("count")
    private int count;

    @JsonProperty("next")
    private String next;

    @JsonProperty("previous")
    private String previous;

    @JsonProperty("results")
    private List<T> results;

    public final int getCount() {
        return count;
    }

    public final String getNext() {
        return next;
    }

    public final String getPrevious() {
        return previous;
    }

    public final List<T> getResults() {
        return results;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Tag.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
import java.util.Objects;

public class DockerHubV2Tag {

    @JsonProperty("name")
    private String name;

    @JsonProperty("full_size")
    private long fullSize;

    @JsonProperty("last_updated")
    private String lastUpdated;

    @JsonProperty("images")
    private List<DockerHubV2TagDigest> images;

    public String getName() {
        return name;
    }

    public long getFullSize() {
        return fullSize;
    }

    public String getLastUpdated() {
        return lastUpdated;
    }

    public List<DockerHubV2TagDigest> getImages() {
        return images;
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, fullSize);
    }

    @Override
    public boolean equals(Object other) {

        if (!(other instanceof DockerHubV2Tag)) {
            return false;
        }

        if (other == this) {
            return true;
        }

        DockerHubV2Tag otherTag = (DockerHubV2Tag) other;
        return name.equals(otherTag.name) && fullSize == otherTag.fullSize;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagDigest.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

import com.fasterxml.jackson.annotation.JsonProperty;

public class DockerHubV2TagDigest {

    @JsonProperty("size")
    private long size;

    @JsonProperty("digest")
    private String digest;

    @JsonProperty("architecture")
    private String architecture;

    @JsonProperty("variant")
    private String variant;

    public long getSize() {
        return size;
    }

    public String getDigest() {
        return digest;
    }

    public String getArchitecture() {
        return architecture;
    }

    public String getVariant() {
        return variant;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagListResult.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.model;

public class DockerHubV2TagListResult extends DockerHubV2ScanResult<DockerHubV2Tag> {
}


================================================
FILE: src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.dockerhub.util;

import io.linuxserver.fleet.v2.types.docker.DockerTag;
import io.linuxserver.fleet.v2.types.docker.DockerTagManifestDigest;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class DockerTagFinder {

    public static DockerTag findVersionedTagMatchingBranch(List<DockerTag> tags, String namedBranch) {

        Optional<DockerTag> tagBranchName = tags.stream().filter(tag -> namedBranch.equals(tag.getName())).findFirst();

        if (tagBranchName.isPresent()) {

            DockerTag namedTagForBranch = tagBranchName.get();
            Optional<DockerTag> versionedLatestTag = tags.stream()
                .filter(tag -> !tag.equals(namedTagForBranch) && allManifestsMatch(namedTagForBranch, tag)).findFirst();

            return versionedLatestTag.orElse(namedTagForBranch);
        }

        return tags.isEmpty() ? null : tags.get(0);
    }

    private static boolean allManifestsMatch(final DockerTag namedTag, final DockerTag toCheck) {

        final List<DockerTagManifestDigest> namedDigests   = namedTag.getDigests();
        final List<DockerTagManifestDigest> digestsToCheck = toCheck.getDigests();

        boolean allMatch = true;

        if (namedDigests.size() == digestsToCheck.size()) {

            final Map<String, String> namedDigestsAsMap = toMapKeyedByArch(namedDigests);

            for (DockerTagManifestDigest digestToCheck : digestsToCheck) {

                final String archPlusVariant = digestToCheck.getArchitecture() + digestToCheck.getArchVariant();
                final String foundDigest     = namedDigestsAsMap.get(archPlusVariant);

                allMatch = allMatch && (null != foundDigest) && foundDigest.equals(digestToCheck.getDigest());
            }

        } else {
            allMatch = false;
        }

        return allMatch;
    }

    private static Map<String, String> toMapKeyedByArch(final List<DockerTagManifestDigest> initialList) {

        final Map<String, String> map = new HashMap<>();
        for (DockerTagManifestDigest digest : initialList) {
            map.put(digest.getArchitecture() + digest.getArchVariant(), digest.getDigest());
        }
        return map;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/exception/SaveException.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.exception;

public class SaveException extends Exception {

    public SaveException(String message) {
        super(message);
    }

    public SaveException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/LoggerOwner.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2;

import org.slf4j.Logger;

public interface LoggerOwner {

    Logger getLogger();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/Utils.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2;

public final class Utils {

    public static <T> T ensureNotNull(final T obj) {

        if (null == obj) {
            throw new IllegalArgumentException("Parameter null");
        }

        return obj;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/AbstractItemCache.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.HasKey;
import io.linuxserver.fleet.v2.key.Key;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

public abstract class AbstractItemCache<KEY extends Key, ITEM extends HasKey<KEY>> implements ItemCache<KEY, ITEM> {

    private final Logger LOGGER = LoggerFactory.getLogger(getClass());

    private final List<ItemCacheListener<ITEM>> listeners;
    private final Map<KEY, ITEM>                items;

    public AbstractItemCache() {

        listeners = new ArrayList<>();
        items     = new HashMap<>();
    }

    public final void clear() {

        LOGGER.info("Emptying cache");
        items.clear();
    }

    public final void registerCacheListener(final ItemCacheListener<ITEM> listener) {

        LOGGER.info("Registering new cache listener {}", listener);
        listeners.add(listener);
    }

    @Override
    public final void addItem(final ITEM item) {

        final ITEM original = items.get(item.getKey());
        final ITEM cached   = items.put(item.getKey(), item);

        LOGGER.info("Item {} cached", item);
        if (null == original) {
            listeners.forEach(l -> l.onItemAdded(cached));
        } else {
            listeners.forEach(l -> l.onItemUpdated(original, cached));
        }
    }

    @Override
    public boolean isEmpty() {
        return items.isEmpty();
    }

    @Override
    public final ITEM findItem(final KEY key) {
        return items.get(key);
    }

    @Override
    public final void removeItem(final KEY key) {

        final ITEM removed = items.remove(key);

        LOGGER.info("Item {} removed from cache", removed);
        listeners.forEach(l -> l.onItemRemoved(removed));
    }

    @Override
    public final boolean isItemCached(final KEY key) {
        return items.containsKey(key);
    }

    @Override
    public Collection<ITEM> getAllItems() {
        return items.values();
    }

    @Override
    public final void addAllItems(Collection<ITEM> allItems) {
        allItems.forEach(this::addItem);
    }

    @Override
    public int size() {
        return items.size();
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/BasicItemCache.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.HasKey;
import io.linuxserver.fleet.v2.key.Key;

public final class BasicItemCache<KEY extends Key, ITEM extends HasKey<KEY>> extends AbstractItemCache<KEY, ITEM> {
    // Default implementation
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/ImageCache.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.types.Image;

public class ImageCache extends AbstractItemCache<ImageKey, Image> {
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/ItemCache.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.HasKey;
import io.linuxserver.fleet.v2.key.Key;

import java.util.Collection;

public interface ItemCache<KEY extends Key, ITEM extends HasKey<KEY>> {

    boolean isEmpty();

    void addItem(ITEM item);

    ITEM findItem(KEY key);

    void removeItem(KEY key);

    boolean isItemCached(KEY key);

    Collection<ITEM> getAllItems();

    void addAllItems(Collection<ITEM> items);

    int size();

    interface ItemCacheListener<ITEM> {

        void onItemAdded(final ITEM item);
        void onItemUpdated(final ITEM oldItem, final ITEM newItem);
        void onItemRemoved(final ITEM item);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/RepositoryCache.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.key.ImageLookupKey;
import io.linuxserver.fleet.v2.key.RepositoryKey;
import io.linuxserver.fleet.v2.types.Image;
import io.linuxserver.fleet.v2.types.Repository;

public class RepositoryCache extends AbstractItemCache<RepositoryKey, Repository> {

    public final Image lookupImage(final ImageLookupKey lookupKey) {

        for (Repository repository : getAllItems()) {
            for (Image image : repository.getImages()) {
                if (lookupKey.isLookupKeyFor(image)) {
                    return image;
                }
            }
        }

        return null;
    }

    public final Image findImage(final ImageKey imageKey) {

        if (isItemCached(imageKey.getRepositoryKey())) {

            final Repository repository = findItem(imageKey.getRepositoryKey());
            for (Image image : repository.getImages()) {

                if (imageKey.equals(image.getKey())) {
                    return image;
                }
            }
        }

        return null;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/cache/ScheduleCache.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.cache;

import io.linuxserver.fleet.v2.key.ScheduleKey;
import io.linuxserver.fleet.v2.thread.schedule.AppSchedule;

public class ScheduleCache extends AbstractItemCache<ScheduleKey, AppSchedule> {

    public final boolean isScheduleRunning(final ScheduleKey scheduleKey) {
        return isItemCached(scheduleKey);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/AbstractDockerApiClient.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker;

import io.linuxserver.fleet.v2.client.docker.converter.DockerResponseConverter;
import io.linuxserver.fleet.v2.types.docker.DockerImage;
import io.linuxserver.fleet.v2.types.docker.DockerTag;

import java.util.List;
import java.util.stream.Collectors;

public abstract class AbstractDockerApiClient<D, T, IC extends DockerResponseConverter<D, DockerImage>, TC extends DockerResponseConverter<T, DockerTag>> implements DockerApiClient {

    private final IC imageConverter;
    private final TC tagConverter;

    public AbstractDockerApiClient(final IC imageConverter, final TC tagConverter) {
        this.imageConverter = imageConverter;
        this.tagConverter   = tagConverter;
    }

    @Override
    public final DockerImage fetchImage(String imageName) {

        final D dockerModel = fetchImageFromApi(imageName);
        if (null == dockerModel) {
            return null;
        }
        return imageConverter.convert(dockerModel);
    }

    @Override
    public final List<DockerImage> fetchAllImages(String repositoryName) {
        return fetchAllImagesFromApi(repositoryName).stream().map(imageConverter::convert).collect(Collectors.toList());
    }

    @Override
    public final List<DockerTag> fetchImageTags(String imageName) {
        return fetchTagsFromApi(imageName).stream().map(tagConverter::convert).collect(Collectors.toList());
    }

    protected abstract D       fetchImageFromApi(final String imageName);
    protected abstract List<D> fetchAllImagesFromApi(final String repositoryName);
    protected abstract List<T> fetchTagsFromApi(final String imageName);
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/DockerApiClient.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker;

import io.linuxserver.fleet.v2.types.docker.DockerImage;
import io.linuxserver.fleet.v2.types.docker.DockerTag;

import java.util.List;

public interface DockerApiClient {

    boolean isRepositoryValid(final String repositoryName);

    DockerImage fetchImage(final String imageName);

    List<DockerImage> fetchAllImages(final String repositoryName);

    List<DockerTag> fetchImageTags(final String imageName);
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/DockerImageNotFoundException.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker;

public class DockerImageNotFoundException extends RuntimeException {

    public DockerImageNotFoundException(final String reason) {
        super(reason);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/converter/AbstractDockerResponseConverter.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.converter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDateTime;
import java.time.format.DateTimeParseException;

public abstract class AbstractDockerResponseConverter<D, I> implements DockerResponseConverter<D, I> {

    private final Logger LOGGER = LoggerFactory.getLogger(getClass());

    @Override
    public final I convert(final D dockerModel) {

        try {

            if (null == dockerModel) {
                LOGGER.warn("Attempted to convert null image");
            } else {
                return doPlainConvert(dockerModel);
            }

        } catch (Exception e) {
            LOGGER.error("Unable to convert docker model to internal.", e);
        }

        return null;
    }

    protected abstract I doPlainConvert(final D dockerApiImage);

    protected final LocalDateTime parseDockerHubDate(String date) {

        if (null == date) {
            return null;
        }

        try {

            final String dateToParse = (date.endsWith("Z") ? date.substring(0, date.length() - 1) : date);
            return LocalDateTime.parse(dateToParse);

        } catch (DateTimeParseException e) {

            LOGGER.error("parseDockerHubDate(" + date + ") unable to leniently parse date.", e);
            return null;
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/converter/DockerResponseConverter.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.converter;

public interface DockerResponseConverter<DOCKER_MODEL, INTERNAL_MODEL> {

    INTERNAL_MODEL convert(final DOCKER_MODEL dockerModel);

    Class<DOCKER_MODEL> getConverterClass();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubApiClient.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.dockerhub;

import io.linuxserver.fleet.dockerhub.DockerHubException;
import io.linuxserver.fleet.dockerhub.model.DockerHubV2Image;
import io.linuxserver.fleet.dockerhub.model.DockerHubV2ImageListResult;
import io.linuxserver.fleet.dockerhub.model.DockerHubV2Tag;
import io.linuxserver.fleet.dockerhub.model.DockerHubV2TagListResult;
import io.linuxserver.fleet.v2.Utils;
import io.linuxserver.fleet.v2.client.docker.AbstractDockerApiClient;
import io.linuxserver.fleet.v2.client.rest.HttpException;
import io.linuxserver.fleet.v2.client.rest.RestClient;
import io.linuxserver.fleet.v2.client.rest.RestResponse;

import java.util.ArrayList;
import java.util.List;

public class DockerHubApiClient extends AbstractDockerApiClient<DockerHubV2Image, DockerHubV2Tag, DockerHubImageConverter, DockerHubTagConverter> {

    public static final String  DockerHubApiUrl = "https://hub.docker.com/v2";
    private static final int    DefaultPageSize = 1000;

    private final RestClient              restClient;
    private final IDockerHubAuthenticator authenticator;

    public DockerHubApiClient(final RestClient restClient,
                              final IDockerHubAuthenticator authenticator) {
        super(new DockerHubImageConverter(), new DockerHubTagConverter());
        this.restClient    = Utils.ensureNotNull(restClient);
        this.authenticator = Utils.ensureNotNull(authenticator);
    }

    @Override
    public final boolean isRepositoryValid(String repositoryName) {

        try {
            return !fetchAllImages(repositoryName).isEmpty();
        } catch (HttpException e) {
            throw new DockerHubException("Unable to verify repository " + repositoryName, e);
        }
    }

    @Override
    protected final DockerHubV2Image fetchImageFromApi(String imageName) {

        try {

            final  String absoluteUrl = DockerHubApiUrl + "/repositories/" + imageName + "/";

            final RestResponse<DockerHubV2Image> restResponse = doCall(absoluteUrl, DockerHubV2Image.class);

            if (isResponseOK(restResponse)) {
                return restResponse.getPayload();
            }

            return null;

        } catch (HttpException e) {
            throw new DockerHubException("Unable to get images for " + imageName, e);
        }
    }

    @Override
    protected final List<DockerHubV2Image> fetchAllImagesFromApi(String repositoryName) {

        final List<DockerHubV2Image> images = new ArrayList<>();

        try {

            String url = DockerHubApiUrl + "/repositories/" + repositoryName + "/?page_size=" + DefaultPageSize;
            while (url != null) {

                final RestResponse<DockerHubV2ImageListResult> response = doCall(url, DockerHubV2ImageListResult.class);

                if (isResponseOK(response)) {

                    DockerHubV2ImageListResult payload = response.getPayload();
                    images.addAll(payload.getResults());

                    url = payload.getNext();
                }
            }

            return images;

        } catch (HttpException e) {
            throw new DockerHubException("Unable to get images for " + repositoryName, e);
        }
    }

    @Override
    protected final List<DockerHubV2Tag> fetchTagsFromApi(String imageName) {

        try {

            List<DockerHubV2Tag> tags = new ArrayList<>();

            String absoluteUrl = DockerHubApiUrl + "/repositories/" + imageName + "/tags/?page_size=" + DefaultPageSize;
            while (absoluteUrl != null) {

                final RestResponse<DockerHubV2TagListResult> response = doCall(absoluteUrl, DockerHubV2TagListResult.class);

                if (isResponseOK(response)) {

                    final DockerHubV2TagListResult payload = response.getPayload();
                    tags.addAll(payload.getResults());

                    absoluteUrl = payload.getNext();
                }
            }

            return tags;

        } catch (HttpException e) {
            throw new DockerHubException("Unable to get tags for " + imageName, e);
        }
    }

    /**
     * <p>
     * Attempts to call DockerHub with the currently set credentials. If they have expired, it will refresh them and try again.
     * This process will only try again once, so if the refresh resulted in another stale token, it will need to be handled.
     * </p>
     */
    private <T> RestResponse<T> doCall(String url, Class<T> responseType) {

        RestResponse<T> restResponse = restClient.executeGet(url, null, authenticator.buildAuthHeaders(), responseType);
        if (isResponseUnauthorised(restResponse)) {

            authenticator.refreshToken();
            restResponse = restClient.executeGet(url, null, authenticator.buildAuthHeaders(), responseType);
        }
        return restResponse;
    }

    private boolean isResponseOK(final RestResponse<?> restResponse) {
        return restResponse.getStatusCode() == 200;
    }

    private boolean isResponseUnauthorised(RestResponse restResponse) {
        return restResponse.getStatusCode() == 401;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubAuthenticator.java
================================================
package io.linuxserver.fleet.v2.client.docker.dockerhub;

import io.linuxserver.fleet.dockerhub.DockerHubException;
import io.linuxserver.fleet.v2.client.rest.RestClient;
import io.linuxserver.fleet.v2.client.rest.RestResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

public class DockerHubAuthenticator implements IDockerHubAuthenticator {

    private static final Logger LOGGER = LoggerFactory.getLogger(DockerHubAuthenticator.class);

    private final RestClient           client;
    private final DockerHubCredentials credentials;

    private String token;

    public DockerHubAuthenticator(final DockerHubCredentials credentials, final RestClient client) {

        this.credentials = credentials;
        this.client = client;

        refreshToken();
    }

    /**
     * <p>
     * Re-authenticates with Docker Hub to obtain a fresh JWT.
     * </p>
     *
     * @return
     *      The new JWT to be used in authenticated requests.
     */
    public synchronized String refreshToken() {

        LOGGER.info("Refreshing token for Docker Hub authentication");

        final RestResponse<DockerHubTokenResponse> authenticationResponse = client.executePost(
                DockerHubApiClient.DockerHubApiUrl + "/users/login", null, null, credentials, DockerHubTokenResponse.class);

        if (authenticationResponse.getStatusCode() == 200) {

            LOGGER.info("Refresh successful");

            final String token = authenticationResponse.getPayload().getToken();
            this.token = token;

            return token;
        }

        LOGGER.info("Unable to refresh token.");

        throw new DockerHubException("Unable to authenticate with Docker Hub. Check credentials");
    }

    synchronized String getCurrentToken() {

        if (null == token) {
            return refreshToken();
        }
        return token;
    }

    @Override
    public Map<String, String> buildAuthHeaders() {

        final Map<String, String> authHeaders = new HashMap<>();
        authHeaders.put("Authorization", "JWT " + getCurrentToken());
        return authHeaders;
    }

    static class DockerHubTokenResponse {

        private String token;

        public String getToken() {
            return token;
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubCredentials.java
================================================
package io.linuxserver.fleet.v2.client.docker.dockerhub;

import io.linuxserver.fleet.v2.Utils;

public class DockerHubCredentials {

    private final String username;
    private final String password;

    public DockerHubCredentials(final String username,
                                final String password) {
        this.username = Utils.ensureNotNull(username);
        this.password = Utils.ensureNotNull(password);
    }

    public final String getUsername() {
        return username;
    }

    public final String getPassword() {
        return password;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubImageConverter.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.dockerhub;

import io.linuxserver.fleet.dockerhub.model.DockerHubV2Image;
import io.linuxserver.fleet.v2.client.docker.converter.AbstractDockerResponseConverter;
import io.linuxserver.fleet.v2.types.docker.DockerImage;

public class DockerHubImageConverter extends AbstractDockerResponseConverter<DockerHubV2Image, DockerImage> {

    @Override
    protected final DockerImage doPlainConvert(final DockerHubV2Image dockerApiImage) {

        return new DockerImage(dockerApiImage.getName(),
                               dockerApiImage.getNamespace(),
                               dockerApiImage.getDescription(),
                               dockerApiImage.getStarCount(),
                               dockerApiImage.getPullCount(),
                               parseDockerHubDate(dockerApiImage.getLastUpdated()));
    }

    @Override
    public Class<DockerHubV2Image> getConverterClass() {
        return DockerHubV2Image.class;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubTagConverter.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.dockerhub;

import io.linuxserver.fleet.dockerhub.model.DockerHubV2Tag;
import io.linuxserver.fleet.dockerhub.model.DockerHubV2TagDigest;
import io.linuxserver.fleet.v2.client.docker.converter.AbstractDockerResponseConverter;
import io.linuxserver.fleet.v2.types.docker.DockerTag;
import io.linuxserver.fleet.v2.types.docker.DockerTagManifestDigest;

public class DockerHubTagConverter extends AbstractDockerResponseConverter<DockerHubV2Tag, DockerTag> {

    @Override
    protected final DockerTag doPlainConvert(final DockerHubV2Tag dockerApiImage) {

        final DockerTag dockerTag = new DockerTag(dockerApiImage.getName(),
                                                  dockerApiImage.getFullSize(),
                                                  parseDockerHubDate(dockerApiImage.getLastUpdated()));

        for (DockerHubV2TagDigest tagImageDigest : dockerApiImage.getImages()) {

            dockerTag.addDigest(new DockerTagManifestDigest(tagImageDigest.getSize(),
                                                            tagImageDigest.getDigest(),
                                                            tagImageDigest.getArchitecture(),
                                                            tagImageDigest.getVariant()));
        }

        return dockerTag;
    }

    @Override
    public Class<DockerHubV2Tag> getConverterClass() {
        return DockerHubV2Tag.class;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/IDockerHubAuthenticator.java
================================================
package io.linuxserver.fleet.v2.client.docker.dockerhub;

import java.util.Map;

public interface IDockerHubAuthenticator {

    Map<String, String> buildAuthHeaders();

    String refreshToken();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/NoOpDockerHubAuthenticator.java
================================================
package io.linuxserver.fleet.v2.client.docker.dockerhub;

import java.util.HashMap;
import java.util.Map;

public class NoOpDockerHubAuthenticator implements IDockerHubAuthenticator {

    @Override
    public Map<String, String> buildAuthHeaders() {
        return new HashMap<>();
    }

    @Override
    public String refreshToken() {
        return null;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubContainerRegistryClient.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.github;

import io.linuxserver.fleet.v2.client.docker.AbstractDockerApiClient;
import io.linuxserver.fleet.v2.client.docker.github.model.GitHubImage;
import io.linuxserver.fleet.v2.client.docker.github.model.GitHubTag;

import java.util.List;

public class GitHubContainerRegistryClient extends AbstractDockerApiClient<GitHubImage, GitHubTag, GitHubImageConverter, GitHubTagConverter> {

    public GitHubContainerRegistryClient() {
        super(new GitHubImageConverter(), new GitHubTagConverter());
    }

    @Override
    protected final GitHubImage fetchImageFromApi(String imageName) {
        return null;
    }

    @Override
    protected final List<GitHubImage> fetchAllImagesFromApi(String repositoryName) {
        return null;
    }

    @Override
    protected final List<GitHubTag> fetchTagsFromApi(String imageName) {
        return null;
    }

    @Override
    public final boolean isRepositoryValid(String repositoryName) {
        return false;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubImageConverter.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.github;

import io.linuxserver.fleet.v2.client.docker.converter.AbstractDockerResponseConverter;
import io.linuxserver.fleet.v2.client.docker.github.model.GitHubImage;
import io.linuxserver.fleet.v2.types.docker.DockerImage;

public class GitHubImageConverter extends AbstractDockerResponseConverter<GitHubImage, DockerImage> {

    @Override
    protected final DockerImage doPlainConvert(final GitHubImage dockerApiImage) {
        return null;
    }

    @Override
    public final Class<GitHubImage> getConverterClass() {
        return GitHubImage.class;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubTagConverter.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.github;

import io.linuxserver.fleet.v2.client.docker.converter.AbstractDockerResponseConverter;
import io.linuxserver.fleet.v2.client.docker.github.model.GitHubTag;
import io.linuxserver.fleet.v2.types.docker.DockerTag;

public class GitHubTagConverter extends AbstractDockerResponseConverter<GitHubTag, DockerTag> {

    @Override
    protected final DockerTag doPlainConvert(final GitHubTag dockerApiImage) {
        return null;
    }

    @Override
    public final Class<GitHubTag> getConverterClass() {
        return GitHubTag.class;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubImage.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.github.model;

public class GitHubImage {
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubTag.java
================================================
/*
 * Copyright (c)  2020 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.github.model;

public class GitHubTag {
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiRequest.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.thread.AsyncTask;

public interface AsyncDockerApiRequest<R extends AsyncDockerApiResponse> extends AsyncTask<DockerApiDelegate, R> {
    ImageKey getImageKey();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiResponse.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.v2.thread.AsyncTaskResponse;

public interface AsyncDockerApiResponse extends AsyncTaskResponse {
    void handleDockerApiResponse();
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiDelegate.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.core.FleetAppController;
import io.linuxserver.fleet.v2.Utils;
import io.linuxserver.fleet.v2.client.docker.DockerApiClient;
import io.linuxserver.fleet.v2.client.docker.DockerImageNotFoundException;
import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.key.RepositoryKey;
import io.linuxserver.fleet.v2.thread.AsyncTaskDelegate;
import io.linuxserver.fleet.v2.types.docker.DockerImage;
import io.linuxserver.fleet.v2.types.docker.DockerTag;

import java.util.List;

public class DockerApiDelegate implements AsyncTaskDelegate {

    private final FleetAppController controller;
    private final DockerApiClient    apiClient;

    public DockerApiDelegate(final FleetAppController controller,
                             final DockerApiClient dockerApiClient) {
        this.controller = controller;
        this.apiClient  = Utils.ensureNotNull(dockerApiClient);
    }

    public final boolean isRepositoryValid(final String repositoryName) {
        return apiClient.isRepositoryValid(repositoryName);
    }

    public final List<DockerImage> getImagesForRepository(final RepositoryKey repositoryKey) {
        return apiClient.fetchAllImages(repositoryKey.getName());
    }

    public final DockerImage getCurrentImageView(final ImageKey imageKey) {

        final DockerImage dockerImage = apiClient.fetchImage(imageKey.getAsRepositoryAndImageName());
        if (null == dockerImage) {
            throw new DockerImageNotFoundException("Image " + imageKey.getAsRepositoryAndImageName() + " was not found upstream.");
        }

        final List<DockerTag> allImageTags = apiClient.fetchImageTags(imageKey.getAsRepositoryAndImageName());
        allImageTags.forEach(dockerImage::addTag);

        return dockerImage;
    }

    @Override
    public FleetAppController getController() {
        return controller;
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiTaskConsumer.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.v2.service.SynchronisationService;
import io.linuxserver.fleet.v2.thread.AbstractTaskQueueConsumer;
import io.linuxserver.fleet.v2.thread.TaskExecutionException;

public final class DockerApiTaskConsumer extends AbstractTaskQueueConsumer<DockerApiDelegate, DockerImageUpdateResponse, DockerImageUpdateRequest> {

    public DockerApiTaskConsumer(final SynchronisationService syncService) {

        super(syncService.getController(),
              syncService.getConfiguredDockerDelegate(),
              syncService.getSyncQueue(),
              "DockerSyncConsumer");
    }

    @Override
    protected void handleTaskResponse(final DockerImageUpdateResponse response) {

        try {
            response.handleDockerApiResponse();
        } catch (Exception e) {

            getLogger().error("handleTaskResponse caught unhandled error, but not something worthy of stalling thread", e);
            throw new TaskExecutionException(e);
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageMissingUpdateResponse.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.core.FleetAppController;
import io.linuxserver.fleet.v2.key.ImageKey;

public class DockerImageMissingUpdateResponse extends DockerImageUpdateResponse {

    public DockerImageMissingUpdateResponse(final FleetAppController controller,
                                            final ImageKey imageKey) {
        super(controller, imageKey, null);
    }

    @Override
    public final void handleDockerApiResponse() {
        // Do nothing. Let schedule handle this.
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateRequest.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.v2.client.docker.DockerImageNotFoundException;
import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.thread.AbstractAppTask;

public class DockerImageUpdateRequest extends AbstractAppTask<DockerApiDelegate, DockerImageUpdateResponse> {

    private final ImageKey imageKey;

    public DockerImageUpdateRequest(final ImageKey imageKey) {
        super(imageKey.toString());
        this.imageKey = imageKey;
    }

    @Override
    protected DockerImageUpdateResponse performTaskInternal(final DockerApiDelegate delegate) {

        try {
            return new DockerImageUpdateResponse(delegate.getController(), imageKey, delegate.getCurrentImageView(imageKey));
        } catch (DockerImageNotFoundException e) {
            getLogger().warn("Request responded with an empty response so assuming image {} has been removed upstream. Error message: {}", imageKey, e.getMessage());
            return new DockerImageMissingUpdateResponse(delegate.getController(), imageKey);
        }
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateResponse.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.core.FleetAppController;
import io.linuxserver.fleet.v2.key.ImageKey;
import io.linuxserver.fleet.v2.types.docker.DockerImage;

public class DockerImageUpdateResponse implements AsyncDockerApiResponse {

    private final FleetAppController controller;
    private final ImageKey           imageKey;
    private final DockerImage        latestImage;

    public DockerImageUpdateResponse(final FleetAppController controller,
                                     final ImageKey imageKey,
                                     final DockerImage latestImage) {
        this.controller  = controller;
        this.imageKey    = imageKey;
        this.latestImage = latestImage;
    }

    protected final FleetAppController getController() {
        return controller;
    }

    @Override
    public void handleDockerApiResponse() {
        controller.getImageService().applyImageUpstreamUpdate(imageKey, latestImage);
    }

    @Override
    public void handleResponse() {
        handleDockerApiResponse();
    }

    @Override
    public String toString() {
        return "DockerImageUpdateResponse[" + imageKey.toString() + "]";
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/TaskQueue.java
================================================
/*
 * Copyright (c)  2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.docker.queue;

import io.linuxserver.fleet.v2.thread.AsyncTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class TaskQueue<TASK extends AsyncTask<?, ?>> {

    private static final Logger LOGGER = LoggerFactory.getLogger(TaskQueue.class);

    private final BlockingQueue<TASK> activeTaskQueue;

    public TaskQueue() {
        activeTaskQueue = new LinkedBlockingQueue<>();
    }

    public final boolean submitTask(final TASK task) {

        LOGGER.info("Task submitted: {}", task);
        if (activeTaskQueue.contains(task)) {

            LOGGER.warn("Task {} is already queued so will not duplicate the request.", task);
            return false;
        }

        return activeTaskQueue.add(task);
    }

    public final int size() {
        return activeTaskQueue.size();
    }

    public final TASK retrieveNextTask() throws InterruptedException {
        return activeTaskQueue.take();
    }

    public final boolean isEmpty() {
        return activeTaskQueue.isEmpty();
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/HttpException.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.rest;

public class HttpException extends RuntimeException {

    public HttpException(String message) {
        super(message);
    }

    public HttpException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/RestClient.java
================================================
/*
 * Copyright (c) 2019 LinuxServer.io
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

package io.linuxserver.fleet.v2.client.rest;

import io.linuxserver.fleet.v2.client.rest.marshalling.JacksonMarshallingStrategy;
import io.linuxserver.fleet.v2.client.rest.marshalling.MarshallingStrategy;
import io.linuxserver.fleet.v2.client.rest.proxy.LazyLoadPayloadProxy;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * <p>
 * Simple wrapper for base HttpClient, providing an easier way to marshall/unmarshall payloads
 * </p>
 */
public class RestClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(RestClient.class);

    private final CloseableHttpClient   client;
    private final HttpClientContext     clientContext;

    private MarshallingStrategy         marshallingStrategy;

    public RestClient() {

        setMarshallingStrategy(new JacksonMarshallingStrategy());
        client = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build();
        clientContext = HttpClientContext.create();
    }

    private void setMarshallingStrategy(MarshallingStrategy marshallingStrategy) {

        LOGGER.debug("Configuring RestClient with " + marshallingStrategy.getClass().getName());
        this.marshallingStrategy = marshallingStrategy;
    }

    public <T> RestResponse<T> executeGet(String url, Map<String, String> queryParameters, Map<String, String> headers, Class<T> responseType) {

        try {

            return executeBaseRequest(responseType, headers, new HttpGet(url + parseQueryParameters(queryParameters)));

        } catch (IOException e) {

            LOGGER.error("Unable to perform GET", e);
            throw new HttpException("Unable to perform GET", e);
        }
    }

    public <T> RestResponse<T> executePost(String url, Map<String, String> queryParameters, Map<String, String> headers, Object payload, Class<T> responseType) {


        try {

            HttpPost post = new HttpPost(url + parseQueryParameters(queryParameters));
            post.setEntity(new StringEntity(marshallingStrategy.marshall(payload), StandardCharsets.UTF_8));
            post.setHeader("Content-Type", marshallingStrategy.getContentType());

            return executeBaseRequest(responseType, headers, post);

        } catch (IOException e) {

            LOGGER.error("Unable to perform GET", e);
            throw new HttpException("Unable to perform GET", e);
        }
    }

    private <T> RestResponse<T> executeBaseRequest(Class<T> responseType, Map<String, String> headers, HttpRequestBase request) throws IOException {

        LOGGER.debug("url             : " + request.getURI().toString());
        LOGGER.debug("headers         : " + headers);

        if (headers != null) {

            for (Map.Entry<String, Str
Download .txt
gitextract_h6oaxvsz/

├── .gitignore
├── LICENSE
├── README.md
├── build.gradle
├── config/
│   ├── example.fleet.properties
│   ├── log4j2.local.xml
│   └── log4j2.release.xml
├── gradle/
│   └── wrapper/
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── io/
    │   │       └── linuxserver/
    │   │           └── fleet/
    │   │               ├── auth/
    │   │               │   ├── AuthenticatedUser.java
    │   │               │   ├── AuthenticationDelegate.java
    │   │               │   ├── AuthenticationResult.java
    │   │               │   ├── DefaultAuthenticationDelegate.java
    │   │               │   ├── UserCredentials.java
    │   │               │   ├── authenticator/
    │   │               │   │   ├── DefaultUserAuthenticator.java
    │   │               │   │   └── UserAuthenticator.java
    │   │               │   └── security/
    │   │               │       ├── PBKDF2PasswordEncoder.java
    │   │               │       ├── PasswordEncoder.java
    │   │               │       └── util/
    │   │               │           └── SaltGenerator.java
    │   │               ├── core/
    │   │               │   ├── AbstractAppController.java
    │   │               │   ├── BaseRuntimeLoader.java
    │   │               │   ├── FleetAppController.java
    │   │               │   ├── FleetRuntime.java
    │   │               │   ├── Main.java
    │   │               │   ├── PropertiesLoader.java
    │   │               │   ├── ServiceProvider.java
    │   │               │   ├── config/
    │   │               │   │   ├── AppProperties.java
    │   │               │   │   ├── DatabaseConnectionProperties.java
    │   │               │   │   ├── Version.java
    │   │               │   │   ├── VersionProperties.java
    │   │               │   │   └── WebConfiguration.java
    │   │               │   └── db/
    │   │               │       ├── DatabaseConnection.java
    │   │               │       ├── DatabaseProvider.java
    │   │               │       └── DefaultDatabaseProvider.java
    │   │               ├── db/
    │   │               │   ├── DefaultDatabaseConnection.java
    │   │               │   ├── PoolingDatabaseConnection.java
    │   │               │   ├── dao/
    │   │               │   │   └── Utils.java
    │   │               │   ├── migration/
    │   │               │   │   └── DatabaseVersion.java
    │   │               │   └── query/
    │   │               │       ├── InsertUpdateResult.java
    │   │               │       ├── InsertUpdateStatus.java
    │   │               │       ├── LimitOffset.java
    │   │               │       └── LimitedResult.java
    │   │               ├── dockerhub/
    │   │               │   ├── DockerHubException.java
    │   │               │   ├── model/
    │   │               │   │   ├── DockerHubV2Image.java
    │   │               │   │   ├── DockerHubV2ImageListResult.java
    │   │               │   │   ├── DockerHubV2NamespaceLookupResult.java
    │   │               │   │   ├── DockerHubV2ScanResult.java
    │   │               │   │   ├── DockerHubV2Tag.java
    │   │               │   │   ├── DockerHubV2TagDigest.java
    │   │               │   │   └── DockerHubV2TagListResult.java
    │   │               │   └── util/
    │   │               │       └── DockerTagFinder.java
    │   │               ├── exception/
    │   │               │   └── SaveException.java
    │   │               └── v2/
    │   │                   ├── LoggerOwner.java
    │   │                   ├── Utils.java
    │   │                   ├── cache/
    │   │                   │   ├── AbstractItemCache.java
    │   │                   │   ├── BasicItemCache.java
    │   │                   │   ├── ImageCache.java
    │   │                   │   ├── ItemCache.java
    │   │                   │   ├── RepositoryCache.java
    │   │                   │   └── ScheduleCache.java
    │   │                   ├── client/
    │   │                   │   ├── docker/
    │   │                   │   │   ├── AbstractDockerApiClient.java
    │   │                   │   │   ├── DockerApiClient.java
    │   │                   │   │   ├── DockerImageNotFoundException.java
    │   │                   │   │   ├── converter/
    │   │                   │   │   │   ├── AbstractDockerResponseConverter.java
    │   │                   │   │   │   └── DockerResponseConverter.java
    │   │                   │   │   ├── dockerhub/
    │   │                   │   │   │   ├── DockerHubApiClient.java
    │   │                   │   │   │   ├── DockerHubAuthenticator.java
    │   │                   │   │   │   ├── DockerHubCredentials.java
    │   │                   │   │   │   ├── DockerHubImageConverter.java
    │   │                   │   │   │   ├── DockerHubTagConverter.java
    │   │                   │   │   │   ├── IDockerHubAuthenticator.java
    │   │                   │   │   │   └── NoOpDockerHubAuthenticator.java
    │   │                   │   │   ├── github/
    │   │                   │   │   │   ├── GitHubContainerRegistryClient.java
    │   │                   │   │   │   ├── GitHubImageConverter.java
    │   │                   │   │   │   ├── GitHubTagConverter.java
    │   │                   │   │   │   └── model/
    │   │                   │   │   │       ├── GitHubImage.java
    │   │                   │   │   │       └── GitHubTag.java
    │   │                   │   │   └── queue/
    │   │                   │   │       ├── AsyncDockerApiRequest.java
    │   │                   │   │       ├── AsyncDockerApiResponse.java
    │   │                   │   │       ├── DockerApiDelegate.java
    │   │                   │   │       ├── DockerApiTaskConsumer.java
    │   │                   │   │       ├── DockerImageMissingUpdateResponse.java
    │   │                   │   │       ├── DockerImageUpdateRequest.java
    │   │                   │   │       ├── DockerImageUpdateResponse.java
    │   │                   │   │       └── TaskQueue.java
    │   │                   │   └── rest/
    │   │                   │       ├── HttpException.java
    │   │                   │       ├── RestClient.java
    │   │                   │       ├── RestResponse.java
    │   │                   │       ├── marshalling/
    │   │                   │       │   ├── JacksonMarshallingStrategy.java
    │   │                   │       │   └── MarshallingStrategy.java
    │   │                   │       └── proxy/
    │   │                   │           ├── LazyLoadPayloadProxy.java
    │   │                   │           └── PayloadProxy.java
    │   │                   ├── db/
    │   │                   │   ├── AbstractDAO.java
    │   │                   │   ├── DbUpdateStatus.java
    │   │                   │   ├── DefaultImageDAO.java
    │   │                   │   ├── DefaultScheduleDAO.java
    │   │                   │   ├── DefaultUserDAO.java
    │   │                   │   ├── ImageDAO.java
    │   │                   │   ├── ImageTemplateFactory.java
    │   │                   │   ├── ScheduleDAO.java
    │   │                   │   ├── UserDAO.java
    │   │                   │   └── Utils.java
    │   │                   ├── file/
    │   │                   │   └── FileManager.java
    │   │                   ├── key/
    │   │                   │   ├── AbstractDatabaseKey.java
    │   │                   │   ├── AbstractHasKey.java
    │   │                   │   ├── AbstractLookupKey.java
    │   │                   │   ├── AlertKey.java
    │   │                   │   ├── HasKey.java
    │   │                   │   ├── ImageKey.java
    │   │                   │   ├── ImageLookupKey.java
    │   │                   │   ├── Key.java
    │   │                   │   ├── RepositoryKey.java
    │   │                   │   ├── ScheduleKey.java
    │   │                   │   ├── TagBranchKey.java
    │   │                   │   └── UserKey.java
    │   │                   ├── service/
    │   │                   │   ├── AbstractAppService.java
    │   │                   │   ├── ImageService.java
    │   │                   │   ├── ScheduleService.java
    │   │                   │   ├── SynchronisationService.java
    │   │                   │   ├── UserService.java
    │   │                   │   └── util/
    │   │                   │       └── TemplateMerger.java
    │   │                   ├── thread/
    │   │                   │   ├── AbstractAppTask.java
    │   │                   │   ├── AbstractAppThread.java
    │   │                   │   ├── AbstractTaskQueueConsumer.java
    │   │                   │   ├── AsyncTask.java
    │   │                   │   ├── AsyncTaskDelegate.java
    │   │                   │   ├── AsyncTaskResponse.java
    │   │                   │   ├── TaskExecutionException.java
    │   │                   │   ├── TaskResponseControllerProxy.java
    │   │                   │   ├── ThreadStatus.java
    │   │                   │   └── schedule/
    │   │                   │       ├── AbstractAppSchedule.java
    │   │                   │       ├── AppSchedule.java
    │   │                   │       ├── CheckAppVersionSchedule.java
    │   │                   │       ├── ScheduleSpec.java
    │   │                   │       ├── TidyHistoricDataSchedule.java
    │   │                   │       ├── TimeWithUnit.java
    │   │                   │       ├── cache/
    │   │                   │       │   └── RefreshCacheSchedule.java
    │   │                   │       └── sync/
    │   │                   │           ├── AllImagesSyncSchedule.java
    │   │                   │           ├── CleanRemovedImagesSchedule.java
    │   │                   │           └── GetMissingImagesSchedule.java
    │   │                   ├── types/
    │   │                   │   ├── AbstractSyncItem.java
    │   │                   │   ├── AppAlert.java
    │   │                   │   ├── FilePathDetails.java
    │   │                   │   ├── HasSyncSpec.java
    │   │                   │   ├── Image.java
    │   │                   │   ├── ImageCountData.java
    │   │                   │   ├── Repository.java
    │   │                   │   ├── Tag.java
    │   │                   │   ├── TagBranch.java
    │   │                   │   ├── TagDigest.java
    │   │                   │   ├── User.java
    │   │                   │   ├── api/
    │   │                   │   │   ├── AbstractApiWrapper.java
    │   │                   │   │   ├── ApiImagePullHistoryWrapper.java
    │   │                   │   │   ├── ApiImageWrapper.java
    │   │                   │   │   ├── ApiRepositoryWrapper.java
    │   │                   │   │   ├── ApiScheduleWrapper.java
    │   │                   │   │   └── external/
    │   │                   │   │       ├── AllImagesExternalApiResponse.java
    │   │                   │   │       ├── ExternalApiImage.java
    │   │                   │   │       ├── ExternalApiResponse.java
    │   │                   │   │       └── templates/
    │   │                   │   │           ├── ApiDeviceTemplate.java
    │   │                   │   │           ├── ApiEnvTemplate.java
    │   │                   │   │           ├── ApiPortTemplate.java
    │   │                   │   │           ├── ApiTemplateHolder.java
    │   │                   │   │           └── ApiVolumeTemplate.java
    │   │                   │   ├── docker/
    │   │                   │   │   ├── DockerCapability.java
    │   │                   │   │   ├── DockerImage.java
    │   │                   │   │   ├── DockerTag.java
    │   │                   │   │   └── DockerTagManifestDigest.java
    │   │                   │   ├── internal/
    │   │                   │   │   ├── AbstractParamRequest.java
    │   │                   │   │   ├── ImageAppLogo.java
    │   │                   │   │   ├── ImageGeneralInfoUpdateRequest.java
    │   │                   │   │   ├── ImageOutlineRequest.java
    │   │                   │   │   ├── ImageTemplateRequest.java
    │   │                   │   │   ├── ImageUrlsUpdateRequest.java
    │   │                   │   │   ├── RepositoryOutlineRequest.java
    │   │                   │   │   ├── TagBranchOutlineRequest.java
    │   │                   │   │   └── UserOutlineRequest.java
    │   │                   │   └── meta/
    │   │                   │       ├── ExternalUrl.java
    │   │                   │       ├── ExternalUrlKey.java
    │   │                   │       ├── ImageCoreMeta.java
    │   │                   │       ├── ImageMetaData.java
    │   │                   │       ├── ItemSyncSpec.java
    │   │                   │       ├── history/
    │   │                   │       │   ├── ImagePullHistory.java
    │   │                   │       │   └── ImagePullStatistic.java
    │   │                   │       └── template/
    │   │                   │           ├── AbstractTemplateItem.java
    │   │                   │           ├── DeviceTemplateItem.java
    │   │                   │           ├── EnvironmentTemplateItem.java
    │   │                   │           ├── ImageTemplateHolder.java
    │   │                   │           ├── PortTemplateItem.java
    │   │                   │           ├── TemplateItem.java
    │   │                   │           └── VolumeTemplateItem.java
    │   │                   └── web/
    │   │                       ├── ApiException.java
    │   │                       ├── AppRole.java
    │   │                       ├── LocationUtils.java
    │   │                       ├── Locations.java
    │   │                       ├── PageModelAttributes.java
    │   │                       ├── PageModelSpec.java
    │   │                       ├── SessionAttributes.java
    │   │                       ├── WebRouteController.java
    │   │                       ├── freemarker/
    │   │                       │   ├── CustomFreemarkerTemplate.java
    │   │                       │   └── Java8DateTimeMethod.java
    │   │                       ├── request/
    │   │                       │   └── json/
    │   │                       │       ├── NewRepositoryRequest.java
    │   │                       │       ├── UpdateImageSpecRequest.java
    │   │                       │       └── UpdateRepositoryRequest.java
    │   │                       └── routes/
    │   │                           ├── AbstractPageHandler.java
    │   │                           ├── AdminImageController.java
    │   │                           ├── AdminImageEditController.java
    │   │                           ├── AdminRepositoryController.java
    │   │                           ├── AdminScheduleController.java
    │   │                           ├── AdminUserController.java
    │   │                           ├── DefaultAccessManager.java
    │   │                           ├── HomeController.java
    │   │                           ├── ImageController.java
    │   │                           ├── InternalApiController.java
    │   │                           ├── LegacyExternalApiController.java
    │   │                           └── LoginController.java
    │   └── resources/
    │       ├── db/
    │       │   └── migration/
    │       │       ├── V1.0__CreateTables.sql
    │       │       ├── V1.10__UpdateImageViewWithRepository.sql
    │       │       ├── V1.1__CreateSprocs.sql
    │       │       ├── V1.2__CreateUserTable.sql
    │       │       ├── V1.3__CreateUserSprocs.sql
    │       │       ├── V1.4__AddDeprecationFields.sql
    │       │       ├── V1.5__UpdateImageSprocs.sql
    │       │       ├── V1.6__ExtendVersionColumn.sql
    │       │       ├── V1.7__RemoveCoalesce.sql
    │       │       ├── V1.8__PullHistoryAndImageMeta.sql
    │       │       ├── V1.9__ExtraTagFields.sql
    │       │       ├── V2.0__CreateV2TablesAndSprocs.sql
    │       │       ├── V2.1__MigrateToNewTables.sql
    │       │       ├── V2.2__MetaDataTables.sql
    │       │       ├── V2.3__UpdateImageViewForCoreMeta.sql
    │       │       ├── V2.4__UpdateUserSprocs.sql
    │       │       ├── V2.5__BranchRemovalSproc.sql
    │       │       ├── V2.6__AddCleanSchedule.sql
    │       │       ├── V2.7__UpdateImageTemplateSprocs.sql
    │       │       └── V2.8__FixStoreCoreMetaOutputBug.sql
    │       ├── static/
    │       │   └── assets/
    │       │       ├── css/
    │       │       │   ├── app.css
    │       │       │   ├── bootstrap.css
    │       │       │   └── prism.css
    │       │       └── js/
    │       │           ├── admin.js
    │       │           ├── app.js
    │       │           ├── fontawesome-all.js
    │       │           ├── jquery.tablesorter.js
    │       │           └── prism.js
    │       ├── version.properties
    │       └── views/
    │           ├── pages/
    │           │   ├── admin/
    │           │   │   ├── image-edit.ftl
    │           │   │   ├── images.ftl
    │           │   │   ├── repositories.ftl
    │           │   │   ├── schedules.ftl
    │           │   │   ├── template-components/
    │           │   │   │   ├── image-template-devices.ftl
    │           │   │   │   ├── image-template-environment.ftl
    │           │   │   │   ├── image-template-misc.ftl
    │           │   │   │   ├── image-template-ports.ftl
    │           │   │   │   └── image-template-volumes.ftl
    │           │   │   └── users.ftl
    │           │   ├── error.ftl
    │           │   ├── home.ftl
    │           │   ├── image.ftl
    │           │   └── login.ftl
    │           ├── prebuilt/
    │           │   ├── base.ftl
    │           │   ├── docker-example.ftl
    │           │   ├── fleet-title.ftl
    │           │   ├── image-list-item.ftl
    │           │   ├── image-list-table-item.ftl
    │           │   └── system-alert.ftl
    │           └── ui/
    │               ├── components/
    │               │   ├── dropdown.ftl
    │               │   ├── message.ftl
    │               │   ├── modal.ftl
    │               │   ├── navbar.ftl
    │               │   └── pagination.ftl
    │               ├── elements/
    │               │   ├── box.ftl
    │               │   ├── button.ftl
    │               │   ├── display-field.ftl
    │               │   ├── media.ftl
    │               │   ├── notification.ftl
    │               │   ├── table.ftl
    │               │   └── tag.ftl
    │               ├── form/
    │               │   └── input.ftl
    │               └── layout/
    │                   ├── container.ftl
    │                   ├── footer.ftl
    │                   ├── hero.ftl
    │                   └── section.ftl
    └── test/
        └── java/
            └── io/
                └── linuxserver/
                    └── fleet/
                        ├── auth/
                        │   └── security/
                        │       └── PBKDF2PasswordEncoderTest.java
                        ├── dockerhub/
                        │   └── util/
                        │       └── DockerTagFinderTest.java
                        └── v2/
                            └── thread/
                                └── schedule/
                                    └── TimeWithUnitTest.java
Download .txt
SYMBOL INDEX (1302 symbols across 222 files)

FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticatedUser.java
  class AuthenticatedUser (line 26) | public class AuthenticatedUser {
    method AuthenticatedUser (line 30) | public AuthenticatedUser(final User user) {
    method getName (line 34) | public final String getName() {
    method getRoles (line 38) | public final Set<AppRole> getRoles() {

FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticationDelegate.java
  type AuthenticationDelegate (line 20) | public interface AuthenticationDelegate {
    method authenticate (line 22) | AuthenticationResult authenticate(String username, String password);
    method encodePassword (line 24) | String encodePassword(String rawPassword);

FILE: src/main/java/io/linuxserver/fleet/auth/AuthenticationResult.java
  class AuthenticationResult (line 20) | public class AuthenticationResult {
    method AuthenticationResult (line 25) | public AuthenticationResult(boolean authenticated, AuthenticatedUser u...
    method notAuthenticated (line 31) | public static AuthenticationResult notAuthenticated() {
    method isAuthenticated (line 35) | public boolean isAuthenticated() {
    method getUser (line 39) | public AuthenticatedUser getUser() {

FILE: src/main/java/io/linuxserver/fleet/auth/DefaultAuthenticationDelegate.java
  class DefaultAuthenticationDelegate (line 23) | public class DefaultAuthenticationDelegate implements AuthenticationDele...
    method DefaultAuthenticationDelegate (line 27) | public DefaultAuthenticationDelegate(final UserAuthenticator authentic...
    method authenticate (line 31) | @Override
    method encodePassword (line 36) | @Override

FILE: src/main/java/io/linuxserver/fleet/auth/UserCredentials.java
  class UserCredentials (line 20) | public class UserCredentials {
    method UserCredentials (line 25) | public UserCredentials(String username, String password) {
    method getUsername (line 31) | public String getUsername() {
    method getPassword (line 35) | public String getPassword() {

FILE: src/main/java/io/linuxserver/fleet/auth/authenticator/DefaultUserAuthenticator.java
  class DefaultUserAuthenticator (line 27) | public class DefaultUserAuthenticator implements UserAuthenticator {
    method DefaultUserAuthenticator (line 32) | public DefaultUserAuthenticator(final UserService userService,
    method authenticate (line 39) | @Override
    method getPasswordEncoder (line 51) | @Override

FILE: src/main/java/io/linuxserver/fleet/auth/authenticator/UserAuthenticator.java
  type UserAuthenticator (line 30) | public interface UserAuthenticator {
    method authenticate (line 38) | AuthenticationResult authenticate(UserCredentials userCredentials);
    method getPasswordEncoder (line 40) | PasswordEncoder getPasswordEncoder();

FILE: src/main/java/io/linuxserver/fleet/auth/security/PBKDF2PasswordEncoder.java
  class PBKDF2PasswordEncoder (line 34) | public class PBKDF2PasswordEncoder implements PasswordEncoder {
    method PBKDF2PasswordEncoder (line 47) | public PBKDF2PasswordEncoder(String secret) {
    method PBKDF2PasswordEncoder (line 51) | public PBKDF2PasswordEncoder(String secret, int hashWidth, int iterati...
    method encode (line 58) | @Override
    method matches (line 68) | @Override
    method passwordsMatch (line 86) | private boolean passwordsMatch(byte[] originalPassword, byte[] provide...
    method encode (line 106) | private byte[] encode(String rawPassword, byte[] salt) {
    method toBase64 (line 130) | private String toBase64(byte[] bytes) {
    method fromBase64 (line 139) | private byte[] fromBase64(String input) {
    method extractSalt (line 149) | private byte[] extractSalt(byte[] decodedHash) {
    method joinArrays (line 158) | private byte[] joinArrays(byte[] first, byte[] second) {
    method extractFromArray (line 170) | private byte[] extractFromArray(byte[] array, int begin, int end) {

FILE: src/main/java/io/linuxserver/fleet/auth/security/PasswordEncoder.java
  type PasswordEncoder (line 27) | public interface PasswordEncoder {
    method encode (line 40) | String encode(String rawPassword);
    method matches (line 54) | boolean matches(String rawPassword, String encodedPassword);

FILE: src/main/java/io/linuxserver/fleet/auth/security/util/SaltGenerator.java
  class SaltGenerator (line 22) | public class SaltGenerator {
    method generateSalt (line 26) | public byte[] generateSalt() {
    method getKeyLength (line 36) | public int getKeyLength() {

FILE: src/main/java/io/linuxserver/fleet/core/AbstractAppController.java
  class AbstractAppController (line 32) | public abstract class AbstractAppController {
    method AbstractAppController (line 38) | public AbstractAppController() {
    method getDatabaseProvider (line 45) | public final DatabaseProvider getDatabaseProvider() {
    method getAppProperties (line 49) | public final AppProperties getAppProperties() {
    method getAlerts (line 53) | public final List<AppAlert> getAlerts() {
    method getSystemAlerts (line 57) | public final List<AppAlert> getSystemAlerts() {
    method addAlert (line 61) | public final void addAlert(final AppAlert appAlert) {
    method clearAlert (line 65) | public final void clearAlert(final AlertKey alertKey) {
    method run (line 69) | protected void run() {

FILE: src/main/java/io/linuxserver/fleet/core/BaseRuntimeLoader.java
  class BaseRuntimeLoader (line 30) | abstract class BaseRuntimeLoader {
    method BaseRuntimeLoader (line 34) | BaseRuntimeLoader() {

FILE: src/main/java/io/linuxserver/fleet/core/FleetAppController.java
  class FleetAppController (line 49) | public class FleetAppController extends AbstractAppController implements...
    method FleetAppController (line 58) | public FleetAppController() {
    method instance (line 70) | public static FleetAppController instance() {
    method run (line 85) | @Override
    method getWebConfiguration (line 92) | public final WebConfiguration getWebConfiguration() {
    method configureWeb (line 96) | private void configureWeb() {
    method handleException (line 100) | public final void handleException(final Exception e) {
    method synchroniseImage (line 104) | public final boolean synchroniseImage(final ImageKey imageKey) {
    method synchroniseRepository (line 108) | public final void synchroniseRepository(final Repository repository) {
    method getConfiguredDockerDelegate (line 112) | public final DockerApiDelegate getConfiguredDockerDelegate() {
    method getImageService (line 116) | public final ImageService getImageService() {
    method storeUpdatedImage (line 120) | public final Image storeUpdatedImage(final Image updatedImage) {
    method getScheduleService (line 124) | @Override
    method verifyRepositoryAndCreateOutline (line 129) | public final Repository verifyRepositoryAndCreateOutline(final Reposit...
    method getSynchronisationService (line 144) | @Override
    method getUserService (line 149) | @Override
    method getFileManager (line 154) | @Override
    method authenticateCredentials (line 159) | public final AuthenticationResult authenticateCredentials(final String...
    method trackBranch (line 163) | public final void trackBranch(final ImageKey imageKey, final String br...
    method configureDockerApiClient (line 169) | private DockerApiClient configureDockerApiClient() {

FILE: src/main/java/io/linuxserver/fleet/core/FleetRuntime.java
  type FleetRuntime (line 20) | public interface FleetRuntime {

FILE: src/main/java/io/linuxserver/fleet/core/Main.java
  class Main (line 20) | public class Main {
    method main (line 22) | public static void main(String[] args) {

FILE: src/main/java/io/linuxserver/fleet/core/PropertiesLoader.java
  class PropertiesLoader (line 39) | class PropertiesLoader extends BaseRuntimeLoader {
    method PropertiesLoader (line 45) | PropertiesLoader() {
    method createConfigFileIfNotProvided (line 73) | private void createConfigFileIfNotProvided() {
    method createStaticFileDirectory (line 90) | private boolean createStaticFileDirectory() {
    method createLogsDirectory (line 101) | private boolean createLogsDirectory() {
    method getProperties (line 120) | AppProperties getProperties() {
    method printProperties (line 129) | private void printProperties() {
    method showPasswords (line 146) | private boolean showPasswords() {

FILE: src/main/java/io/linuxserver/fleet/core/ServiceProvider.java
  type ServiceProvider (line 26) | public interface ServiceProvider {
    method getSynchronisationService (line 28) | SynchronisationService getSynchronisationService();
    method getImageService (line 30) | ImageService getImageService();
    method getScheduleService (line 32) | ScheduleService getScheduleService();
    method getUserService (line 34) | UserService getUserService();
    method getFileManager (line 36) | FileManager getFileManager();

FILE: src/main/java/io/linuxserver/fleet/core/config/AppProperties.java
  class AppProperties (line 27) | public class AppProperties {
    method AppProperties (line 31) | public AppProperties(final Properties properties) {
    method getDatabaseProperties (line 35) | public DatabaseConnectionProperties getDatabaseProperties() {
    method getVersionProperties (line 43) | public final VersionProperties getVersionProperties() {
    method getDatabaseDriverClassName (line 51) | private String getDatabaseDriverClassName() {
    method getDatabaseUrl (line 55) | private String getDatabaseUrl() {
    method getDatabaseUsername (line 59) | private String getDatabaseUsername() {
    method getDatabasePassword (line 63) | private String getDatabasePassword() {
    method getStaticFilesPath (line 67) | public final Path getStaticFilesPath() {
    method getAppSecret (line 71) | public String getAppSecret() {
    method getAppPort (line 77) | public int getAppPort() {
    method isDockerHubAuthEnabled (line 81) | public boolean isDockerHubAuthEnabled() {
    method getDockerHubCredentials (line 85) | public DockerHubCredentials getDockerHubCredentials() {
    method getStringProperty (line 99) | private String getStringProperty(String propertyKey) {

FILE: src/main/java/io/linuxserver/fleet/core/config/DatabaseConnectionProperties.java
  class DatabaseConnectionProperties (line 20) | public class DatabaseConnectionProperties {
    method DatabaseConnectionProperties (line 27) | public DatabaseConnectionProperties(final String driverClass,
    method getDatabaseDriverClass (line 37) | public final String getDatabaseDriverClass() {
    method getDatabaseUrl (line 41) | public final String getDatabaseUrl() {
    method getDatabaseUsername (line 45) | public final String getDatabaseUsername() {
    method getDatabasePassword (line 49) | public final String getDatabasePassword() {

FILE: src/main/java/io/linuxserver/fleet/core/config/Version.java
  class Version (line 20) | public class Version {
    method Version (line 26) | public Version(int major, int minor, int patch) {
    method Version (line 33) | public Version(String version) {
    method getMajor (line 42) | public int getMajor() {
    method getMinor (line 46) | public int getMinor() {
    method getPatch (line 50) | public int getPatch() {
    method isNewerThan (line 54) | public boolean isNewerThan(Version version) {
    method toString (line 67) | @Override

FILE: src/main/java/io/linuxserver/fleet/core/config/VersionProperties.java
  class VersionProperties (line 26) | public class VersionProperties {
    method VersionProperties (line 33) | public VersionProperties(final String version,
    method getVersion (line 44) | public final Version getVersion() {
    method getBuildUser (line 48) | public final String getBuildUser() {
    method getBuildDate (line 52) | public final LocalDateTime getBuildDate() {
    method getBuildPlatform (line 56) | public final String getBuildPlatform() {
    method toString (line 60) | @Override

FILE: src/main/java/io/linuxserver/fleet/core/config/WebConfiguration.java
  class WebConfiguration (line 20) | public class WebConfiguration {
    method WebConfiguration (line 24) | public WebConfiguration(final AppProperties properties) {
    method getPort (line 28) | public final int getPort() {

FILE: src/main/java/io/linuxserver/fleet/core/db/DatabaseConnection.java
  type DatabaseConnection (line 24) | public interface DatabaseConnection  {
    method getDataSource (line 26) | DataSource getDataSource();
    method getConnection (line 28) | Connection getConnection() throws SQLException;

FILE: src/main/java/io/linuxserver/fleet/core/db/DatabaseProvider.java
  type DatabaseProvider (line 22) | public interface DatabaseProvider {
    method getDatabaseConnection (line 24) | DatabaseConnection getDatabaseConnection();
    method getVersionHandler (line 26) | DatabaseVersion getVersionHandler();

FILE: src/main/java/io/linuxserver/fleet/core/db/DefaultDatabaseProvider.java
  class DefaultDatabaseProvider (line 22) | public class DefaultDatabaseProvider implements DatabaseProvider {
    method DefaultDatabaseProvider (line 27) | public DefaultDatabaseProvider(final DatabaseConnection databaseConnec...
    method getDatabaseConnection (line 32) | @Override
    method getVersionHandler (line 37) | @Override

FILE: src/main/java/io/linuxserver/fleet/db/DefaultDatabaseConnection.java
  class DefaultDatabaseConnection (line 22) | public class DefaultDatabaseConnection extends PoolingDatabaseConnection {
    method DefaultDatabaseConnection (line 24) | public DefaultDatabaseConnection(final DatabaseConnectionProperties pr...

FILE: src/main/java/io/linuxserver/fleet/db/PoolingDatabaseConnection.java
  class PoolingDatabaseConnection (line 30) | public abstract class PoolingDatabaseConnection implements DatabaseConne...
    method PoolingDatabaseConnection (line 36) | PoolingDatabaseConnection(final DatabaseConnectionProperties propertie...
    method getDataSource (line 47) | @Override
    method getConnection (line 52) | @Override

FILE: src/main/java/io/linuxserver/fleet/db/dao/Utils.java
  class Utils (line 26) | class Utils {
    method setNullableInt (line 28) | static void setNullableInt(CallableStatement call, int position, Integ...
    method setNullableLong (line 37) | static void setNullableLong(CallableStatement call, int position, Long...
    method setNullableString (line 46) | static void setNullableString(CallableStatement call, int position, St...
    method setNullableTimestamp (line 55) | static void setNullableTimestamp(CallableStatement call, int position,...
    method safeClose (line 64) | static void safeClose(CallableStatement call) {

FILE: src/main/java/io/linuxserver/fleet/db/migration/DatabaseVersion.java
  class DatabaseVersion (line 32) | public class DatabaseVersion {
    method DatabaseVersion (line 38) | public DatabaseVersion(final DatabaseConnection databaseConnection) {
    method migrate (line 48) | public void migrate() {

FILE: src/main/java/io/linuxserver/fleet/db/query/InsertUpdateResult.java
  class InsertUpdateResult (line 20) | public class InsertUpdateResult<T> {
    method InsertUpdateResult (line 26) | public InsertUpdateResult(T result) {
    method InsertUpdateResult (line 30) | public InsertUpdateResult(T result, int status, String statusMessage) {
    method InsertUpdateResult (line 37) | public InsertUpdateResult(int status, String statusMessage) {
    method getResult (line 41) | public final T getResult() {
    method getStatus (line 45) | public final int getStatus() {
    method getStatusMessage (line 49) | public final String getStatusMessage() {
    method isError (line 53) | public final boolean isError() {

FILE: src/main/java/io/linuxserver/fleet/db/query/InsertUpdateStatus.java
  type InsertUpdateStatus (line 20) | public interface InsertUpdateStatus {

FILE: src/main/java/io/linuxserver/fleet/db/query/LimitOffset.java
  class LimitOffset (line 20) | public class LimitOffset {
    method LimitOffset (line 25) | public LimitOffset(int limit, int offset) {
    method getLimit (line 31) | public int getLimit() {
    method getOffset (line 35) | public int getOffset() {

FILE: src/main/java/io/linuxserver/fleet/db/query/LimitedResult.java
  class LimitedResult (line 22) | public class LimitedResult<T> {
    method LimitedResult (line 28) | public LimitedResult(List<T> results, int totalCount) {
    method LimitedResult (line 32) | public LimitedResult(List<T> results, int totalCount, LimitOffset next) {
    method getResults (line 39) | public List<T> getResults() {
    method getTotalCount (line 43) | public int getTotalCount() {
    method getNext (line 47) | public LimitOffset getNext() {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/DockerHubException.java
  class DockerHubException (line 20) | public class DockerHubException extends RuntimeException {
    method DockerHubException (line 22) | public DockerHubException(String message) {
    method DockerHubException (line 26) | public DockerHubException(String message, Throwable cause) {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Image.java
  class DockerHubV2Image (line 23) | @JsonInclude(JsonInclude.Include.NON_NULL)
    method getUser (line 47) | public final String getUser() {
    method getName (line 51) | public final String getName() {
    method getNamespace (line 55) | public final String getNamespace() {
    method getDescription (line 59) | public String getDescription() {
    method getStarCount (line 63) | public final int getStarCount() {
    method getPullCount (line 67) | public final long getPullCount() {
    method getLastUpdated (line 71) | public final String getLastUpdated() {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ImageListResult.java
  class DockerHubV2ImageListResult (line 20) | public class DockerHubV2ImageListResult extends DockerHubV2ScanResult<Do...

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2NamespaceLookupResult.java
  class DockerHubV2NamespaceLookupResult (line 25) | public class DockerHubV2NamespaceLookupResult {
    method getNamespaces (line 30) | public List<String> getNamespaces() {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ScanResult.java
  class DockerHubV2ScanResult (line 24) | public class DockerHubV2ScanResult<T> {
    method getCount (line 38) | public final int getCount() {
    method getNext (line 42) | public final String getNext() {
    method getPrevious (line 46) | public final String getPrevious() {
    method getResults (line 50) | public final List<T> getResults() {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Tag.java
  class DockerHubV2Tag (line 25) | public class DockerHubV2Tag {
    method getName (line 39) | public String getName() {
    method getFullSize (line 43) | public long getFullSize() {
    method getLastUpdated (line 47) | public String getLastUpdated() {
    method getImages (line 51) | public List<DockerHubV2TagDigest> getImages() {
    method toString (line 55) | @Override
    method hashCode (line 60) | @Override
    method equals (line 65) | @Override

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagDigest.java
  class DockerHubV2TagDigest (line 22) | public class DockerHubV2TagDigest {
    method getSize (line 36) | public long getSize() {
    method getDigest (line 40) | public String getDigest() {
    method getArchitecture (line 44) | public String getArchitecture() {
    method getVariant (line 48) | public String getVariant() {

FILE: src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagListResult.java
  class DockerHubV2TagListResult (line 20) | public class DockerHubV2TagListResult extends DockerHubV2ScanResult<Dock...

FILE: src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java
  class DockerTagFinder (line 28) | public class DockerTagFinder {
    method findVersionedTagMatchingBranch (line 30) | public static DockerTag findVersionedTagMatchingBranch(List<DockerTag>...
    method allManifestsMatch (line 46) | private static boolean allManifestsMatch(final DockerTag namedTag, fin...
    method toMapKeyedByArch (line 72) | private static Map<String, String> toMapKeyedByArch(final List<DockerT...

FILE: src/main/java/io/linuxserver/fleet/exception/SaveException.java
  class SaveException (line 20) | public class SaveException extends Exception {
    method SaveException (line 22) | public SaveException(String message) {
    method SaveException (line 26) | public SaveException(String message, Throwable cause) {

FILE: src/main/java/io/linuxserver/fleet/v2/LoggerOwner.java
  type LoggerOwner (line 22) | public interface LoggerOwner {
    method getLogger (line 24) | Logger getLogger();

FILE: src/main/java/io/linuxserver/fleet/v2/Utils.java
  class Utils (line 20) | public final class Utils {
    method ensureNotNull (line 22) | public static <T> T ensureNotNull(final T obj) {

FILE: src/main/java/io/linuxserver/fleet/v2/cache/AbstractItemCache.java
  class AbstractItemCache (line 27) | public abstract class AbstractItemCache<KEY extends Key, ITEM extends Ha...
    method AbstractItemCache (line 34) | public AbstractItemCache() {
    method clear (line 40) | public final void clear() {
    method registerCacheListener (line 46) | public final void registerCacheListener(final ItemCacheListener<ITEM> ...
    method addItem (line 52) | @Override
    method isEmpty (line 66) | @Override
    method findItem (line 71) | @Override
    method removeItem (line 76) | @Override
    method isItemCached (line 85) | @Override
    method getAllItems (line 90) | @Override
    method addAllItems (line 95) | @Override
    method size (line 100) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/cache/BasicItemCache.java
  class BasicItemCache (line 23) | public final class BasicItemCache<KEY extends Key, ITEM extends HasKey<K...

FILE: src/main/java/io/linuxserver/fleet/v2/cache/ImageCache.java
  class ImageCache (line 23) | public class ImageCache extends AbstractItemCache<ImageKey, Image> {

FILE: src/main/java/io/linuxserver/fleet/v2/cache/ItemCache.java
  type ItemCache (line 25) | public interface ItemCache<KEY extends Key, ITEM extends HasKey<KEY>> {
    method isEmpty (line 27) | boolean isEmpty();
    method addItem (line 29) | void addItem(ITEM item);
    method findItem (line 31) | ITEM findItem(KEY key);
    method removeItem (line 33) | void removeItem(KEY key);
    method isItemCached (line 35) | boolean isItemCached(KEY key);
    method getAllItems (line 37) | Collection<ITEM> getAllItems();
    method addAllItems (line 39) | void addAllItems(Collection<ITEM> items);
    method size (line 41) | int size();
    type ItemCacheListener (line 43) | interface ItemCacheListener<ITEM> {
      method onItemAdded (line 45) | void onItemAdded(final ITEM item);
      method onItemUpdated (line 46) | void onItemUpdated(final ITEM oldItem, final ITEM newItem);
      method onItemRemoved (line 47) | void onItemRemoved(final ITEM item);

FILE: src/main/java/io/linuxserver/fleet/v2/cache/RepositoryCache.java
  class RepositoryCache (line 26) | public class RepositoryCache extends AbstractItemCache<RepositoryKey, Re...
    method lookupImage (line 28) | public final Image lookupImage(final ImageLookupKey lookupKey) {
    method findImage (line 41) | public final Image findImage(final ImageKey imageKey) {

FILE: src/main/java/io/linuxserver/fleet/v2/cache/ScheduleCache.java
  class ScheduleCache (line 23) | public class ScheduleCache extends AbstractItemCache<ScheduleKey, AppSch...
    method isScheduleRunning (line 25) | public final boolean isScheduleRunning(final ScheduleKey scheduleKey) {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/AbstractDockerApiClient.java
  class AbstractDockerApiClient (line 27) | public abstract class AbstractDockerApiClient<D, T, IC extends DockerRes...
    method AbstractDockerApiClient (line 32) | public AbstractDockerApiClient(final IC imageConverter, final TC tagCo...
    method fetchImage (line 37) | @Override
    method fetchAllImages (line 47) | @Override
    method fetchImageTags (line 52) | @Override
    method fetchImageFromApi (line 57) | protected abstract D       fetchImageFromApi(final String imageName);
    method fetchAllImagesFromApi (line 58) | protected abstract List<D> fetchAllImagesFromApi(final String reposito...
    method fetchTagsFromApi (line 59) | protected abstract List<T> fetchTagsFromApi(final String imageName);

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/DockerApiClient.java
  type DockerApiClient (line 25) | public interface DockerApiClient {
    method isRepositoryValid (line 27) | boolean isRepositoryValid(final String repositoryName);
    method fetchImage (line 29) | DockerImage fetchImage(final String imageName);
    method fetchAllImages (line 31) | List<DockerImage> fetchAllImages(final String repositoryName);
    method fetchImageTags (line 33) | List<DockerTag> fetchImageTags(final String imageName);

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/DockerImageNotFoundException.java
  class DockerImageNotFoundException (line 20) | public class DockerImageNotFoundException extends RuntimeException {
    method DockerImageNotFoundException (line 22) | public DockerImageNotFoundException(final String reason) {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/converter/AbstractDockerResponseConverter.java
  class AbstractDockerResponseConverter (line 26) | public abstract class AbstractDockerResponseConverter<D, I> implements D...
    method convert (line 30) | @Override
    method doPlainConvert (line 48) | protected abstract I doPlainConvert(final D dockerApiImage);
    method parseDockerHubDate (line 50) | protected final LocalDateTime parseDockerHubDate(String date) {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/converter/DockerResponseConverter.java
  type DockerResponseConverter (line 20) | public interface DockerResponseConverter<DOCKER_MODEL, INTERNAL_MODEL> {
    method convert (line 22) | INTERNAL_MODEL convert(final DOCKER_MODEL dockerModel);
    method getConverterClass (line 24) | Class<DOCKER_MODEL> getConverterClass();

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubApiClient.java
  class DockerHubApiClient (line 34) | public class DockerHubApiClient extends AbstractDockerApiClient<DockerHu...
    method DockerHubApiClient (line 42) | public DockerHubApiClient(final RestClient restClient,
    method isRepositoryValid (line 49) | @Override
    method fetchImageFromApi (line 59) | @Override
    method fetchAllImagesFromApi (line 79) | @Override
    method fetchTagsFromApi (line 107) | @Override
    method doCall (line 141) | private <T> RestResponse<T> doCall(String url, Class<T> responseType) {
    method isResponseOK (line 152) | private boolean isResponseOK(final RestResponse<?> restResponse) {
    method isResponseUnauthorised (line 156) | private boolean isResponseUnauthorised(RestResponse restResponse) {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubAuthenticator.java
  class DockerHubAuthenticator (line 12) | public class DockerHubAuthenticator implements IDockerHubAuthenticator {
    method DockerHubAuthenticator (line 21) | public DockerHubAuthenticator(final DockerHubCredentials credentials, ...
    method refreshToken (line 37) | public synchronized String refreshToken() {
    method getCurrentToken (line 59) | synchronized String getCurrentToken() {
    method buildAuthHeaders (line 67) | @Override
    class DockerHubTokenResponse (line 75) | static class DockerHubTokenResponse {
      method getToken (line 79) | public String getToken() {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubCredentials.java
  class DockerHubCredentials (line 5) | public class DockerHubCredentials {
    method DockerHubCredentials (line 10) | public DockerHubCredentials(final String username,
    method getUsername (line 16) | public final String getUsername() {
    method getPassword (line 20) | public final String getPassword() {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubImageConverter.java
  class DockerHubImageConverter (line 24) | public class DockerHubImageConverter extends AbstractDockerResponseConve...
    method doPlainConvert (line 26) | @Override
    method getConverterClass (line 37) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubTagConverter.java
  class DockerHubTagConverter (line 26) | public class DockerHubTagConverter extends AbstractDockerResponseConvert...
    method doPlainConvert (line 28) | @Override
    method getConverterClass (line 46) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/IDockerHubAuthenticator.java
  type IDockerHubAuthenticator (line 5) | public interface IDockerHubAuthenticator {
    method buildAuthHeaders (line 7) | Map<String, String> buildAuthHeaders();
    method refreshToken (line 9) | String refreshToken();

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/NoOpDockerHubAuthenticator.java
  class NoOpDockerHubAuthenticator (line 6) | public class NoOpDockerHubAuthenticator implements IDockerHubAuthenticat...
    method buildAuthHeaders (line 8) | @Override
    method refreshToken (line 13) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubContainerRegistryClient.java
  class GitHubContainerRegistryClient (line 26) | public class GitHubContainerRegistryClient extends AbstractDockerApiClie...
    method GitHubContainerRegistryClient (line 28) | public GitHubContainerRegistryClient() {
    method fetchImageFromApi (line 32) | @Override
    method fetchAllImagesFromApi (line 37) | @Override
    method fetchTagsFromApi (line 42) | @Override
    method isRepositoryValid (line 47) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubImageConverter.java
  class GitHubImageConverter (line 24) | public class GitHubImageConverter extends AbstractDockerResponseConverte...
    method doPlainConvert (line 26) | @Override
    method getConverterClass (line 31) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubTagConverter.java
  class GitHubTagConverter (line 24) | public class GitHubTagConverter extends AbstractDockerResponseConverter<...
    method doPlainConvert (line 26) | @Override
    method getConverterClass (line 31) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubImage.java
  class GitHubImage (line 20) | public class GitHubImage {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubTag.java
  class GitHubTag (line 20) | public class GitHubTag {

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiRequest.java
  type AsyncDockerApiRequest (line 23) | public interface AsyncDockerApiRequest<R extends AsyncDockerApiResponse>...
    method getImageKey (line 24) | ImageKey getImageKey();

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiResponse.java
  type AsyncDockerApiResponse (line 22) | public interface AsyncDockerApiResponse extends AsyncTaskResponse {
    method handleDockerApiResponse (line 23) | void handleDockerApiResponse();

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiDelegate.java
  class DockerApiDelegate (line 32) | public class DockerApiDelegate implements AsyncTaskDelegate {
    method DockerApiDelegate (line 37) | public DockerApiDelegate(final FleetAppController controller,
    method isRepositoryValid (line 43) | public final boolean isRepositoryValid(final String repositoryName) {
    method getImagesForRepository (line 47) | public final List<DockerImage> getImagesForRepository(final Repository...
    method getCurrentImageView (line 51) | public final DockerImage getCurrentImageView(final ImageKey imageKey) {
    method getController (line 64) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiTaskConsumer.java
  class DockerApiTaskConsumer (line 24) | public final class DockerApiTaskConsumer extends AbstractTaskQueueConsum...
    method DockerApiTaskConsumer (line 26) | public DockerApiTaskConsumer(final SynchronisationService syncService) {
    method handleTaskResponse (line 34) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageMissingUpdateResponse.java
  class DockerImageMissingUpdateResponse (line 23) | public class DockerImageMissingUpdateResponse extends DockerImageUpdateR...
    method DockerImageMissingUpdateResponse (line 25) | public DockerImageMissingUpdateResponse(final FleetAppController contr...
    method handleDockerApiResponse (line 30) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateRequest.java
  class DockerImageUpdateRequest (line 24) | public class DockerImageUpdateRequest extends AbstractAppTask<DockerApiD...
    method DockerImageUpdateRequest (line 28) | public DockerImageUpdateRequest(final ImageKey imageKey) {
    method performTaskInternal (line 33) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateResponse.java
  class DockerImageUpdateResponse (line 24) | public class DockerImageUpdateResponse implements AsyncDockerApiResponse {
    method DockerImageUpdateResponse (line 30) | public DockerImageUpdateResponse(final FleetAppController controller,
    method getController (line 38) | protected final FleetAppController getController() {
    method handleDockerApiResponse (line 42) | @Override
    method handleResponse (line 47) | @Override
    method toString (line 52) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/docker/queue/TaskQueue.java
  class TaskQueue (line 27) | public class TaskQueue<TASK extends AsyncTask<?, ?>> {
    method TaskQueue (line 33) | public TaskQueue() {
    method submitTask (line 37) | public final boolean submitTask(final TASK task) {
    method size (line 49) | public final int size() {
    method retrieveNextTask (line 53) | public final TASK retrieveNextTask() throws InterruptedException {
    method isEmpty (line 57) | public final boolean isEmpty() {

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/HttpException.java
  class HttpException (line 20) | public class HttpException extends RuntimeException {
    method HttpException (line 22) | public HttpException(String message) {
    method HttpException (line 26) | public HttpException(String message, Throwable cause) {

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/RestClient.java
  class RestClient (line 47) | public class RestClient {
    method RestClient (line 56) | public RestClient() {
    method setMarshallingStrategy (line 63) | private void setMarshallingStrategy(MarshallingStrategy marshallingStr...
    method executeGet (line 69) | public <T> RestResponse<T> executeGet(String url, Map<String, String> ...
    method executePost (line 82) | public <T> RestResponse<T> executePost(String url, Map<String, String>...
    method executeBaseRequest (line 100) | private <T> RestResponse<T> executeBaseRequest(Class<T> responseType, ...
    method parseQueryParameters (line 138) | private String parseQueryParameters(Map<String, String> queryParameter...

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/RestResponse.java
  class RestResponse (line 22) | public class RestResponse<T> {
    method RestResponse (line 27) | RestResponse(int statusCode) {
    method RestResponse (line 31) | RestResponse(PayloadProxy<T> payloadProxy, int statusCode) {
    method getPayload (line 37) | public T getPayload() {
    method getStatusCode (line 41) | public int getStatusCode() {

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/marshalling/JacksonMarshallingStrategy.java
  class JacksonMarshallingStrategy (line 30) | public class JacksonMarshallingStrategy implements MarshallingStrategy {
    method unmarshall (line 39) | @Override
    method marshall (line 44) | @Override
    method getContentType (line 49) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/marshalling/MarshallingStrategy.java
  type MarshallingStrategy (line 5) | public interface MarshallingStrategy {
    method unmarshall (line 18) | <T> T unmarshall(String value, Class<T> classType) throws IOException;
    method marshall (line 29) | String marshall(Object value) throws IOException;
    method getContentType (line 36) | String getContentType();

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/proxy/LazyLoadPayloadProxy.java
  class LazyLoadPayloadProxy (line 25) | public class LazyLoadPayloadProxy<T> implements PayloadProxy<T> {
    method LazyLoadPayloadProxy (line 31) | public LazyLoadPayloadProxy(MarshallingStrategy marshallingStrategy, S...
    method get (line 38) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/client/rest/proxy/PayloadProxy.java
  type PayloadProxy (line 20) | public interface PayloadProxy<T> {
    method get (line 22) | T get();

FILE: src/main/java/io/linuxserver/fleet/v2/db/AbstractDAO.java
  class AbstractDAO (line 28) | public class AbstractDAO implements LoggerOwner {
    method AbstractDAO (line 34) | public AbstractDAO(final DatabaseProvider databaseProvider) {
    method getConnection (line 38) | protected final Connection getConnection() throws SQLException {
    method getLogger (line 42) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/db/DbUpdateStatus.java
  type DbUpdateStatus (line 20) | public enum DbUpdateStatus {
    method isExpected (line 24) | public final boolean isExpected(final DbUpdateStatus expected) {
    method isExists (line 28) | public final boolean isExists() {
    method isInserted (line 32) | public final boolean isInserted() {
    method isUpdated (line 36) | public final boolean isUpdated() {
    method isNoChange (line 40) | public final boolean isNoChange() {

FILE: src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java
  class DefaultImageDAO (line 43) | public class DefaultImageDAO extends AbstractDAO implements ImageDAO {
    method DefaultImageDAO (line 70) | public DefaultImageDAO(final DatabaseProvider databaseConnection) {
    method fetchImage (line 75) | @Override
    method storeImage (line 89) | @Override
    method storeImageMetaData (line 133) | @Override
    method createImageOutline (line 153) | @Override
    method createTagBranchOutline (line 195) | @Override
    method removeImage (line 221) | @Override
    method fetchRepository (line 249) | @Override
    method createRepositoryOutline (line 261) | @Override
    method fetchAllRepositories (line 302) | @Override
    method storeRepository (line 325) | @Override
    method removeRepository (line 357) | @Override
    method storeCoreMetaData (line 386) | private void storeCoreMetaData(final Connection connection, final Imag...
    method storeExternalUrls (line 406) | private void storeExternalUrls(final Connection connection, final Imag...
    method storeTagBranches (line 429) | private void storeTagBranches(final Connection connection, final Image...
    method removeOrphans (line 455) | private void removeOrphans(final Connection connection,
    method storeTagDigests (line 470) | private void storeTagDigests(final Connection connection, final TagBra...
    method makeRepositories (line 490) | private List<Repository> makeRepositories(final List<RepositoryKey> re...
    method makeImage (line 510) | private Image makeImage(final ImageKey imageKey, final Connection conn...
    method makeImages (line 526) | private List<Image> makeImages(final List<ImageKey> imageKeys, final C...
    method makeOneImage (line 547) | private Image makeOneImage(final Connection connection, final Callable...
    method makeImageMetaData (line 570) | private ImageMetaData makeImageMetaData(final Connection connection, f...
    method makeCoreMeta (line 577) | private ImageCoreMeta makeCoreMeta(final Connection connection, final ...
    method makeExternalUrls (line 587) | private List<ExternalUrl> makeExternalUrls(final Connection connection...
    method makePullHistory (line 608) | private ImagePullHistory makePullHistory(final Connection connection, ...
    method makeImageKey (line 638) | private ImageKey makeImageKey(final ResultSet results) throws SQLExcep...
    method makeRepository (line 645) | private Repository makeRepository(final RepositoryKey repositoryKey, f...
    method makeOneRepository (line 654) | private Repository makeOneRepository(final Connection connection, fina...
    method enrichRepositoryWithImages (line 671) | private void enrichRepositoryWithImages(final Repository repository, f...
    method makeRepositoryKey (line 688) | private RepositoryKey makeRepositoryKey(final ResultSet results) throw...
    method makeSyncSpec (line 694) | private ItemSyncSpec makeSyncSpec(final ResultSet results) throws SQLE...
    method makeCountData (line 703) | private ImageCountData makeCountData(final ResultSet results) throws S...
    method enrichImageWithTagBranches (line 709) | private void enrichImageWithTagBranches(final Image image, final Conne...
    method makeTagBranch (line 722) | private TagBranch makeTagBranch(final ResultSet results, final Connect...
    method makeTagBranchKey (line 732) | private TagBranchKey makeTagBranchKey(ResultSet results, ImageKey imag...
    method makeTag (line 736) | private Tag makeTag(final ResultSet results, final Connection connecti...
    method makeTagDigests (line 743) | private Set<TagDigest> makeTagDigests(final Connection connection, fin...
    method makeTagDigest (line 760) | private TagDigest makeTagDigest(final ResultSet results) throws SQLExc...

FILE: src/main/java/io/linuxserver/fleet/v2/db/DefaultScheduleDAO.java
  class DefaultScheduleDAO (line 33) | public class DefaultScheduleDAO extends AbstractDAO implements ScheduleD...
    method DefaultScheduleDAO (line 37) | public DefaultScheduleDAO(final DatabaseProvider databaseProvider) {
    method fetchScheduleSpecs (line 41) | @Override
    method makeOneScheduleSpec (line 68) | @SuppressWarnings("unchecked")

FILE: src/main/java/io/linuxserver/fleet/v2/db/DefaultUserDAO.java
  class DefaultUserDAO (line 32) | public class DefaultUserDAO extends AbstractDAO implements UserDAO {
    method DefaultUserDAO (line 41) | public DefaultUserDAO(DatabaseProvider databaseProvider) {
    method fetchUser (line 45) | @Override
    method lookUpUser (line 69) | @Override
    method createUser (line 93) | @Override
    method fetchAllUsers (line 129) | @Override
    method removeUser (line 153) | @Override
    method updateUser (line 173) | @Override
    method makeOneUser (line 210) | private User makeOneUser(final ResultSet results) throws SQLException {

FILE: src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java
  type ImageDAO (line 33) | public interface ImageDAO {
    method fetchImage (line 35) | Image fetchImage(final ImageKey imageKey);
    method storeImage (line 37) | InsertUpdateResult<Image> storeImage(final Image image);
    method storeImageMetaData (line 39) | InsertUpdateResult<Image> storeImageMetaData(final Image image);
    method createImageOutline (line 41) | InsertUpdateResult<Image> createImageOutline(final ImageOutlineRequest...
    method createTagBranchOutline (line 43) | InsertUpdateResult<TagBranch> createTagBranchOutline(final TagBranchOu...
    method removeImage (line 45) | InsertUpdateResult<Void> removeImage(final Image image);
    method fetchRepository (line 47) | Repository fetchRepository(final RepositoryKey repositoryKey);
    method createRepositoryOutline (line 49) | InsertUpdateResult<Repository> createRepositoryOutline(final Repositor...
    method fetchAllRepositories (line 51) | List<Repository> fetchAllRepositories();
    method storeRepository (line 53) | InsertUpdateResult<Repository> storeRepository(Repository repository);
    method removeRepository (line 55) | InsertUpdateResult<Void> removeRepository(final Repository repository);

FILE: src/main/java/io/linuxserver/fleet/v2/db/ImageTemplateFactory.java
  class ImageTemplateFactory (line 32) | public class ImageTemplateFactory {
    method makeTemplateHolder (line 47) | public final ImageTemplateHolder makeTemplateHolder(final Connection c...
    method storeImageTemplates (line 78) | public final void storeImageTemplates(final Connection connection, fin...
    method enrichHolderWithTemplates (line 130) | private void enrichHolderWithTemplates(final Connection connection, fi...
    method clearTemplates (line 173) | private void clearTemplates(final CallableStatement clearTemplatesCall...
    method joinStream (line 192) | private <T, R extends CharSequence> String joinStream(final List<T> li...
    method storeTemplateBase (line 196) | private void storeTemplateBase(final CallableStatement storeBaseCall, ...
    method storeTemplateCapabilities (line 213) | private void storeTemplateCapabilities(final CallableStatement storeCa...
    method storeTemplateDevices (line 227) | private void storeTemplateDevices(final CallableStatement storeDeviceC...
    method storeTemplateEnv (line 241) | private void storeTemplateEnv(final CallableStatement storeEnvCall, fi...
    method storeTemplateVolumes (line 256) | private void storeTemplateVolumes(final CallableStatement storeVolumeC...
    method storeTemplatePorts (line 271) | private void storeTemplatePorts(final CallableStatement storePortCall,...

FILE: src/main/java/io/linuxserver/fleet/v2/db/ScheduleDAO.java
  type ScheduleDAO (line 24) | public interface ScheduleDAO {
    method fetchScheduleSpecs (line 26) | Set<ScheduleSpec> fetchScheduleSpecs();

FILE: src/main/java/io/linuxserver/fleet/v2/db/UserDAO.java
  type UserDAO (line 27) | public interface UserDAO {
    method fetchUser (line 29) | User fetchUser(UserKey userKey);
    method lookUpUser (line 31) | User lookUpUser(String username);
    method createUser (line 33) | InsertUpdateResult<User> createUser(UserOutlineRequest request);
    method fetchAllUsers (line 35) | List<User> fetchAllUsers();
    method removeUser (line 37) | InsertUpdateResult<Void> removeUser(User user);
    method updateUser (line 39) | InsertUpdateResult<User> updateUser(User updatedUser);

FILE: src/main/java/io/linuxserver/fleet/v2/db/Utils.java
  class Utils (line 26) | class Utils {
    method setNullableInt (line 28) | static void setNullableInt(CallableStatement call, int position, Integ...
    method setNullableLong (line 37) | static void setNullableLong(CallableStatement call, int position, Long...
    method setNullableString (line 46) | static void setNullableString(CallableStatement call, int position, St...
    method setNullableTimestamp (line 55) | static void setNullableTimestamp(CallableStatement call, int position,...
    method safeClose (line 64) | static void safeClose(CallableStatement call) {

FILE: src/main/java/io/linuxserver/fleet/v2/file/FileManager.java
  class FileManager (line 30) | public class FileManager extends AbstractAppService {
    method FileManager (line 37) | public FileManager(final FleetAppController controller) {
    method saveImageLogo (line 44) | public final FilePathDetails saveImageLogo(final ImageAppLogo logo) {
    method makeFilePathDetails (line 85) | private FilePathDetails makeFilePathDetails(final ImageAppLogo logo) {
    method makePathSafeFileName (line 92) | private String makePathSafeFileName(final ImageKey key) {
    method writeDataToFile (line 96) | private void writeDataToFile(final ImageAppLogo logo, final File logoF...
    method makeImageUploadDir (line 109) | private void makeImageUploadDir() {

FILE: src/main/java/io/linuxserver/fleet/v2/key/AbstractDatabaseKey.java
  class AbstractDatabaseKey (line 20) | public abstract class AbstractDatabaseKey implements Key {
    method AbstractDatabaseKey (line 24) | public AbstractDatabaseKey(final Integer id) {
    method getId (line 28) | @Override
    method equals (line 33) | @Override
    method hashCode (line 47) | @Override
    method toString (line 57) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java
  class AbstractHasKey (line 22) | public abstract class AbstractHasKey<KEY extends Key> implements HasKey<...
    method AbstractHasKey (line 26) | public AbstractHasKey(final KEY key) {
    method getKey (line 30) | @Override
    method hashCode (line 35) | @Override
    method equals (line 40) | @Override
    method toString (line 50) | @Override
    method compareTo (line 55) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/AbstractLookupKey.java
  class AbstractLookupKey (line 20) | public abstract class AbstractLookupKey<TYPE extends HasKey<?>> implemen...
    method AbstractLookupKey (line 24) | public AbstractLookupKey(final String query) {
    method getQuery (line 28) | public final String getQuery() {
    method getId (line 32) | @Override
    method toString (line 37) | @Override
    method isLookupKeyFor (line 42) | public abstract boolean isLookupKeyFor(final TYPE type);

FILE: src/main/java/io/linuxserver/fleet/v2/key/AlertKey.java
  class AlertKey (line 22) | public class AlertKey extends AbstractLookupKey<AppAlert> {
    method AlertKey (line 24) | public AlertKey(String query) {
    method isLookupKeyFor (line 28) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/HasKey.java
  type HasKey (line 20) | public interface HasKey<KEY extends Key> extends Comparable<HasKey<KEY>> {
    method getKey (line 22) | KEY getKey();

FILE: src/main/java/io/linuxserver/fleet/v2/key/ImageKey.java
  class ImageKey (line 20) | public class ImageKey extends AbstractDatabaseKey {
    method ImageKey (line 27) | @Deprecated
    method ImageKey (line 32) | public ImageKey(final Integer id, final String name, final RepositoryK...
    method parse (line 39) | public static ImageKey parse(final String keyAsString) {
    method getAsLookupKey (line 57) | public final ImageLookupKey getAsLookupKey() {
    method getAsRepositoryAndImageName (line 61) | public final String getAsRepositoryAndImageName() {
    method getRepositoryKey (line 65) | public final RepositoryKey getRepositoryKey() {
    method getName (line 69) | public final String getName() {
    method toString (line 73) | @Override
    method equals (line 78) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/ImageLookupKey.java
  class ImageLookupKey (line 22) | public class ImageLookupKey extends AbstractLookupKey<Image> {
    method ImageLookupKey (line 29) | public ImageLookupKey(final String query) {
    method isLookupKeyFor (line 43) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/Key.java
  type Key (line 22) | public interface Key {
    method getId (line 24) | Integer getId();

FILE: src/main/java/io/linuxserver/fleet/v2/key/RepositoryKey.java
  class RepositoryKey (line 20) | public class RepositoryKey extends AbstractDatabaseKey {
    method parse (line 26) | public static RepositoryKey parse(final String keyAsString) {
    method RepositoryKey (line 41) | public RepositoryKey(final Integer id, final String name) {
    method cloneWithId (line 46) | public RepositoryKey cloneWithId(int id) {
    method getName (line 50) | public final String getName() {
    method toString (line 54) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/key/ScheduleKey.java
  class ScheduleKey (line 20) | public class ScheduleKey extends AbstractDatabaseKey {
    method ScheduleKey (line 22) | public ScheduleKey(Integer id) {

FILE: src/main/java/io/linuxserver/fleet/v2/key/TagBranchKey.java
  class TagBranchKey (line 20) | public class TagBranchKey extends AbstractDatabaseKey {
    method TagBranchKey (line 24) | public TagBranchKey(final Integer id, final ImageKey imageKey) {
    method getImageKey (line 29) | public final ImageKey getImageKey() {

FILE: src/main/java/io/linuxserver/fleet/v2/key/UserKey.java
  class UserKey (line 20) | public class UserKey extends AbstractDatabaseKey {
    method UserKey (line 22) | public UserKey() {
    method UserKey (line 26) | public UserKey(Integer id) {

FILE: src/main/java/io/linuxserver/fleet/v2/service/AbstractAppService.java
  class AbstractAppService (line 26) | public class AbstractAppService implements LoggerOwner {
    method AbstractAppService (line 31) | public AbstractAppService(FleetAppController controller) {
    method getController (line 36) | public final FleetAppController getController() {
    method getProperties (line 40) | public final AppProperties getProperties() {
    method getLogger (line 44) | public final Logger getLogger() {

FILE: src/main/java/io/linuxserver/fleet/v2/service/ImageService.java
  class ImageService (line 45) | public class ImageService extends AbstractAppService {
    method ImageService (line 54) | public ImageService(final FleetAppController controller, final ImageDA...
    method reloadCache (line 65) | public final void reloadCache() {
    method updateImageSpec (line 73) | public final Image updateImageSpec(final ImageKey imageKey, final Item...
    method updateRepositorySpec (line 84) | public final Repository updateRepositorySpec(final RepositoryKey repos...
    method createRepositoryOutline (line 106) | public Repository createRepositoryOutline(final RepositoryOutlineReque...
    method createImageOutline (line 122) | public final Image createImageOutline(final ImageOutlineRequest reques...
    method removeImage (line 139) | public final void removeImage(final ImageKey imageKey) {
    method removeRepository (line 150) | public final void removeRepository(final RepositoryKey repositoryKey) {
    method storeImage (line 167) | public final Image storeImage(final Image image) {
    method storeImageTemplateMetaData (line 171) | public final Image storeImageTemplateMetaData(final Image image) {
    method getImage (line 175) | public final Image getImage(final ImageKey imageKey) {
    method lookupImage (line 179) | public final Image lookupImage(final ImageLookupKey imageLookupKey) {
    method getRepository (line 183) | public final Repository getRepository(final RepositoryKey repositoryKe...
    method getFirstRepository (line 187) | public final Repository getFirstRepository() {
    method getAllRepositories (line 191) | public final List<Repository> getAllRepositories() {
    method getAllShownRepositories (line 195) | public final List<Repository> getAllShownRepositories() {
    method applyImageUpstreamUpdate (line 199) | public Image applyImageUpstreamUpdate(final ImageKey imageKey, final D...
    method trackBranchOnImage (line 229) | public void trackBranchOnImage(final ImageKey imageKey, final String b...
    method removeTrackedBranch (line 247) | public void removeTrackedBranch(final ImageKey imageKey, final String ...
    method updateImageGeneralInfo (line 261) | public void updateImageGeneralInfo(final ImageKey imageKey, final Imag...
    method updateImageExternalUrls (line 283) | public void updateImageExternalUrls(final ImageKey imageKey, final Ima...
    method updateImageTemplate (line 294) | public void updateImageTemplate(final ImageKey imageKey, final ImageTe...
    method storeImage (line 303) | private synchronized Image storeImage(final Image image, final ImageSt...
    method findImage (line 318) | private Image findImage(ImageKey imageKey) {
    method updateCache (line 327) | private void updateCache(final Image storedImage) {
    type ImageStorage (line 338) | @FunctionalInterface
      method store (line 340) | InsertUpdateResult<Image> store(final Image image);

FILE: src/main/java/io/linuxserver/fleet/v2/service/ScheduleService.java
  class ScheduleService (line 39) | public class ScheduleService extends AbstractAppService {
    method ScheduleService (line 48) | public ScheduleService(final FleetAppController controller, final Sche...
    method initialiseSchedules (line 55) | public final void initialiseSchedules() {
    method forceRun (line 73) | public final AppSchedule forceRun(final ScheduleKey scheduleKey) {
    method getLoadedSchedules (line 98) | public final List<AppSchedule> getLoadedSchedules() {
    method loadSchedule (line 102) | private AppSchedule loadSchedule(final ScheduleSpec spec) {
    method loadOneSchedule (line 117) | private void loadOneSchedule(final AppSchedule schedule) {
    method loadOneScheduleImmediately (line 121) | private void loadOneScheduleImmediately(final AppSchedule schedule) {
    method loadInternal (line 125) | private void loadInternal(final AppSchedule schedule, final TimeWithUn...
    class ScheduleWrapper (line 139) | public static class ScheduleWrapper extends AbstractHasKey<ScheduleKey> {
      method ScheduleWrapper (line 144) | public ScheduleWrapper(final AppSchedule schedule, final ScheduledFu...
      method getFuture (line 150) | public final ScheduledFuture<?> getFuture() {
      method getSchedule (line 154) | public final AppSchedule getSchedule() {
      method getName (line 158) | public final String getName() {

FILE: src/main/java/io/linuxserver/fleet/v2/service/SynchronisationService.java
  class SynchronisationService (line 35) | public class SynchronisationService extends AbstractAppService {
    method SynchronisationService (line 40) | public SynchronisationService(FleetAppController controller) {
    method synchroniseUpstreamRepository (line 48) | public final void synchroniseUpstreamRepository(final Repository repos...
    method synchroniseCachedRepository (line 78) | public final void synchroniseCachedRepository(final Repository reposit...
    method synchroniseImage (line 96) | public final boolean synchroniseImage(final ImageKey imageKey) {
    method getSyncQueue (line 100) | public final TaskQueue<DockerImageUpdateRequest> getSyncQueue() {
    method getConfiguredDockerDelegate (line 104) | public final DockerApiDelegate getConfiguredDockerDelegate() {
    method isConsumerRunning (line 108) | public final boolean isConsumerRunning() {
    method isSyncQueueEmpty (line 112) | public final boolean isSyncQueueEmpty() {

FILE: src/main/java/io/linuxserver/fleet/v2/service/UserService.java
  class UserService (line 34) | public class UserService extends AbstractAppService {
    method UserService (line 39) | public UserService(final FleetAppController controller,
    method authenticateCredentials (line 48) | public final AuthenticationResult authenticateCredentials(final String...
    method lookUpUser (line 52) | public final User lookUpUser(final String username) {
    method fetchUser (line 56) | public final User fetchUser(final UserKey userKey) {
    method fetchAllUsers (line 60) | public final List<User> fetchAllUsers() {
    method removeUser (line 64) | public final void removeUser(final User user) {
    method updateUserPassword (line 68) | public final User updateUserPassword(final User user, final String pas...
    method createUserAndHashPassword (line 81) | public final User createUserAndHashPassword(final UserOutlineRequest u...
    method createUser (line 85) | public final User createUser(final UserOutlineRequest userOutlineReque...
    method createInitialAdminUser (line 96) | private void createInitialAdminUser() {

FILE: src/main/java/io/linuxserver/fleet/v2/service/util/TemplateMerger.java
  class TemplateMerger (line 27) | public class TemplateMerger {
    method mergeTemplateRequestIntoImage (line 31) | public final Image mergeTemplateRequestIntoImage(final Image image, fi...
    method makeTemplateHolder (line 43) | private ImageTemplateHolder makeTemplateHolder(final ImageTemplateRequ...
    method addPorts (line 51) | private void addPorts(final ImageTemplateRequest request, final ImageT...
    method addVolumes (line 61) | private void addVolumes(final ImageTemplateRequest request, final Imag...
    method addEnvironment (line 71) | private void addEnvironment(final ImageTemplateRequest request, final ...
    method addDevices (line 77) | private void addDevices(final ImageTemplateRequest request, final Imag...
    method addMisc (line 85) | private void addMisc(final ImageTemplateRequest request, final ImageTe...

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AbstractAppTask.java
  class AbstractAppTask (line 24) | public abstract class AbstractAppTask<DELEGATE extends AsyncTaskDelegate...
    method AbstractAppTask (line 30) | public AbstractAppTask(final String name) {
    method performTaskOn (line 39) | @Override
    method getLogger (line 50) | @Override
    method performTaskInternal (line 55) | protected abstract RESPONSE performTaskInternal(final DELEGATE delegate);
    method toString (line 57) | @Override
    method hashCode (line 62) | @Override
    method equals (line 67) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AbstractAppThread.java
  class AbstractAppThread (line 24) | public abstract class AbstractAppThread extends Thread {
    method AbstractAppThread (line 32) | public AbstractAppThread(final FleetAppController controller, final St...
    method getController (line 37) | public final FleetAppController getController() {
    method run (line 41) | @Override
    method isThreadRunning (line 62) | public final boolean isThreadRunning() {
    method getLogger (line 66) | protected final Logger getLogger() {
    method doRunSinglePass (line 70) | protected abstract void doRunSinglePass() throws Exception;

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AbstractTaskQueueConsumer.java
  class AbstractTaskQueueConsumer (line 23) | public abstract class AbstractTaskQueueConsumer<DELEGATE extends AsyncTa...
    method AbstractTaskQueueConsumer (line 29) | public AbstractTaskQueueConsumer(final FleetAppController controller,
    method doRunSinglePass (line 38) | @Override
    method handleTaskResponse (line 55) | protected abstract void handleTaskResponse(final R response);

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AsyncTask.java
  type AsyncTask (line 20) | public interface AsyncTask<DELEGATE extends AsyncTaskDelegate, RESPONSE ...
    method performTaskOn (line 21) | RESPONSE performTaskOn(DELEGATE delegate);

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AsyncTaskDelegate.java
  type AsyncTaskDelegate (line 22) | public interface AsyncTaskDelegate {
    method getController (line 24) | FleetAppController getController();

FILE: src/main/java/io/linuxserver/fleet/v2/thread/AsyncTaskResponse.java
  type AsyncTaskResponse (line 20) | public interface AsyncTaskResponse {
    method handleResponse (line 21) | void handleResponse();

FILE: src/main/java/io/linuxserver/fleet/v2/thread/TaskExecutionException.java
  class TaskExecutionException (line 20) | public class TaskExecutionException extends RuntimeException {
    method TaskExecutionException (line 22) | public TaskExecutionException(final Exception cause) {

FILE: src/main/java/io/linuxserver/fleet/v2/thread/TaskResponseControllerProxy.java
  class TaskResponseControllerProxy (line 22) | public class TaskResponseControllerProxy<R extends AsyncTaskResponse> im...
    method TaskResponseControllerProxy (line 27) | public TaskResponseControllerProxy(final FleetAppController controller...
    method handleResponse (line 32) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/ThreadStatus.java
  type ThreadStatus (line 20) | public enum ThreadStatus {

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/AbstractAppSchedule.java
  class AbstractAppSchedule (line 31) | public abstract class AbstractAppSchedule extends AbstractHasKey<Schedul...
    method AbstractAppSchedule (line 42) | public AbstractAppSchedule(final ScheduleSpec spec,
    method getController (line 53) | protected final FleetAppController getController() {
    method getSpec (line 57) | public final ScheduleSpec getSpec() {
    method getName (line 61) | @Override
    method getLastRunTime (line 66) | @Override
    method getNextRunTime (line 71) | @Override
    method getLastRunDuration (line 89) | @Override
    method getInterval (line 94) | @Override
    method getDelay (line 99) | @Override
    method getLogger (line 104) | @Override
    method run (line 109) | @Override
    method toString (line 136) | @Override
    method isAllowedToExecute (line 141) | protected boolean isAllowedToExecute() {

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/AppSchedule.java
  type AppSchedule (line 26) | public interface AppSchedule extends HasKey<ScheduleKey>, Runnable {
    method getName (line 28) | String getName();
    method getLastRunTime (line 30) | LocalDateTime getLastRunTime();
    method getNextRunTime (line 32) | LocalDateTime getNextRunTime();
    method getLastRunDuration (line 34) | Duration getLastRunDuration();
    method getDelay (line 36) | TimeWithUnit getDelay();
    method getInterval (line 38) | TimeWithUnit getInterval();
    method executeSchedule (line 40) | void executeSchedule();

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java
  class CheckAppVersionSchedule (line 22) | public class CheckAppVersionSchedule extends AbstractAppSchedule {
    method CheckAppVersionSchedule (line 24) | public CheckAppVersionSchedule(final ScheduleSpec spec,
    method executeSchedule (line 29) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/ScheduleSpec.java
  class ScheduleSpec (line 23) | public final class ScheduleSpec extends AbstractHasKey<ScheduleKey> {
    method ScheduleSpec (line 30) | private ScheduleSpec(final ScheduleKey key,
    method makeInitial (line 43) | public static ScheduleSpec makeInitial(final ScheduleKey key,
    method getScheduleName (line 55) | public final String getScheduleName() {
    method getInterval (line 59) | public final TimeWithUnit getInterval() {
    method getDelayOffset (line 63) | public final TimeWithUnit getDelayOffset() {
    method getScheduleClass (line 67) | public final Class<? extends AppSchedule> getScheduleClass() {

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java
  class TidyHistoricDataSchedule (line 22) | public class TidyHistoricDataSchedule extends AbstractAppSchedule {
    method TidyHistoricDataSchedule (line 24) | public TidyHistoricDataSchedule(final ScheduleSpec spec,
    method executeSchedule (line 29) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/TimeWithUnit.java
  class TimeWithUnit (line 23) | public class TimeWithUnit {
    method TimeWithUnit (line 30) | public TimeWithUnit(final long timeDuration, final TimeUnit timeUnit) {
    method valueOf (line 36) | public static TimeWithUnit valueOf(final String value) {
    method convertToLowestUnit (line 47) | public final TimeWithUnit convertToLowestUnit(final TimeWithUnit other...
    method getTimeDuration (line 57) | public final long getTimeDuration() {
    method getChronoUnit (line 61) | public final ChronoUnit getChronoUnit() {
    method getTimeUnit (line 65) | public final TimeUnit getTimeUnit() {
    method isGreaterThanZero (line 69) | public final boolean isGreaterThanZero() {
    method toString (line 73) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/cache/RefreshCacheSchedule.java
  class RefreshCacheSchedule (line 24) | public final class RefreshCacheSchedule extends AbstractAppSchedule {
    method RefreshCacheSchedule (line 26) | public RefreshCacheSchedule(final ScheduleSpec spec,
    method executeSchedule (line 31) | @Override
    method isAllowedToExecute (line 36) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/AllImagesSyncSchedule.java
  class AllImagesSyncSchedule (line 27) | public final class AllImagesSyncSchedule extends AbstractAppSchedule {
    method AllImagesSyncSchedule (line 29) | public AllImagesSyncSchedule(final ScheduleSpec spec,
    method executeSchedule (line 34) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/CleanRemovedImagesSchedule.java
  class CleanRemovedImagesSchedule (line 30) | public final class CleanRemovedImagesSchedule extends AbstractAppSchedule {
    method CleanRemovedImagesSchedule (line 32) | public CleanRemovedImagesSchedule(final ScheduleSpec spec,
    method executeSchedule (line 37) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/GetMissingImagesSchedule.java
  class GetMissingImagesSchedule (line 27) | public final class GetMissingImagesSchedule extends AbstractAppSchedule {
    method GetMissingImagesSchedule (line 29) | public GetMissingImagesSchedule(final ScheduleSpec spec,
    method executeSchedule (line 34) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/AbstractSyncItem.java
  class AbstractSyncItem (line 27) | public abstract class AbstractSyncItem<KEY extends Key, ITEM extends Abs...
    method AbstractSyncItem (line 31) | public AbstractSyncItem(final KEY key, final ItemSyncSpec syncSpec) {
    method cloneWithSyncSpec (line 36) | public abstract ITEM cloneWithSyncSpec(final ItemSyncSpec syncSpec);
    method getSpec (line 38) | public final ItemSyncSpec getSpec() {
    method isSyncEnabled (line 42) | @Override
    method isStable (line 47) | @Override
    method isDeprecated (line 52) | @Override
    method getVersionMask (line 57) | @Override
    method isHidden (line 62) | @Override
    method getMaskedVersion (line 67) | public final String getMaskedVersion(final Tag tag) {
    method extractMaskedVersion (line 76) | private String extractMaskedVersion(final String tagVersion) {

FILE: src/main/java/io/linuxserver/fleet/v2/types/AppAlert.java
  class AppAlert (line 26) | public class AppAlert extends AbstractHasKey<AlertKey> {
    method AppAlert (line 33) | private AppAlert(final AlertKey key,
    method makeAlert (line 46) | public static AppAlert makeAlert(final AlertLevel alertLevel, final St...
    method getAlertDate (line 55) | public final LocalDateTime getAlertDate() {
    method getSubject (line 59) | public final String getSubject() {
    method getAlertMessage (line 63) | public final String getAlertMessage() {
    method getAlertLevel (line 67) | public final AlertLevel getAlertLevel() {
    method isSystemAlert (line 71) | public final boolean isSystemAlert() {
    type AlertLevel (line 75) | public enum AlertLevel {
      method isInfo (line 79) | public final boolean isInfo() {
      method isSystem (line 83) | public final boolean isSystem() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/FilePathDetails.java
  class FilePathDetails (line 20) | public class FilePathDetails {
    method FilePathDetails (line 26) | public FilePathDetails(final String fileNameWithExtension,
    method getFileNameWithExtension (line 35) | public final String getFileNameWithExtension() {
    method getFullAbsolutePath (line 39) | public final String getFullAbsolutePath() {
    method getPublicSafePathWithFileName (line 43) | public final String getPublicSafePathWithFileName() {
    method getFullAbsolutePathWithFileName (line 47) | public final String getFullAbsolutePathWithFileName() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/HasSyncSpec.java
  type HasSyncSpec (line 20) | public interface HasSyncSpec {
    method isSyncEnabled (line 22) | boolean isSyncEnabled();
    method isStable (line 24) | boolean isStable();
    method isDeprecated (line 26) | boolean isDeprecated();
    method getVersionMask (line 28) | String getVersionMask();
    method isHidden (line 30) | boolean isHidden();

FILE: src/main/java/io/linuxserver/fleet/v2/types/Image.java
  class Image (line 30) | public class Image extends AbstractSyncItem<ImageKey, Image> {
    method Image (line 40) | public Image(final ImageKey key,
    method cloneForUpdate (line 56) | public final Image cloneForUpdate(final long pullCount,
    method cloneForUpdate (line 66) | public final Image cloneForUpdate() {
    method cloneWithMetaData (line 70) | public final Image cloneWithMetaData(final ImageMetaData metaData) {
    method cloneWithSyncSpec (line 77) | @Override
    method getFullName (line 86) | public final String getFullName() {
    method getRepositoryKey (line 90) | public final RepositoryKey getRepositoryKey() {
    method getRepositoryName (line 94) | public final String getRepositoryName() {
    method getName (line 98) | public final String getName() {
    method getDescription (line 102) | public final String getDescription() {
    method getMetaData (line 106) | public final ImageMetaData getMetaData() {
    method getLastUpdated (line 110) | public final LocalDateTime getLastUpdated() {
    method getLastUpdatedAsString (line 114) | public final String getLastUpdatedAsString() {
    method getTagBranches (line 120) | public final List<TagBranch> getTagBranches() {
    method findTagBranchByName (line 124) | public final TagBranch findTagBranchByName(final String branchName) {
    method addTagBranch (line 136) | public final void addTagBranch(final TagBranch tagBranch) {
    method removeTagBranch (line 144) | public final void removeTagBranch(final TagBranch tagBranch) {
    method getPullCount (line 156) | public final long getPullCount() {
    method getStarCount (line 160) | public final int getStarCount() {
    method getLatestTag (line 164) | public final Tag getLatestTag() {
    method compareTo (line 176) | @Override
    method toString (line 181) | @Override
    method parseDateTime (line 186) | private LocalDateTime parseDateTime(final LocalDateTime dateTime) {

FILE: src/main/java/io/linuxserver/fleet/v2/types/ImageCountData.java
  class ImageCountData (line 20) | public class ImageCountData {
    method ImageCountData (line 25) | public ImageCountData(final long pullCount, final int starCount) {
    method getPullCount (line 31) | public final long getPullCount() {
    method getStarCount (line 35) | public final int getStarCount() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/Repository.java
  class Repository (line 28) | public class Repository extends AbstractSyncItem<RepositoryKey, Reposito...
    method Repository (line 32) | public Repository(final RepositoryKey key, final ItemSyncSpec syncSpec) {
    method cloneWithSyncSpec (line 37) | @Override
    method addImage (line 46) | public final void addImage(final Image image) {
    method getName (line 50) | public final String getName() {
    method getImages (line 54) | public final List<Image> getImages() {
    method getTotalPulls (line 61) | public final long getTotalPulls() {
    method getTotalStars (line 70) | public final int getTotalStars() {
    method isHidden (line 79) | @Override
    method isStable (line 84) | @Override
    method isDeprecated (line 89) | @Override
    method removeImage (line 94) | public final void removeImage(final Image image) {
    method toString (line 98) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/Tag.java
  class Tag (line 23) | public class Tag {
    method Tag (line 31) | public Tag(final String version, final LocalDateTime buildDate, final ...
    method getDigests (line 38) | public final List<TagDigest> getDigests() {
    method getVersion (line 42) | public String getVersion() {
    method getBuildDate (line 46) | public LocalDateTime getBuildDate() {
    method toString (line 55) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java
  class TagBranch (line 25) | public class TagBranch extends AbstractHasKey<TagBranchKey> {
    method TagBranch (line 31) | public TagBranch(final TagBranchKey tagBranchKey, final String tagBran...
    method updateLatestTag (line 39) | public final void updateLatestTag(final Tag latestTag) {
    method setBranchProtected (line 43) | public final void setBranchProtected(final boolean branchProtected) {
    method getBranchName (line 47) | public final String getBranchName() {
    method getLatestTag (line 51) | public final Tag getLatestTag() {
    method isNamedLatest (line 55) | public final boolean isNamedLatest() {
    method isBranchProtected (line 59) | public final boolean isBranchProtected() {
    method cloneForUpdate (line 63) | public final TagBranch cloneForUpdate() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/TagDigest.java
  class TagDigest (line 22) | public class TagDigest implements Comparable<TagDigest> {
    method TagDigest (line 29) | public TagDigest(final long size, final String digest, final String ar...
    method getSize (line 37) | public final long getSize() {
    method getDigest (line 41) | public final String getDigest() {
    method getArchitecture (line 45) | public final String getArchitecture() {
    method getArchVariant (line 49) | public final String getArchVariant() {
    method hashCode (line 53) | @Override
    method equals (line 58) | @Override
    method toString (line 76) | @Override
    method compareTo (line 81) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/User.java
  class User (line 26) | public class User extends AbstractHasKey<UserKey> {
    method User (line 33) | public User(final UserKey key,
    method getUsername (line 46) | public final String getUsername() {
    method getPassword (line 50) | public final String getPassword() {
    method getRole (line 54) | public final AppRole getRole() {
    method getModifiedTime (line 58) | public final LocalDateTime getModifiedTime() {
    method cloneWithPassword (line 67) | public final User cloneWithPassword(final String hashedPassword) {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/AbstractApiWrapper.java
  class AbstractApiWrapper (line 20) | public class AbstractApiWrapper<T> {
    method AbstractApiWrapper (line 24) | public AbstractApiWrapper(final T originalObject) {
    method getOriginalObject (line 28) | protected final T getOriginalObject() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java
  class ApiImagePullHistoryWrapper (line 25) | public class ApiImagePullHistoryWrapper extends AbstractApiWrapper<List<...
    method ApiImagePullHistoryWrapper (line 29) | public ApiImagePullHistoryWrapper(final List<ImagePullStatistic> origi...
    method getGroupModeDataPoint (line 35) | public final String getGroupModeDataPoint() {
    method getLabels (line 39) | public final List<String> getLabels() {
    method getPulls (line 43) | public final List<Long> getPulls() {
    method getMean (line 47) | public final long getMean() {
    method getPullDifferential (line 51) | public final PullDifferentialsWithLabels getPullDifferential() {
    class PullDifferentialsWithLabels (line 65) | public static class PullDifferentialsWithLabels {
      method PullDifferentialsWithLabels (line 69) | public PullDifferentialsWithLabels() {
      method addDifferential (line 73) | public final void addDifferential(final String label, final Long pul...
      method getLabels (line 77) | public final Set<String> getLabels() {
      method getPulls (line 81) | public final Collection<Long> getPulls() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/ApiImageWrapper.java
  class ApiImageWrapper (line 22) | public class ApiImageWrapper extends AbstractApiWrapper<Image> {
    method ApiImageWrapper (line 24) | public ApiImageWrapper(final Image originalObject) {
    method getName (line 28) | public final String getName() {
    method getVersionMask (line 32) | public final String getVersionMask() {
    method isSyncEnabled (line 36) | public final boolean isSyncEnabled() {
    method isHidden (line 40) | public final boolean isHidden() {
    method isDeprecated (line 44) | public final boolean isDeprecated() {
    method isStable (line 48) | public final boolean isStable() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/ApiRepositoryWrapper.java
  class ApiRepositoryWrapper (line 22) | public class ApiRepositoryWrapper extends AbstractApiWrapper<Repository> {
    method ApiRepositoryWrapper (line 24) | public ApiRepositoryWrapper(final Repository originalObject) {
    method getName (line 28) | public final String getName() {
    method getVersionMask (line 32) | public final String getVersionMask() {
    method isSyncEnabled (line 36) | public final boolean isSyncEnabled() {
    method getNumberOfImages (line 40) | public final int getNumberOfImages() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/ApiScheduleWrapper.java
  class ApiScheduleWrapper (line 22) | public class ApiScheduleWrapper extends AbstractApiWrapper<AppSchedule> {
    method ApiScheduleWrapper (line 24) | public ApiScheduleWrapper(final AppSchedule schedule) {
    method getName (line 28) | public final String getName() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/AllImagesExternalApiResponse.java
  class AllImagesExternalApiResponse (line 25) | public class AllImagesExternalApiResponse {
    method AllImagesExternalApiResponse (line 29) | public AllImagesExternalApiResponse() {
    method addImage (line 33) | public final ExternalApiImage addImage(final String repositoryName,
    method getTotalPullCount (line 50) | public final long getTotalPullCount() {
    method getRepositories (line 61) | public final Map<String, List<ExternalApiImage>> getRepositories() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/ExternalApiImage.java
  class ExternalApiImage (line 22) | public class ExternalApiImage {
    method ExternalApiImage (line 33) | public ExternalApiImage(final String name, final long pullCount, final...
    method getName (line 42) | public final String getName() {
    method getPullCount (line 46) | public final long getPullCount() {
    method getVersion (line 50) | public final String getVersion() {
    method getCategory (line 54) | public final String getCategory() {
    method isStable (line 58) | public final boolean isStable() {
    method isDeprecated (line 62) | public final boolean isDeprecated() {
    method setTemplateSpec (line 66) | public final void setTemplateSpec(final ApiTemplateHolder templateHold...
    method getTemplateSpec (line 70) | public final ApiTemplateHolder getTemplateSpec() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/ExternalApiResponse.java
  class ExternalApiResponse (line 20) | public class ExternalApiResponse<T> {
    method ExternalApiResponse (line 25) | public ExternalApiResponse(final ApiStatus status, final T data) {
    method getStatus (line 30) | public final ApiStatus getStatus() {
    method getData (line 34) | public final T getData() {
    type ApiStatus (line 38) | public enum ApiStatus {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiDeviceTemplate.java
  class ApiDeviceTemplate (line 19) | public class ApiDeviceTemplate {
    method ApiDeviceTemplate (line 24) | public ApiDeviceTemplate(final String device, final String description) {
    method getDevice (line 29) | public String getDevice() {
    method getDescription (line 33) | public String getDescription() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiEnvTemplate.java
  class ApiEnvTemplate (line 19) | public class ApiEnvTemplate {
    method ApiEnvTemplate (line 25) | public ApiEnvTemplate(final String name, final String exampleValue, fi...
    method getName (line 31) | public String getName() {
    method getExampleValue (line 35) | public String getExampleValue() {
    method getDescription (line 39) | public String getDescription() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiPortTemplate.java
  class ApiPortTemplate (line 19) | public class ApiPortTemplate {
    method ApiPortTemplate (line 25) | public ApiPortTemplate(final int port, final String protocol, final St...
    method getPort (line 31) | public int getPort() {
    method getProtocol (line 35) | public String getProtocol() {
    method getDescription (line 39) | public String getDescription() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiTemplateHolder.java
  class ApiTemplateHolder (line 22) | public class ApiTemplateHolder {
    method ApiTemplateHolder (line 33) | public ApiTemplateHolder(final boolean hostNetwork, final boolean priv...
    method addCapability (line 38) | public final void addCapability(final String cap) {
    method addDevice (line 42) | public final void addDevice(final ApiDeviceTemplate deviceTemplate) {
    method addEnv (line 46) | public final void addEnv(final ApiEnvTemplate envTemplate) {
    method addPort (line 50) | public final void addPort(final ApiPortTemplate portTemplate) {
    method addVolume (line 54) | public final void addVolume(final ApiVolumeTemplate volumeTemplate) {
    method getCapabilities (line 58) | public List<String> getCapabilities() {
    method getDevices (line 62) | public List<ApiDeviceTemplate> getDevices() {
    method getEnvironmentVariables (line 66) | public List<ApiEnvTemplate> getEnvironmentVariables() {
    method getPorts (line 70) | public List<ApiPortTemplate> getPorts() {
    method getVolumes (line 74) | public List<ApiVolumeTemplate> getVolumes() {
    method isHostNetwork (line 78) | public boolean isHostNetwork() {
    method isPrivileged (line 82) | public boolean isPrivileged() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiVolumeTemplate.java
  class ApiVolumeTemplate (line 19) | public class ApiVolumeTemplate {
    method ApiVolumeTemplate (line 25) | public ApiVolumeTemplate(final String containerPath, final boolean rea...
    method getContainerPath (line 31) | public String getContainerPath() {
    method isReadonly (line 35) | public boolean isReadonly() {
    method getDescription (line 39) | public String getDescription() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/docker/DockerCapability.java
  type DockerCapability (line 20) | public enum DockerCapability {

FILE: src/main/java/io/linuxserver/fleet/v2/types/docker/DockerImage.java
  class DockerImage (line 30) | public class DockerImage {
    method DockerImage (line 41) | public DockerImage(String name, String repository, String description,...
    method addTag (line 51) | public final void addTag(final DockerTag tag) {
    method getTags (line 55) | public final List<DockerTag> getTags() {
    method getName (line 59) | public final String getName() {
    method getRepository (line 63) | public final String getRepository() {
    method getDescription (line 67) | public final String getDescription() {
    method getStarCount (line 71) | public final int getStarCount() {
    method getPullCount (line 75) | public final long getPullCount() {
    method getBuildDate (line 79) | public final LocalDateTime getBuildDate() {
    method toString (line 83) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java
  class DockerTag (line 27) | public class DockerTag {
    method DockerTag (line 35) | public DockerTag(String name, long size, LocalDateTime buildDate) {
    method addDigest (line 42) | public final void addDigest(final DockerTagManifestDigest digest) {
    method getDigests (line 46) | public final List<DockerTagManifestDigest> getDigests() {
    method getName (line 50) | public String getName() {
    method getSize (line 54) | public long getSize() {
    method getBuildDate (line 58) | public LocalDateTime getBuildDate() {
    method toString (line 62) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java
  class DockerTagManifestDigest (line 20) | public class DockerTagManifestDigest {
    method DockerTagManifestDigest (line 27) | public DockerTagManifestDigest(final long size, final String digest, f...
    method getSize (line 35) | public final long getSize() {
    method getDigest (line 39) | public final String getDigest() {
    method getArchitecture (line 43) | public final String getArchitecture() {
    method getArchVariant (line 47) | public final String getArchVariant() {
    method toString (line 51) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/AbstractParamRequest.java
  class AbstractParamRequest (line 25) | public class AbstractParamRequest {
    method AbstractParamRequest (line 29) | public AbstractParamRequest(final Map<String, List<String>> params) {
    method getParams (line 33) | protected final List<String> getParams(final String key) {
    method getOrNull (line 37) | protected final String getOrNull(final String value) {
    method getFirstOrNull (line 41) | protected final String getFirstOrNull(final String key) {
    method getAsBoolean (line 50) | protected final boolean getAsBoolean(final String value) {
    method checkLists (line 54) | @SafeVarargs

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/ImageAppLogo.java
  class ImageAppLogo (line 24) | public class ImageAppLogo {
    method ImageAppLogo (line 33) | public ImageAppLogo(final ImageKey imageKey,
    method getImageKey (line 48) | public final ImageKey getImageKey() {
    method getRawDataStream (line 52) | public final InputStream getRawDataStream() {
    method getMimeType (line 56) | public final String getMimeType() {
    method getLogoName (line 60) | public final String getLogoName() {
    method getLogoSize (line 64) | public final long getLogoSize() {
    method getFileExtension (line 68) | public final String getFileExtension() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/ImageGeneralInfoUpdateRequest.java
  class ImageGeneralInfoUpdateRequest (line 23) | public class ImageGeneralInfoUpdateRequest extends AbstractParamRequest {
    method ImageGeneralInfoUpdateRequest (line 27) | public ImageGeneralInfoUpdateRequest(final Map<String, List<String>> p...
    method getImageAppLogo (line 33) | public final ImageAppLogo getImageAppLogo() {
    method getBaseImage (line 37) | public final String getBaseImage() {
    method getCategory (line 41) | public final String getCategory() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/ImageOutlineRequest.java
  class ImageOutlineRequest (line 24) | public class ImageOutlineRequest {
    method ImageOutlineRequest (line 31) | public ImageOutlineRequest(final RepositoryKey repositoryKey,
    method getRepositoryKey (line 42) | public final RepositoryKey getRepositoryKey() {
    method getImageName (line 46) | public final String getImageName() {
    method getImageDescription (line 50) | public final String getImageDescription() {
    method getImageLastUpdated (line 54) | public final LocalDateTime getImageLastUpdated() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/ImageTemplateRequest.java
  class ImageTemplateRequest (line 24) | public class ImageTemplateRequest extends AbstractParamRequest {
    method ImageTemplateRequest (line 26) | public ImageTemplateRequest(final Map<String, List<String>> rawTemplat...
    method getRegistryUrl (line 30) | public final String getRegistryUrl() {
    method getRestartPolicy (line 34) | public final String getRestartPolicy() {
    method isHostNetworkEnabled (line 38) | public final boolean isHostNetworkEnabled() {
    method isPrivilegedMode (line 42) | public final boolean isPrivilegedMode() {
    method getCapabilities (line 46) | public final List<String> getCapabilities() {
    method getPorts (line 50) | public final List<TemplateItem<String>> getPorts() {
    method getVolumes (line 74) | public final List<TemplateItem<Boolean>> getVolumes() {
    method getEnvironment (line 98) | public final List<TemplateItem<String>> getEnvironment() {
    method getDevices (line 119) | public final List<TemplateItem<Void>> getDevices() {
    class TemplateItem (line 139) | public static class TemplateItem<T> {
      method TemplateItem (line 145) | public TemplateItem(final String name, final String description, fin...
      method getName (line 152) | public final String getName() {
      method getDescription (line 156) | public final String getDescription() {
      method getSecondaryField (line 160) | public final T getSecondaryField() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/ImageUrlsUpdateRequest.java
  class ImageUrlsUpdateRequest (line 27) | public class ImageUrlsUpdateRequest extends AbstractParamRequest {
    method ImageUrlsUpdateRequest (line 29) | public ImageUrlsUpdateRequest(final Map<String, List<String>> params) {
    method getExternalUrls (line 33) | public final List<ExternalUrl> getExternalUrls() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/RepositoryOutlineRequest.java
  class RepositoryOutlineRequest (line 20) | public class RepositoryOutlineRequest {
    method RepositoryOutlineRequest (line 24) | public RepositoryOutlineRequest(final String repositoryName) {
    method getRepositoryName (line 28) | public final String getRepositoryName() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/TagBranchOutlineRequest.java
  class TagBranchOutlineRequest (line 22) | public class TagBranchOutlineRequest {
    method TagBranchOutlineRequest (line 27) | public TagBranchOutlineRequest(final ImageKey imageKey, final String b...
    method getImageKey (line 33) | public final ImageKey getImageKey() {
    method getBranchName (line 37) | public final String getBranchName() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/internal/UserOutlineRequest.java
  class UserOutlineRequest (line 22) | public class UserOutlineRequest {
    method UserOutlineRequest (line 30) | public UserOutlineRequest(final String username, final String password...
    method cloneWithPassword (line 37) | public final UserOutlineRequest cloneWithPassword(final String passwor...
    method getUsername (line 41) | public final String getUsername() {
    method getPassword (line 45) | public final String getPassword() {
    method getRole (line 49) | public final AppRole getRole() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/ExternalUrl.java
  class ExternalUrl (line 23) | public class ExternalUrl extends AbstractHasKey<ExternalUrlKey> {
    method ExternalUrl (line 29) | public ExternalUrl(final ExternalUrlKey key,
    method getType (line 39) | public final ExternalUrlType getType() {
    method getName (line 43) | public final String getName() {
    method getAbsoluteUrl (line 47) | public final String getAbsoluteUrl() {
    method toString (line 51) | @Override
    method compareTo (line 56) | @Override
    method isNonPersisted (line 66) | private boolean isNonPersisted(final ExternalUrlKey key) {
    type ExternalUrlType (line 70) | public enum ExternalUrlType {
      method ExternalUrlType (line 80) | ExternalUrlType(final String icon,
      method getIcon (line 86) | public final String getIcon() {
      method getDescription (line 90) | public final String getDescription() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/ExternalUrlKey.java
  class ExternalUrlKey (line 24) | public class ExternalUrlKey extends AbstractDatabaseKey {
    method ExternalUrlKey (line 28) | public ExternalUrlKey(final Integer id) {
    method equals (line 32) | @Override
    method areBothNonPersistedKeys (line 44) | private boolean areBothNonPersistedKeys(Key other) {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/ImageCoreMeta.java
  class ImageCoreMeta (line 25) | public class ImageCoreMeta {
    method ImageCoreMeta (line 32) | public ImageCoreMeta(final String appImagePath,
    method cloneWithBaseData (line 42) | public final ImageCoreMeta cloneWithBaseData(final String appImagePath,
    method cloneWithExternalUrls (line 54) | public final ImageCoreMeta cloneWithExternalUrls(final List<ExternalUr...
    method addExternalUrl (line 64) | public final void addExternalUrl(final ExternalUrl externalUrl) {
    method removeExternalUrl (line 72) | public final void removeExternalUrl(final ExternalUrlKey externalUrlKe...
    method getAppImagePath (line 76) | public final String getAppImagePath() {
    method getBaseImage (line 80) | public final String getBaseImage() {
    method getCategory (line 84) | public final String getCategory() {
    method getExternalUrls (line 88) | public final List<ExternalUrl> getExternalUrls() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/ImageMetaData.java
  class ImageMetaData (line 26) | public class ImageMetaData {
    method ImageMetaData (line 32) | public ImageMetaData(final ImageCoreMeta coreMeta,
    method cloneWithTemplate (line 40) | public final ImageMetaData cloneWithTemplate(final ImageTemplateHolder...
    method cloneWithCoreMeta (line 44) | public final ImageMetaData cloneWithCoreMeta(final ImageCoreMeta coreM...
    method getHistoryFor (line 48) | public final List<ImagePullStatistic> getHistoryFor(final ImagePullSta...
    method getTemplates (line 52) | public final ImageTemplateHolder getTemplates() {
    method getCoreMeta (line 56) | public final ImageCoreMeta getCoreMeta() {
    method getAppImagePath (line 60) | public final String getAppImagePath() {
    method getBaseImage (line 64) | public final String getBaseImage() {
    method getCategory (line 68) | public final String getCategory() {
    method getExternalUrls (line 72) | public final List<ExternalUrl> getExternalUrls() {
    method isPopulated (line 76) | public final boolean isPopulated() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/ItemSyncSpec.java
  class ItemSyncSpec (line 20) | public class ItemSyncSpec {
    method ItemSyncSpec (line 30) | public ItemSyncSpec(final boolean deprecated,
    method copyOf (line 43) | public final ItemSyncSpec copyOf() {
    method setDeprecated (line 47) | public final void setDeprecated(boolean deprecated) {
    method setHidden (line 51) | public final void setHidden(boolean hidden) {
    method setStable (line 55) | public final void setStable(boolean stable) {
    method setSynchronised (line 59) | public final void setSynchronised(boolean synchronised) {
    method setVersionMask (line 63) | public final void setVersionMask(String versionMask) {
    method isDeprecated (line 67) | public final boolean isDeprecated() {
    method isHidden (line 71) | public final boolean isHidden() {
    method isStable (line 75) | public final boolean isStable() {
    method isSynchronised (line 79) | public final boolean isSynchronised() {
    method getVersionMask (line 83) | public final String getVersionMask() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullHistory.java
  class ImagePullHistory (line 25) | public class ImagePullHistory {
    method ImagePullHistory (line 29) | public ImagePullHistory() {
    method addStatistic (line 33) | public final boolean addStatistic(final ImagePullStatistic statistic) {
    method getHistoryFor (line 37) | public final List<ImagePullStatistic> getHistoryFor(final ImagePullSta...

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java
  class ImagePullStatistic (line 20) | public class ImagePullStatistic implements Comparable<ImagePullStatistic> {
    method ImagePullStatistic (line 26) | public ImagePullStatistic(final long pullCount,
    method getPullCount (line 35) | public final long getPullCount() {
    method getGroupedDateTime (line 39) | public final String getGroupedDateTime() {
    method isGroupedBy (line 43) | public final boolean isGroupedBy(final StatGroupMode groupMode) {
    method compareTo (line 47) | @Override
    method hashCode (line 57) | @Override
    method equals (line 62) | @Override
    method toString (line 73) | @Override
    type StatGroupMode (line 78) | public enum StatGroupMode {
      method StatGroupMode (line 86) | StatGroupMode(final String dataPoints) {
      method getDataPoint (line 90) | public final String getDataPoint() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/AbstractTemplateItem.java
  class AbstractTemplateItem (line 20) | public abstract class AbstractTemplateItem<T extends Comparable<T>, ITEM...
    method AbstractTemplateItem (line 25) | protected AbstractTemplateItem(final T name, final String description) {
    method getName (line 31) | @Override
    method getDescription (line 36) | @Override
    method compareTo (line 41) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/DeviceTemplateItem.java
  class DeviceTemplateItem (line 20) | public class DeviceTemplateItem extends AbstractTemplateItem<String, Dev...
    method DeviceTemplateItem (line 22) | public DeviceTemplateItem(final String name, final String description) {
    method getDevice (line 26) | public final String getDevice() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/EnvironmentTemplateItem.java
  class EnvironmentTemplateItem (line 20) | public class EnvironmentTemplateItem extends AbstractTemplateItem<String...
    method EnvironmentTemplateItem (line 24) | public EnvironmentTemplateItem(final String name, final String descrip...
    method getEnv (line 29) | public final String getEnv() {
    method getExampleValue (line 33) | public final String getExampleValue() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/ImageTemplateHolder.java
  class ImageTemplateHolder (line 27) | public class ImageTemplateHolder {
    method ImageTemplateHolder (line 43) | public ImageTemplateHolder(final String registryUrl,
    method hasCapability (line 54) | public final boolean hasCapability(final DockerCapability capability) {
    method addCapability (line 58) | public final void addCapability(final DockerCapability capability) {
    method getCapabilities (line 62) | public final List<DockerCapability> getCapabilities() {
    method addPort (line 66) | public final void addPort(final PortTemplateItem port) {
    method addVolume (line 70) | public final void addVolume(final VolumeTemplateItem volume) {
    method addEnvironment (line 74) | public final void addEnvironment(final EnvironmentTemplateItem env) {
    method addDevice (line 78) | public final void addDevice(final DeviceTemplateItem device) {
    method getPorts (line 82) | public final List<PortTemplateItem> getPorts() {
    method getVolumes (line 86) | public final List<VolumeTemplateItem> getVolumes() {
    method getEnv (line 90) | public final List<EnvironmentTemplateItem> getEnv() {
    method getDevices (line 94) | public final List<DeviceTemplateItem> getDevices() {
    method getRestartPolicy (line 98) | public final String getRestartPolicy() {
    method isHostNetworkingEnabled (line 102) | public final boolean isHostNetworkingEnabled() {
    method isPrivilegedMode (line 106) | public final boolean isPrivilegedMode() {
    method getRegistryUrl (line 110) | public final String getRegistryUrl() {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/PortTemplateItem.java
  class PortTemplateItem (line 20) | public class PortTemplateItem extends AbstractTemplateItem<Integer, Port...
    method PortTemplateItem (line 24) | public PortTemplateItem(final Integer port, final String description, ...
    method getPort (line 29) | public final Integer getPort() {
    method getProtocol (line 33) | public final String getProtocol() {
    method getProtocolAsProtocol (line 37) | public final Protocol getProtocolAsProtocol() {
    type Protocol (line 41) | public enum Protocol {
      method Protocol (line 48) | Protocol(final String protocolName) {
      method fromName (line 52) | public static Protocol fromName(final String protocolName) {

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/TemplateItem.java
  type TemplateItem (line 20) | public interface TemplateItem<T> {
    method getName (line 22) | T getName();
    method getDescription (line 24) | String getDescription();

FILE: src/main/java/io/linuxserver/fleet/v2/types/meta/template/VolumeTemplateItem.java
  class VolumeTemplateItem (line 20) | public class VolumeTemplateItem extends AbstractTemplateItem<String, Vol...
    method VolumeTemplateItem (line 24) | public VolumeTemplateItem(final String volume, final String descriptio...
    method getVolume (line 29) | public final String getVolume() {
    method isReadonly (line 33) | public final boolean isReadonly() {
    type Protocol (line 37) | public enum Protocol {
      method Protocol (line 44) | Protocol(final String protocolName) {
      method fromName (line 48) | public static Protocol fromName(final String protocolName) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/ApiException.java
  class ApiException (line 20) | public class ApiException extends RuntimeException {
    method ApiException (line 22) | public ApiException(final String message, final Throwable cause) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/AppRole.java
  type AppRole (line 22) | public enum AppRole implements Role {

FILE: src/main/java/io/linuxserver/fleet/v2/web/LocationUtils.java
  class LocationUtils (line 22) | public class LocationUtils {
    method isUnAuthenticatedLocation (line 24) | public static boolean isUnAuthenticatedLocation(final String location) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/Locations.java
  type Locations (line 20) | public interface Locations {
    type Static (line 22) | interface Static {
    type Api (line 37) | interface Api {
    type Internal (line 41) | interface Internal {
    type Admin (line 52) | interface Admin {

FILE: src/main/java/io/linuxserver/fleet/v2/web/PageModelAttributes.java
  type PageModelAttributes (line 20) | public interface PageModelAttributes {

FILE: src/main/java/io/linuxserver/fleet/v2/web/PageModelSpec.java
  class PageModelSpec (line 23) | public class PageModelSpec {
    method PageModelSpec (line 28) | public PageModelSpec(final String viewName) {
    method getViewName (line 34) | public final String getViewName() {
    method getModel (line 38) | public final Map<String, Object> getModel() {
    method addModelAttribute (line 42) | public void addModelAttribute(final String key, final Object value) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/SessionAttributes.java
  type SessionAttributes (line 20) | public interface SessionAttributes {

FILE: src/main/java/io/linuxserver/fleet/v2/web/WebRouteController.java
  class WebRouteController (line 35) | public class WebRouteController {
    method WebRouteController (line 40) | public WebRouteController(final FleetAppController app) {
    method printBanner (line 134) | private static String printBanner() {

FILE: src/main/java/io/linuxserver/fleet/v2/web/freemarker/CustomFreemarkerTemplate.java
  type CustomFreemarkerTemplate (line 22) | public interface CustomFreemarkerTemplate extends TemplateMethodModelEx {
    method getName (line 24) | String getName();

FILE: src/main/java/io/linuxserver/fleet/v2/web/freemarker/Java8DateTimeMethod.java
  class Java8DateTimeMethod (line 28) | public class Java8DateTimeMethod implements CustomFreemarkerTemplate {
    method getName (line 30) | @Override
    method exec (line 35) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/request/json/NewRepositoryRequest.java
  class NewRepositoryRequest (line 22) | public class NewRepositoryRequest {
    method getRepositoryName (line 27) | public final String getRepositoryName() {

FILE: src/main/java/io/linuxserver/fleet/v2/web/request/json/UpdateImageSpecRequest.java
  class UpdateImageSpecRequest (line 22) | public class UpdateImageSpecRequest {
    method getImageKey (line 42) | public final String getImageKey() {
    method isSyncEnabled (line 46) | public final boolean isSyncEnabled() {
    method getVersionMask (line 50) | public final String getVersionMask() {
    method isStable (line 54) | public final boolean isStable() {
    method isHidden (line 58) | public final boolean isHidden() {
    method isDeprecated (line 62) | public boolean isDeprecated() {

FILE: src/main/java/io/linuxserver/fleet/v2/web/request/json/UpdateRepositoryRequest.java
  class UpdateRepositoryRequest (line 22) | public class UpdateRepositoryRequest {
    method getRepositoryKey (line 33) | public final String getRepositoryKey() {
    method isSyncEnabled (line 37) | public final boolean isSyncEnabled() {
    method getVersionMask (line 41) | public final String getVersionMask() {

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AbstractPageHandler.java
  class AbstractPageHandler (line 38) | public abstract class AbstractPageHandler extends AbstractAppService imp...
    method AbstractPageHandler (line 49) | AbstractPageHandler(final FleetAppController controller) {
    method handle (line 54) | @Override
    method handlePageLoad (line 81) | protected abstract PageModelSpec handlePageLoad(Context ctx);
    method handleFormSubmission (line 83) | protected abstract PageModelSpec handleFormSubmission(Context ctx);
    method injectCustomMethods (line 85) | protected void injectCustomMethods(final PageModelSpec spec) {
    method injectTopLevelModelAttributes (line 92) | private void injectTopLevelModelAttributes(final Context ctx, final Pa...
    method checkViewForRedirect (line 98) | private void checkViewForRedirect(final Context ctx, final PageModelSp...
    method isRedirect (line 107) | private boolean isRedirect(final String view) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageController.java
  class AdminImageController (line 26) | public class AdminImageController extends AbstractPageHandler {
    method AdminImageController (line 30) | public AdminImageController(final FleetAppController controller) {
    method handlePageLoad (line 35) | @Override
    method handleFormSubmission (line 50) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AdminImageEditController.java
  class AdminImageEditController (line 33) | public class AdminImageEditController extends AbstractPageHandler {
    method AdminImageEditController (line 37) | public AdminImageEditController(final FleetAppController controller) {
    method handlePageLoad (line 42) | @Override
    method handleFormSubmission (line 59) | @Override
    method handleUrlUpdate (line 86) | private void handleUrlUpdate(final Context ctx, final ImageKey imageKe...
    method handleGeneralUpdate (line 90) | private void handleGeneralUpdate(final Context ctx, final ImageKey ima...
    method handleTemplateUpdate (line 99) | private void handleTemplateUpdate(final Context ctx, final ImageKey im...
    method makeInfoRequest (line 103) | private ImageGeneralInfoUpdateRequest makeInfoRequest(final ImageKey i...
    method makeImageLogoIfPresent (line 109) | private ImageAppLogo makeImageLogoIfPresent(final ImageKey imageKey, f...

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AdminRepositoryController.java
  class AdminRepositoryController (line 25) | public class AdminRepositoryController extends AbstractPageHandler {
    method AdminRepositoryController (line 29) | public AdminRepositoryController(final FleetAppController controller) {
    method handlePageLoad (line 34) | @Override
    method handleFormSubmission (line 42) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AdminScheduleController.java
  class AdminScheduleController (line 26) | public class AdminScheduleController extends AbstractPageHandler {
    method AdminScheduleController (line 31) | public AdminScheduleController(final FleetAppController controller) {
    method handlePageLoad (line 38) | @Override
    method handleFormSubmission (line 48) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/AdminUserController.java
  class AdminUserController (line 29) | public class AdminUserController extends AbstractPageHandler {
    method AdminUserController (line 33) | public AdminUserController(final FleetAppController controller) {
    method handlePageLoad (line 38) | @Override
    method handleFormSubmission (line 46) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/DefaultAccessManager.java
  class DefaultAccessManager (line 32) | public class DefaultAccessManager implements AccessManager {
    method manage (line 34) | @Override
    method isUserRoleValid (line 52) | private boolean isUserRoleValid(final AuthenticatedUser user, final Se...

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/HomeController.java
  class HomeController (line 27) | public class HomeController extends AbstractPageHandler {
    method HomeController (line 31) | public HomeController(final FleetAppController controller) {
    method handlePageLoad (line 36) | @Override
    method setSingleRepository (line 59) | private void setSingleRepository(PageModelSpec modelSpec, Repository r...
    method handleFormSubmission (line 66) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/ImageController.java
  class ImageController (line 26) | public class ImageController extends AbstractPageHandler {
    method ImageController (line 30) | public ImageController(final FleetAppController controller) {
    method handlePageLoad (line 35) | @Override
    method handleFormSubmission (line 50) | @Override

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/InternalApiController.java
  class InternalApiController (line 43) | public class InternalApiController extends AbstractAppService {
    method InternalApiController (line 45) | public InternalApiController(final FleetAppController controller) {
    method updateImageSpec (line 49) | public final void updateImageSpec(final Context ctx) {
    method updateRepositorySpec (line 73) | public final void updateRepositorySpec(final Context ctx) {
    method addNewRepository (line 94) | public final void addNewRepository(final Context ctx) {
    method runSchedule (line 111) | public final void runSchedule(final Context ctx) {
    method syncRepository (line 125) | public final void syncRepository(final Context ctx) {
    method syncImage (line 141) | public final void syncImage(final Context ctx) {
    method deleteRepository (line 155) | public void deleteRepository(final Context ctx) {
    method getImagePullHistory (line 169) | public void getImagePullHistory(final Context ctx) {
    method trackNewBranch (line 184) | public void trackNewBranch(final Context ctx) {
    method removeTrackedBranch (line 198) | public void removeTrackedBranch(final Context ctx) {

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/LegacyExternalApiController.java
  class LegacyExternalApiController (line 35) | public class LegacyExternalApiController extends AbstractAppService {
    method LegacyExternalApiController (line 37) | public LegacyExternalApiController(final FleetAppController controller) {
    method fetchAllImages (line 41) | public final void fetchAllImages(final Context ctx) {
    method enrichImageWithTemplateData (line 74) | private void enrichImageWithTemplateData(final ExternalApiImage apiIma...

FILE: src/main/java/io/linuxserver/fleet/v2/web/routes/LoginController.java
  class LoginController (line 26) | public class LoginController extends AbstractPageHandler {
    method LoginController (line 28) | public LoginController(final FleetAppController controller) {
    method handlePageLoad (line 32) | @Override
    method handleFormSubmission (line 42) | @Override
    method doLogIn (line 61) | private boolean doLogIn(final Context ctx) {
    method doLogOut (line 77) | private void doLogOut(final Context ctx) {

FILE: src/main/resources/db/migration/V1.0__CreateTables.sql
  type Repositories (line 1) | CREATE TABLE Repositories (
  type Images (line 10) | CREATE TABLE Images (

FILE: src/main/resources/db/migration/V1.10__UpdateImageViewWithRepository.sql
  type `Image_View` (line 3) | CREATE OR REPLACE VIEW `Image_View` AS (

FILE: src/main/resources/db/migration/V1.2__CreateUserTable.sql
  type Users (line 1) | CREATE TABLE Users (

FILE: src/main/resources/db/migration/V1.8__PullHistoryAndImageMeta.sql
  type ImagePullHistory (line 3) | CREATE TABLE ImagePullHistory (

FILE: src/main/resources/db/migration/V1.9__ExtraTagFields.sql
  type `Image_View` (line 8) | CREATE OR REPLACE VIEW `Image_View` AS (

FILE: src/main/resources/db/migration/V2.0__CreateV2TablesAndSprocs.sql
  type Repository (line 3) | CREATE TABLE Repository (
  type Image (line 16) | CREATE TABLE Image (
  type TagBranch (line 34) | CREATE TABLE TagBranch (
  type TagDigest (line 46) | CREATE TABLE TagDigest (
  type Schedule (line 57) | CREATE TABLE Schedule (
  type AppSetting (line 66) | CREATE TABLE AppSetting (
  type `Image_View` (line 81) | CREATE OR REPLACE VIEW `Image_View` AS (
  type `RepositoryKey_View` (line 113) | CREATE OR REPLACE VIEW `RepositoryKey_View` AS
  type `Repository_View` (line 123) | CREATE OR REPLACE VIEW `Repository_View` AS
  type `ImageKey_View` (line 144) | CREATE OR REPLACE VIEW `ImageKey_View` AS (
  type `TagBranch_View` (line 158) | CREATE OR REPLACE VIEW `TagBranch_View` AS (
  type `TagDigest_View` (line 172) | CREATE OR REPLACE VIEW `TagDigest_View` AS (
  type `User_View` (line 645) | CREATE OR REPLACE VIEW `User_View` AS (

FILE: src/main/resources/db/migration/V2.2__MetaDataTables.sql
  type ImageMetadata (line 3) | CREATE TABLE ImageMetadata (
  type ImageTemplateBase (line 18) | CREATE TABLE ImageTemplateBase (
  type ImageTemplateEnvironment (line 29) | CREATE TABLE ImageTemplateEnvironment (
  type ImageTemplateExtra (line 38) | CREATE TABLE ImageTemplateExtra (
  type ImageTemplateDevices (line 47) | CREATE TABLE ImageTemplateDevices (
  type ImageTemplateVolumes (line 56) | CREATE TABLE ImageTemplateVolumes (
  type ImageTemplatePorts (line 66) | CREATE TABLE ImageTemplatePorts (

FILE: src/main/resources/db/migration/V2.3__UpdateImageViewForCoreMeta.sql
  type `Image_View` (line 3) | CREATE OR REPLACE VIEW `Image_View` AS (

FILE: src/main/resources/db/migration/V2.4__UpdateUserSprocs.sql
  type `User_View` (line 3) | CREATE OR REPLACE VIEW `User_View` AS (

FILE: src/main/resources/db/migration/V2.5__BranchRemovalSproc.sql
  type `Image_View` (line 15) | CREATE OR REPLACE VIEW `Image_View` AS (
  type ExternalUrl (line 166) | CREATE TABLE ExternalUrl (

FILE: src/main/resources/static/assets/js/fontawesome-all.js
  function M (line 5) | function M(c,z){var l=(2<arguments.length&&void 0!==arguments[2]?argumen...
  function M (line 5) | function M(c,z){var l=(2<arguments.length&&void 0!==arguments[2]?argumen...
  function M (line 5) | function M(c,z){var l=(2<arguments.length&&void 0!==arguments[2]?argumen...
  function a (line 5) | function a(c){return(a="function"==typeof Symbol&&"symbol"==typeof Symbo...
  function v (line 5) | function v(c,l){for(var h=0;h<l.length;h++){var z=l[h];z.enumerable=z.en...
  function G (line 5) | function G(v){for(var c=1;c<arguments.length;c++){var a=null!=arguments[...
  function n (line 5) | function n(c,l){return function(c){if(Array.isArray(c))return c}(c)||fun...
  function r (line 5) | function r(c){return function(c){if(Array.isArray(c)){for(var l=0,h=new ...
  function U (line 5) | function U(c){H&&(W?setTimeout(c,0):D.push(c))}
  function ac (line 5) | function ac(){for(var c=0;c<vc.length;c++)vc[c][0](vc[c][1]);Q=!(vc=[])}
  function mc (line 5) | function mc(c,l){vc.push([c,l]),Q||(Q=!0,zc(ac,0))}
  function sc (line 5) | function sc(c){var l=c.owner,h=l._state,z=l._data,v=c[h],a=c.then;if("fu...
  function ec (line 5) | function ec(l,h){var z;try{if(l===h)throw new TypeError("A promises call...
  function tc (line 5) | function tc(c,l){c!==l&&ec(c,l)||Mc(c,l)}
  function Mc (line 5) | function Mc(c,l){c._state===X&&(c._state=B,c._data=l,mc(Hc,c))}
  function fc (line 5) | function fc(c,l){c._state===X&&(c._state=B,c._data=l,mc(nc,c))}
  function rc (line 5) | function rc(c){c._then=c._then.forEach(sc)}
  function Hc (line 5) | function Hc(c){c._state=K,rc(c)}
  function nc (line 5) | function nc(c){c._state=cc,rc(c),!c._handled&&hc&&global.process.emit("u...
  function ic (line 5) | function ic(c){global.process.emit("rejectionHandled",c)}
  function Vc (line 5) | function Vc(c){if("function"!=typeof c)throw new TypeError("Promise reso...
  function l (line 5) | function l(l){return v++,function(c){z[l]=c,--v||h(z)}}
  function dc (line 5) | function dc(c){if(c&&H){var l=o.createElement("style");l.setAttribute("t...
  function pc (line 5) | function pc(){for(var c=12,l="";0<c--;)l+=uc[62*Math.random()|0];return l}
  function bc (line 5) | function bc(c){for(var l=[],h=(c||[]).length>>>0;h--;)l[h]=c[h];return l}
  function gc (line 5) | function gc(c){return c.classList?bc(c.classList):(c.getAttribute("class...
  function Ac (line 5) | function Ac(c,l){var h,z=l.split("-"),v=z[0],a=z.slice(1).join("-");retu...
  function Sc (line 5) | function Sc(c){return"".concat(c).replace(/&/g,"&amp;").replace(/"/g,"&q...
  function yc (line 5) | function yc(h){return Object.keys(h||{}).reduce(function(c,l){return c+"...
  function wc (line 5) | function wc(c){return c.size!==Lc.size||c.x!==Lc.x||c.y!==Lc.y||c.rotate...
  function kc (line 5) | function kc(c){var l=c.transform,h=c.containerWidth,z=c.iconWidth,v={tra...
  function xc (line 5) | function xc(c){var l=!(1<arguments.length&&void 0!==arguments[1])||argum...
  function qc (line 5) | function qc(c){var l=c.icons,h=l.main,z=l.mask,v=c.prefix,a=c.iconName,m...
  function Oc (line 5) | function Oc(c){var l=c.content,h=c.width,z=c.height,v=c.transform,a=c.ti...
  function Ic (line 5) | function Ic(c){for(var l="",h=0;h<c.length;h++){l+=("000"+c.charCodeAt(h...
  function Qc (line 5) | function Qc(c,l){return(Yc[c]||{})[l]}
  function Kc (line 5) | function Kc(c){return c.reduce(function(c,l){var h=Ac($.familyPrefix,l);...
  function Gc (line 5) | function Gc(c,l,h){if(c&&c[l]&&c[l][h])return{prefix:l,iconName:h,icon:c...
  function Jc (line 5) | function Jc(c){var h,l=c.tag,z=c.attributes,v=void 0===z?{}:z,a=c.childr...
  function cl (line 5) | function cl(c){return"string"==typeof(c.getAttribute?c.getAttribute(J):n...
  function hl (line 5) | function hl(c){c()}
  function zl (line 5) | function zl(h,c){var z="function"==typeof c?c:$c;if(0===h.length)z();els...
  function al (line 5) | function al(){vl=!1}
  function sl (line 5) | function sl(c){if(t&&$.observeMutations){var v=c.treeCallback,a=c.nodeCa...
  function el (line 5) | function el(c){var l,h,z=c.getAttribute("data-prefix"),v=c.getAttribute(...
  function Ml (line 5) | function Ml(c){var l,h,z,v,a,m,s,e,t=el(c),M=t.iconName,f=t.prefix,r=t.r...
  function fl (line 5) | function fl(c){this.name="MissingIcon",this.message=c||"Icon unavailable...
  function Cl (line 5) | function Cl(c){var l=c[0],h=c[1],z=n(c.slice(4),1)[0];return{found:!0,wi...
  function Ll (line 5) | function Ll(z,v){return new oc(function(c,l){var h={found:!1,width:512,h...
  function ul (line 5) | function ul(c){var a,l,m,s,e,t,M,f,h,r,H,z=Ml(c);return~z.extra.classes....
  function pl (line 5) | function pl(c){var h=1<arguments.length&&void 0!==arguments[1]?arguments...
  function bl (line 5) | function bl(c){var l=1<arguments.length&&void 0!==arguments[1]?arguments...
  function gl (line 5) | function gl(H,n){var i="".concat(u).concat(n.replace(":","-"));return ne...
  function Al (line 5) | function Al(c){return oc.all([gl(c,":before"),gl(c,":after")])}
  function Sl (line 5) | function Sl(c){return!(c.parentNode===document.head||~w.indexOf(c.tagNam...
  function yl (line 5) | function yl(v){if(H)return new oc(function(c,l){var h=bc(v.querySelector...
  function kl (line 5) | function kl(){var c=C,l=L,h=$.familyPrefix,z=$.replacementClass,v=wl;if(...
  function Zl (line 5) | function Zl(){$.autoAddCss&&!Pl&&(dc(kl()),Pl=!0)}
  function xl (line 5) | function xl(l,c){return Object.defineProperty(l,"abstract",{get:c}),Obje...
  function ql (line 5) | function ql(c){var l=c.prefix,h=void 0===l?"fa":l,z=c.iconName;if(z)retu...
  function c (line 5) | function c(){!function(c,l){if(!(c instanceof l))throw new TypeError("Ca...

FILE: src/main/resources/static/assets/js/prism.js
  function l (line 3) | function l(e){o.highlightedCode=e,C.hooks.run("before-insert",o),o.eleme...
  function _ (line 3) | function _(e,n,r,t,a){this.type=e,this.content=n,this.alias=r,this.lengt...
  function r (line 3) | function r(){C.manual||C.highlightAll()}
  function o (line 7) | function o(){var o=new r(t,{text:function(){return e.code}});o.on("succe...
  function n (line 7) | function n(){setTimeout(function(){t.textContent="Copy"},5e3)}

FILE: src/test/java/io/linuxserver/fleet/auth/security/PBKDF2PasswordEncoderTest.java
  class PBKDF2PasswordEncoderTest (line 26) | public class PBKDF2PasswordEncoderTest {
    method shouldGenerateHash (line 32) | @Test

FILE: src/test/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinderTest.java
  class DockerTagFinderTest (line 33) | public class DockerTagFinderTest {
    method shouldFindCorrectTagIfAllDigestsMatch (line 35) | @Test
    method shouldReturnFoundNamedTagIfNoOthersMatchFully (line 61) | @Test

FILE: src/test/java/io/linuxserver/fleet/v2/thread/schedule/TimeWithUnitTest.java
  class TimeWithUnitTest (line 28) | public class TimeWithUnitTest {
    method shouldConvertToLowestUnit (line 30) | @Test
Condensed preview — 287 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,315K chars).
[
  {
    "path": ".gitignore",
    "chars": 526,
    "preview": "# Compiled class file\n*.class\n\n# Log file\n*.log\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Packa"
  },
  {
    "path": "LICENSE",
    "chars": 35149,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free "
  },
  {
    "path": "README.md",
    "chars": 2454,
    "preview": "# Fleet\n\nFleet is a Docker Hub repository and image management tool for organisations (or individuals) who wish to displ"
  },
  {
    "path": "build.gradle",
    "chars": 2534,
    "preview": "plugins {\n    id 'java'\n}\n\nsourceCompatibility = JavaVersion.VERSION_11\ntargetCompatibility = JavaVersion.VERSION_11\n\nre"
  },
  {
    "path": "config/example.fleet.properties",
    "chars": 522,
    "preview": "# This is an example properties file for Fleet.\n# You should fill in your own values here and rename the file to \"fleet."
  },
  {
    "path": "config/log4j2.local.xml",
    "chars": 550,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration>\n\n    <Appenders>\n\n        <Console name=\"Console\" target=\"SYSTEM_"
  },
  {
    "path": "config/log4j2.release.xml",
    "chars": 754,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration>\n\n    <Appenders>\n\n        <RollingFile name=\"File\" fileName=\"${sy"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 202,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradlew",
    "chars": 8047,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015-2021 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "gradlew.bat",
    "chars": 2763,
    "preview": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (th"
  },
  {
    "path": "settings.gradle",
    "chars": 26,
    "preview": "rootProject.name = 'fleet'"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/AuthenticatedUser.java",
    "chars": 1200,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/AuthenticationDelegate.java",
    "chars": 897,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/AuthenticationResult.java",
    "chars": 1278,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/DefaultAuthenticationDelegate.java",
    "chars": 1476,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/UserCredentials.java",
    "chars": 1106,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/authenticator/DefaultUserAuthenticator.java",
    "chars": 2023,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/authenticator/UserAuthenticator.java",
    "chars": 1345,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/security/PBKDF2PasswordEncoder.java",
    "chars": 5342,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/security/PasswordEncoder.java",
    "chars": 1896,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/auth/security/util/SaltGenerator.java",
    "chars": 1109,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/AbstractAppController.java",
    "chars": 2451,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/BaseRuntimeLoader.java",
    "chars": 1327,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/FleetAppController.java",
    "chars": 6509,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/FleetRuntime.java",
    "chars": 1415,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/Main.java",
    "chars": 850,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/PropertiesLoader.java",
    "chars": 4616,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/ServiceProvider.java",
    "chars": 1250,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/config/AppProperties.java",
    "chars": 3766,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/config/DatabaseConnectionProperties.java",
    "chars": 1644,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/config/Version.java",
    "chars": 1812,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/config/VersionProperties.java",
    "chars": 2042,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/config/WebConfiguration.java",
    "chars": 1001,
    "preview": "/*\n * Copyright (c) 2019 Wallett\n *\n * This program is free software: you can redistribute it and/or modify\n * it under "
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/db/DatabaseConnection.java",
    "chars": 950,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/db/DatabaseProvider.java",
    "chars": 923,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/core/db/DefaultDatabaseProvider.java",
    "chars": 1407,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/DefaultDatabaseConnection.java",
    "chars": 997,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/PoolingDatabaseConnection.java",
    "chars": 2001,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/dao/Utils.java",
    "chars": 2218,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/migration/DatabaseVersion.java",
    "chars": 1941,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/query/InsertUpdateResult.java",
    "chars": 1596,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/query/InsertUpdateStatus.java",
    "chars": 818,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/query/LimitOffset.java",
    "chars": 1054,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/db/query/LimitedResult.java",
    "chars": 1410,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/DockerHubException.java",
    "chars": 979,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Image.java",
    "chars": 1842,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ImageListResult.java",
    "chars": 834,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2NamespaceLookupResult.java",
    "chars": 1065,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2ScanResult.java",
    "chars": 1355,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2Tag.java",
    "chars": 1926,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagDigest.java",
    "chars": 1323,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/model/DockerHubV2TagListResult.java",
    "chars": 830,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/dockerhub/util/DockerTagFinder.java",
    "chars": 2954,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/exception/SaveException.java",
    "chars": 957,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/LoggerOwner.java",
    "chars": 813,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/Utils.java",
    "chars": 944,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/AbstractItemCache.java",
    "chars": 2874,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/BasicItemCache.java",
    "chars": 968,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/ImageCache.java",
    "chars": 896,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/ItemCache.java",
    "chars": 1378,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/RepositoryCache.java",
    "chars": 1820,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/cache/ScheduleCache.java",
    "chars": 1053,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/AbstractDockerApiClient.java",
    "chars": 2347,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/DockerApiClient.java",
    "chars": 1161,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/DockerImageNotFoundException.java",
    "chars": 908,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/converter/AbstractDockerResponseConverter.java",
    "chars": 2048,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/converter/DockerResponseConverter.java",
    "chars": 936,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubApiClient.java",
    "chars": 5828,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubAuthenticator.java",
    "chars": 2321,
    "preview": "package io.linuxserver.fleet.v2.client.docker.dockerhub;\n\nimport io.linuxserver.fleet.dockerhub.DockerHubException;\nimpo"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubCredentials.java",
    "chars": 579,
    "preview": "package io.linuxserver.fleet.v2.client.docker.dockerhub;\n\nimport io.linuxserver.fleet.v2.Utils;\n\npublic class DockerHubC"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubImageConverter.java",
    "chars": 1693,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/DockerHubTagConverter.java",
    "chars": 2157,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/IDockerHubAuthenticator.java",
    "chars": 199,
    "preview": "package io.linuxserver.fleet.v2.client.docker.dockerhub;\n\nimport java.util.Map;\n\npublic interface IDockerHubAuthenticato"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/dockerhub/NoOpDockerHubAuthenticator.java",
    "chars": 368,
    "preview": "package io.linuxserver.fleet.v2.client.docker.dockerhub;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class "
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubContainerRegistryClient.java",
    "chars": 1717,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubImageConverter.java",
    "chars": 1310,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/github/GitHubTagConverter.java",
    "chars": 1292,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubImage.java",
    "chars": 786,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/github/model/GitHubTag.java",
    "chars": 784,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiRequest.java",
    "chars": 990,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/AsyncDockerApiResponse.java",
    "chars": 914,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiDelegate.java",
    "chars": 2634,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerApiTaskConsumer.java",
    "chars": 1738,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageMissingUpdateResponse.java",
    "chars": 1255,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateRequest.java",
    "chars": 1794,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/DockerImageUpdateResponse.java",
    "chars": 1917,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/docker/queue/TaskQueue.java",
    "chars": 1846,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/HttpException.java",
    "chars": 969,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/RestClient.java",
    "chars": 5681,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/RestResponse.java",
    "chars": 1279,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/marshalling/JacksonMarshallingStrategy.java",
    "chars": 1785,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/marshalling/MarshallingStrategy.java",
    "chars": 907,
    "preview": "package io.linuxserver.fleet.v2.client.rest.marshalling;\n\nimport java.io.IOException;\n\npublic interface MarshallingStrat"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/proxy/LazyLoadPayloadProxy.java",
    "chars": 1676,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/client/rest/proxy/PayloadProxy.java",
    "chars": 798,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/AbstractDAO.java",
    "chars": 1479,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/DbUpdateStatus.java",
    "chars": 1228,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/DefaultImageDAO.java",
    "chars": 31151,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/DefaultScheduleDAO.java",
    "chars": 2963,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/DefaultUserDAO.java",
    "chars": 7558,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/ImageDAO.java",
    "chars": 2112,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/ImageTemplateFactory.java",
    "chars": 12552,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/ScheduleDAO.java",
    "chars": 896,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/UserDAO.java",
    "chars": 1290,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/db/Utils.java",
    "chars": 2217,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/file/FileManager.java",
    "chars": 4199,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/AbstractDatabaseKey.java",
    "chars": 1492,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/AbstractHasKey.java",
    "chars": 1859,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/AbstractLookupKey.java",
    "chars": 1214,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/AlertKey.java",
    "chars": 1054,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/HasKey.java",
    "chars": 829,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/ImageKey.java",
    "chars": 2692,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/ImageLookupKey.java",
    "chars": 1643,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/Key.java",
    "chars": 833,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/RepositoryKey.java",
    "chars": 1758,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/ScheduleKey.java",
    "chars": 854,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/TagBranchKey.java",
    "chars": 1032,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/key/UserKey.java",
    "chars": 895,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/AbstractAppService.java",
    "chars": 1536,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/ImageService.java",
    "chars": 13742,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/ScheduleService.java",
    "chars": 6188,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/SynchronisationService.java",
    "chars": 4852,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/UserService.java",
    "chars": 4229,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/service/util/TemplateMerger.java",
    "chars": 4201,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AbstractAppTask.java",
    "chars": 2140,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AbstractAppThread.java",
    "chars": 2080,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AbstractTaskQueueConsumer.java",
    "chars": 2042,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AsyncTask.java",
    "chars": 886,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AsyncTaskDelegate.java",
    "chars": 871,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/AsyncTaskResponse.java",
    "chars": 803,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/TaskExecutionException.java",
    "chars": 890,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/TaskResponseControllerProxy.java",
    "chars": 1225,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/ThreadStatus.java",
    "chars": 788,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/AbstractAppSchedule.java",
    "chars": 4600,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/AppSchedule.java",
    "chars": 1194,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/CheckAppVersionSchedule.java",
    "chars": 1187,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/ScheduleSpec.java",
    "chars": 2594,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/TidyHistoricDataSchedule.java",
    "chars": 1190,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/TimeWithUnit.java",
    "chars": 2396,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/cache/RefreshCacheSchedule.java",
    "chars": 1434,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/AllImagesSyncSchedule.java",
    "chars": 1576,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/CleanRemovedImagesSchedule.java",
    "chars": 2597,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/thread/schedule/sync/GetMissingImagesSchedule.java",
    "chars": 1593,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/AbstractSyncItem.java",
    "chars": 2745,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/AppAlert.java",
    "chars": 2666,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/FilePathDetails.java",
    "chars": 1714,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/HasSyncSpec.java",
    "chars": 907,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/Image.java",
    "chars": 6064,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/ImageCountData.java",
    "chars": 1130,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/Repository.java",
    "chars": 2762,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/Tag.java",
    "chars": 1799,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/TagBranch.java",
    "chars": 2212,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/TagDigest.java",
    "chars": 2387,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/User.java",
    "chars": 2167,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/AbstractApiWrapper.java",
    "chars": 1007,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/ApiImagePullHistoryWrapper.java",
    "chars": 3046,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/ApiImageWrapper.java",
    "chars": 1525,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/ApiRepositoryWrapper.java",
    "chars": 1371,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/ApiScheduleWrapper.java",
    "chars": 1058,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/AllImagesExternalApiResponse.java",
    "chars": 2328,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/ExternalApiImage.java",
    "chars": 2148,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/ExternalApiResponse.java",
    "chars": 1167,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiDeviceTemplate.java",
    "chars": 1154,
    "preview": "/*\n * Copyright (c)  2021 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiEnvTemplate.java",
    "chars": 1318,
    "preview": "/*\n * Copyright (c)  2021 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiPortTemplate.java",
    "chars": 1290,
    "preview": "/*\n * Copyright (c)  2021 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiTemplateHolder.java",
    "chars": 2619,
    "preview": "/*\n * Copyright (c)  2021 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/api/external/templates/ApiVolumeTemplate.java",
    "chars": 1358,
    "preview": "/*\n * Copyright (c)  2021 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/docker/DockerCapability.java",
    "chars": 1341,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/docker/DockerImage.java",
    "chars": 2422,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTag.java",
    "chars": 1871,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/docker/DockerTagManifestDigest.java",
    "chars": 1631,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/AbstractParamRequest.java",
    "chars": 2649,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/ImageAppLogo.java",
    "chars": 2109,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/ImageGeneralInfoUpdateRequest.java",
    "chars": 1417,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/ImageOutlineRequest.java",
    "chars": 1854,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/ImageTemplateRequest.java",
    "chars": 5342,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/ImageUrlsUpdateRequest.java",
    "chars": 2037,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/RepositoryOutlineRequest.java",
    "chars": 1059,
    "preview": "/*io.linuxserver.fleet.v2.db\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistri"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/TagBranchOutlineRequest.java",
    "chars": 1233,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/internal/UserOutlineRequest.java",
    "chars": 1629,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/ExternalUrl.java",
    "chars": 2861,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/ExternalUrlKey.java",
    "chars": 1554,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/ImageCoreMeta.java",
    "chars": 3037,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/ImageMetaData.java",
    "chars": 2701,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/ItemSyncSpec.java",
    "chars": 2464,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullHistory.java",
    "chars": 1386,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/history/ImagePullStatistic.java",
    "chars": 2732,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/AbstractTemplateItem.java",
    "chars": 1415,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/DeviceTemplateItem.java",
    "chars": 1032,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/EnvironmentTemplateItem.java",
    "chars": 1233,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/ImageTemplateHolder.java",
    "chars": 3572,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/PortTemplateItem.java",
    "chars": 1880,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/TemplateItem.java",
    "chars": 835,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/types/meta/template/VolumeTemplateItem.java",
    "chars": 1775,
    "preview": "/*\n * Copyright (c)  2020 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/ApiException.java",
    "chars": 898,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/AppRole.java",
    "chars": 831,
    "preview": "/*\n * Copyright (c)  2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * i"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/LocationUtils.java",
    "chars": 942,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/Locations.java",
    "chars": 1756,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/PageModelAttributes.java",
    "chars": 931,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/PageModelSpec.java",
    "chars": 1303,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  },
  {
    "path": "src/main/java/io/linuxserver/fleet/v2/web/SessionAttributes.java",
    "chars": 965,
    "preview": "/*\n * Copyright (c) 2019 LinuxServer.io\n *\n * This program is free software: you can redistribute it and/or modify\n * it"
  }
]

// ... and 87 more files (download for full content)

About this extraction

This page contains the full source code of the linuxserver/fleet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 287 files (2.1 MB), approximately 574.3k tokens, and a symbol index with 1302 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!