Full Code of gpx-animator/gpx-animator for AI

master 62ddb30b9fc1 cached
140 files
4.0 MB
1.1M tokens
784 symbols
1 requests
Download .txt
Showing preview only (4,212K chars total). Download the full file or copy to clipboard to get everything.
Repository: gpx-animator/gpx-animator
Branch: master
Commit: 62ddb30b9fc1
Files: 140
Total size: 4.0 MB

Directory structure:
gitextract_zrhr46wq/

├── .all-contributorsrc
├── .editorconfig
├── .fleet/
│   ├── run.json
│   └── settings.json
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── add-to-project.yml
│       └── gradle.yml
├── .gitignore
├── .gitpod.Dockerfile
├── .gitpod.yml
├── .run/
│   ├── GPX Animator (de) HiDPI.run.xml
│   ├── GPX Animator (de).run.xml
│   ├── GPX Animator (en) HiDPI.run.xml
│   ├── GPX Animator (en).run.xml
│   ├── check test.run.xml
│   ├── check.run.xml
│   └── test.run.xml
├── .sdkmanrc
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── build.gradle
├── config/
│   ├── checkstyle/
│   │   └── checkstyle.xml
│   ├── pmd/
│   │   └── pmd-rules.xml
│   └── spotbugs/
│       └── exclude.xml
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── install/
│   └── gpx-animator.install4j
├── jitpack.yml
├── package.json
├── renovate.json
├── settings.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── app/
    │   │       └── gpx_animator/
    │   │           ├── Main.java
    │   │           ├── core/
    │   │           │   ├── Constants.java
    │   │           │   ├── Help.java
    │   │           │   ├── Option.java
    │   │           │   ├── UserException.java
    │   │           │   ├── configuration/
    │   │           │   │   ├── Configuration.java
    │   │           │   │   ├── TrackConfiguration.java
    │   │           │   │   └── adapter/
    │   │           │   │       ├── ColorXmlAdapter.java
    │   │           │   │       ├── FileXmlAdapter.java
    │   │           │   │       ├── FontXmlAdapter.java
    │   │           │   │       └── TrackIconXmlAdapter.java
    │   │           │   ├── data/
    │   │           │   │   ├── MapTemplate.java
    │   │           │   │   ├── MusicCodec.java
    │   │           │   │   ├── Photo.java
    │   │           │   │   ├── Position.java
    │   │           │   │   ├── SpeedUnit.java
    │   │           │   │   ├── TrackIcon.java
    │   │           │   │   ├── VideoCodec.java
    │   │           │   │   ├── entity/
    │   │           │   │   │   ├── MyPoint.java
    │   │           │   │   │   ├── Track.java
    │   │           │   │   │   ├── TrackPoint.java
    │   │           │   │   │   ├── TrackSegment.java
    │   │           │   │   │   ├── TrackType.java
    │   │           │   │   │   └── WayPoint.java
    │   │           │   │   └── gpx/
    │   │           │   │       ├── GPX.java
    │   │           │   │       ├── GpxContentHandler.java
    │   │           │   │       ├── GpxParser.java
    │   │           │   │       └── GpxPoint.java
    │   │           │   ├── preferences/
    │   │           │   │   └── Preferences.java
    │   │           │   ├── renderer/
    │   │           │   │   ├── ImageRenderer.java
    │   │           │   │   ├── Metadata.java
    │   │           │   │   ├── Renderer.java
    │   │           │   │   ├── RenderingContext.java
    │   │           │   │   ├── TextRenderer.java
    │   │           │   │   ├── cache/
    │   │           │   │   │   └── TileCache.java
    │   │           │   │   ├── framewriter/
    │   │           │   │   │   ├── FileFrameWriter.java
    │   │           │   │   │   ├── FrameWriter.java
    │   │           │   │   │   ├── NullFrameWriter.java
    │   │           │   │   │   └── VideoFrameWriter.java
    │   │           │   │   └── plugins/
    │   │           │   │       ├── AttributionPlugin.java
    │   │           │   │       ├── BackgroundColorPlugin.java
    │   │           │   │       ├── BackgroundImagePlugin.java
    │   │           │   │       ├── BackgroundMapPlugin.java
    │   │           │   │       ├── CommentPlugin.java
    │   │           │   │       ├── InformationPlugin.java
    │   │           │   │       ├── LogoPlugin.java
    │   │           │   │       ├── PhotoPlugin.java
    │   │           │   │       ├── PreviewPlugin.java
    │   │           │   │       └── RendererPlugin.java
    │   │           │   └── util/
    │   │           │       ├── DateUtil.java
    │   │           │       ├── FormatUtil.java
    │   │           │       ├── MapUtil.java
    │   │           │       ├── Notification.java
    │   │           │       ├── PluginUtil.java
    │   │           │       ├── PointUtil.java
    │   │           │       ├── RenderUtil.java
    │   │           │       ├── Sound.java
    │   │           │       └── Utils.java
    │   │           └── ui/
    │   │               ├── UIMode.java
    │   │               ├── cli/
    │   │               │   └── CommandLineConfigurationFactory.java
    │   │               └── swing/
    │   │                   ├── ColorSelector.java
    │   │                   ├── DurationEditor.java
    │   │                   ├── DurationFormatter.java
    │   │                   ├── DurationSpinnerModel.java
    │   │                   ├── EmptyNullSpinnerModel.java
    │   │                   ├── EmptyZeroNumberEditor.java
    │   │                   ├── ErrorDialog.java
    │   │                   ├── EscapeDialog.java
    │   │                   ├── FileSelector.java
    │   │                   ├── FontChooser.java
    │   │                   ├── FontSelector.java
    │   │                   ├── GeneralSettingsPanel.java
    │   │                   ├── JPlaceholderTextField.java
    │   │                   ├── MainFrame.java
    │   │                   ├── MarkdownDialog.java
    │   │                   ├── MarkdownFileDialog.java
    │   │                   ├── PreferencesDialog.java
    │   │                   ├── PreviewDialog.java
    │   │                   ├── ProtocolDialog.java
    │   │                   ├── TrackSettingsPanel.java
    │   │                   └── UsageDialog.java
    │   └── resources/
    │       ├── ABOUT.md
    │       ├── i18n/
    │       │   ├── Messages.properties
    │       │   └── Messages_de.properties
    │       └── logback.xml
    └── test/
        ├── java/
        │   └── app/
        │       └── gpx_animator/
        │           ├── MemoryAppender.java
        │           ├── MissingTranslationsTest.java
        │           ├── core/
        │           │   ├── configuration/
        │           │   │   └── adapter/
        │           │   │       └── FontXmlAdapterTest.java
        │           │   ├── data/
        │           │   │   ├── SpeedUnitTest.java
        │           │   │   └── gpx/
        │           │   │       └── GpxContentHandlerTest.java
        │           │   ├── renderer/
        │           │   │   └── plugins/
        │           │   │       └── PhotoPluginTest.java
        │           │   └── util/
        │           │       ├── DateUtilTest.java
        │           │       ├── PointUtilTest.java
        │           │       ├── RenderUtilTest.java
        │           │       └── UtilsTest.java
        │           └── ui/
        │               ├── cli/
        │               │   ├── CommandLineConfigurationFactoryTest.java
        │               │   ├── CommandLineIT.java
        │               │   └── OptionParam.java
        │               └── swing/
        │                   ├── DurationFormatterTest.java
        │                   └── DurationSpinnerModelTest.java
        └── resources/
            └── gpx/
                ├── bikeride.gpx
                └── comment.gpx

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

================================================
FILE: .all-contributorsrc
================================================
{
  "projectName": "gpx-animator",
  "projectOwner": "gpx-animator",
  "repoType": "github",
  "repoHost": "https://github.com",
  "files": [
    "README.md"
  ],
  "imageSize": 100,
  "commit": true,
  "commitConvention": "gitmoji",
  "badgeTemplate": "[![All Contributors](https://img.shields.io/badge/all_contributors-<%= contributors.length %>-orange.svg?style=flat-square)](#contributors)",
  "contributors": [
    {
      "login": "McPringle",
      "name": "Marcus Fihlon",
      "avatar_url": "https://avatars.githubusercontent.com/u/1254039?v=4",
      "profile": "https://github.com/McPringle",
      "contributions": [
        "projectManagement",
        "ideas",
        "code"
      ]
    },
    {
      "login": "zdila",
      "name": "Martin Ždila",
      "avatar_url": "https://avatars.githubusercontent.com/u/636095?v=4",
      "profile": "https://github.com/zdila",
      "contributions": [
        "projectManagement",
        "ideas",
        "code"
      ]
    },
    {
      "login": "n76",
      "name": "n76",
      "avatar_url": "https://avatars.githubusercontent.com/u/4681938?v=4",
      "profile": "http://retiredtechie.fitchfamily.org/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "markus-schmidlin",
      "name": "Markus Schmidlin",
      "avatar_url": "https://avatars.githubusercontent.com/u/13030829?v=4",
      "profile": "https://github.com/markus-schmidlin",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "martinfrancois",
      "name": "François Martin",
      "avatar_url": "https://avatars.githubusercontent.com/u/14319020?v=4",
      "profile": "https://github.com/martinfrancois",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "maebli",
      "name": "Maebli",
      "avatar_url": "https://avatars.githubusercontent.com/u/1138612?v=4",
      "profile": "https://github.com/maebli",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "rindy22",
      "name": "rindy22",
      "avatar_url": "https://avatars.githubusercontent.com/u/56276884?v=4",
      "profile": "https://github.com/rindy22",
      "contributions": [
        "ideas",
        "code"
      ]
    },
    {
      "login": "bat-bloke",
      "name": "Andy Oakey",
      "avatar_url": "https://avatars.githubusercontent.com/u/57795480?v=4",
      "profile": "https://github.com/bat-bloke",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "fgaignat",
      "name": "fgaignat",
      "avatar_url": "https://avatars.githubusercontent.com/u/23083528?v=4",
      "profile": "https://github.com/fgaignat",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "charlysog",
      "name": "charlysog",
      "avatar_url": "https://avatars.githubusercontent.com/u/63605339?v=4",
      "profile": "https://github.com/charlysog",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "waschulte",
      "name": "waschulte",
      "avatar_url": "https://avatars.githubusercontent.com/u/59023045?v=4",
      "profile": "https://github.com/waschulte",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "SirCremefresh",
      "name": "Donato Wolfisberg",
      "avatar_url": "https://avatars.githubusercontent.com/u/20863779?v=4",
      "profile": "https://github.com/SirCremefresh",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "galz10",
      "name": "Gal Zahavi",
      "avatar_url": "https://avatars.githubusercontent.com/u/38544478?v=4",
      "profile": "https://github.com/galz10",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "poorlymac",
      "name": "poorlymac",
      "avatar_url": "https://avatars.githubusercontent.com/u/16620846?v=4",
      "profile": "https://github.com/poorlymac",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "abarber7",
      "name": "Antonio D Barber",
      "avatar_url": "https://avatars.githubusercontent.com/u/21110513?v=4",
      "profile": "https://www.linkedin.com/in/antonio-barber-67273bba/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "herrwusel",
      "name": "herrwusel",
      "avatar_url": "https://avatars.githubusercontent.com/u/8242787?v=4",
      "profile": "https://github.com/herrwusel",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "rammmiro",
      "name": "Ramiro Martínez Pinilla",
      "avatar_url": "https://avatars.githubusercontent.com/u/32325306?v=4",
      "profile": "https://github.com/rammmiro",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "pdroogers",
      "name": "Peter Droogers",
      "avatar_url": "https://avatars.githubusercontent.com/u/12559676?v=4",
      "profile": "http://www.futurewater.nl/",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "fwieringen",
      "name": "Friso van Wieringen",
      "avatar_url": "https://avatars.githubusercontent.com/u/4232879?v=4",
      "profile": "https://github.com/fwieringen",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "thomergil",
      "name": "Thomer Gil",
      "avatar_url": "https://avatars.githubusercontent.com/u/1020105?v=4",
      "profile": "http://thomer.com/",
      "contributions": [
        "bug",
        "code"
      ]
    },
    {
      "login": "mundry",
      "name": "mundry",
      "avatar_url": "https://avatars.githubusercontent.com/u/1453314?v=4",
      "profile": "https://github.com/mundry",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "MrTrustor",
      "name": "Théo Chamley",
      "avatar_url": "https://avatars.githubusercontent.com/u/2864678?v=4",
      "profile": "http://blog.mrtrustor.net/",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "triskaidekafeliks",
      "name": "triskaidekafeliks",
      "avatar_url": "https://avatars.githubusercontent.com/u/19534176?v=4",
      "profile": "https://github.com/triskaidekafeliks",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "krugerk",
      "name": "krugerk",
      "avatar_url": "https://avatars.githubusercontent.com/u/4656811?v=4",
      "profile": "https://github.com/krugerk",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "piiskop",
      "name": "peacecop kalmer:",
      "avatar_url": "https://avatars.githubusercontent.com/u/14224528?v=4",
      "profile": "https://github.com/piiskop",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "rneppi",
      "name": "rneppi",
      "avatar_url": "https://avatars.githubusercontent.com/u/28830856?v=4",
      "profile": "https://github.com/rneppi",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "szolnokit",
      "name": "szolnokit",
      "avatar_url": "https://avatars.githubusercontent.com/u/49479918?v=4",
      "profile": "https://github.com/szolnokit",
      "contributions": [
        "bug",
        "infra",
        "code"
      ]
    },
    {
      "login": "fkroepfl",
      "name": "Franz Kröpfl",
      "avatar_url": "https://avatars.githubusercontent.com/u/6333880?v=4",
      "profile": "http://www.linkedin.com/in/franzkroepfl",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "stefanweisswange",
      "name": "Stefan Weißwange",
      "avatar_url": "https://avatars.githubusercontent.com/u/27846815?v=4",
      "profile": "http://rifter.org/",
      "contributions": [
        "bug"
      ]
    },
    {
      "login": "scordio",
      "name": "Stefano Cordio",
      "avatar_url": "https://avatars.githubusercontent.com/u/26772046?v=4",
      "profile": "https://github.com/scordio",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "Interactiondesigner",
      "name": "Interactiondesigner",
      "avatar_url": "https://avatars.githubusercontent.com/u/17220369?v=4",
      "profile": "https://github.com/Interactiondesigner",
      "contributions": [
        "design"
      ]
    },
    {
      "login": "Melancholic",
      "name": "Andrey N.",
      "avatar_url": "https://avatars.githubusercontent.com/u/2463361?v=4",
      "profile": "https://github.com/Melancholic",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "ky0n",
      "name": "Hendrik",
      "avatar_url": "https://avatars.githubusercontent.com/u/30866028?v=4",
      "profile": "https://github.com/ky0n",
      "contributions": [
        "bug",
        "code"
      ]
    },
    {
      "login": "FadriPestalozzi",
      "name": "FadriPestalozzi",
      "avatar_url": "https://avatars.githubusercontent.com/u/16454272?v=4",
      "profile": "https://github.com/FadriPestalozzi",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "blacksun777",
      "name": "blacksun777",
      "avatar_url": "https://avatars.githubusercontent.com/u/11344657?v=4",
      "profile": "https://github.com/blacksun777",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "reinhapa",
      "name": "Patrick Reinhart",
      "avatar_url": "https://avatars.githubusercontent.com/u/4694567?v=4",
      "profile": "https://mastodon.social/@reinhapa",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "danielmischler",
      "name": "Daniel Mischler",
      "avatar_url": "https://avatars.githubusercontent.com/u/23777?v=4",
      "profile": "https://github.com/danielmischler",
      "contributions": [
        "code"
      ]
    },
    {
      "login": "onixred",
      "name": "Andrey",
      "avatar_url": "https://avatars.githubusercontent.com/u/26665874?v=4",
      "profile": "https://bitbucket.org/onixred",
      "contributions": [
        "code"
      ]
    }
  ],
  "contributorsPerLine": 7,
  "linkToUsage": false
}


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

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

[*.css]
ij_css_align_closing_brace_with_properties = false
ij_css_blank_lines_around_nested_selector = 1
ij_css_blank_lines_between_blocks = 1
ij_css_brace_placement = end_of_line
ij_css_enforce_quotes_on_format = false
ij_css_hex_color_long_format = false
ij_css_hex_color_lower_case = false
ij_css_hex_color_short_format = false
ij_css_hex_color_upper_case = false
ij_css_keep_blank_lines_in_code = 2
ij_css_keep_indents_on_empty_lines = false
ij_css_keep_single_line_blocks = false
ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow
ij_css_space_after_colon = true
ij_css_space_before_opening_brace = true
ij_css_use_double_quotes = true
ij_css_value_alignment = do_not_align

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

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

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

[{*.cjs,*.js}]
ij_continuation_indent_size = 4
ij_javascript_align_imports = false
ij_javascript_align_multiline_array_initializer_expression = false
ij_javascript_align_multiline_binary_operation = false
ij_javascript_align_multiline_chained_methods = false
ij_javascript_align_multiline_extends_list = false
ij_javascript_align_multiline_for = true
ij_javascript_align_multiline_parameters = true
ij_javascript_align_multiline_parameters_in_calls = false
ij_javascript_align_multiline_ternary_operation = false
ij_javascript_align_object_properties = 0
ij_javascript_align_union_types = false
ij_javascript_align_var_statements = 0
ij_javascript_array_initializer_new_line_after_left_brace = false
ij_javascript_array_initializer_right_brace_on_new_line = false
ij_javascript_array_initializer_wrap = off
ij_javascript_assignment_wrap = off
ij_javascript_binary_operation_sign_on_next_line = false
ij_javascript_binary_operation_wrap = off
ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**/*,@angular/material,@angular/material/typings/**
ij_javascript_blank_lines_after_imports = 1
ij_javascript_blank_lines_around_class = 1
ij_javascript_blank_lines_around_field = 0
ij_javascript_blank_lines_around_function = 1
ij_javascript_blank_lines_around_method = 1
ij_javascript_block_brace_style = end_of_line
ij_javascript_call_parameters_new_line_after_left_paren = false
ij_javascript_call_parameters_right_paren_on_new_line = false
ij_javascript_call_parameters_wrap = off
ij_javascript_catch_on_new_line = false
ij_javascript_chained_call_dot_on_new_line = true
ij_javascript_class_brace_style = end_of_line
ij_javascript_comma_on_new_line = false
ij_javascript_do_while_brace_force = never
ij_javascript_else_on_new_line = false
ij_javascript_enforce_trailing_comma = keep
ij_javascript_extends_keyword_wrap = off
ij_javascript_extends_list_wrap = off
ij_javascript_field_prefix = _
ij_javascript_file_name_style = relaxed
ij_javascript_finally_on_new_line = false
ij_javascript_for_brace_force = never
ij_javascript_for_statement_new_line_after_left_paren = false
ij_javascript_for_statement_right_paren_on_new_line = false
ij_javascript_for_statement_wrap = off
ij_javascript_force_quote_style = false
ij_javascript_force_semicolon_style = false
ij_javascript_function_expression_brace_style = end_of_line
ij_javascript_if_brace_force = never
ij_javascript_import_merge_members = global
ij_javascript_import_prefer_absolute_path = global
ij_javascript_import_sort_members = true
ij_javascript_import_sort_module_name = false
ij_javascript_import_use_node_resolution = true
ij_javascript_imports_wrap = on_every_item
ij_javascript_indent_case_from_switch = true
ij_javascript_indent_chained_calls = true
ij_javascript_indent_package_children = 0
ij_javascript_jsx_attribute_value = braces
ij_javascript_keep_blank_lines_in_code = 2
ij_javascript_keep_first_column_comment = true
ij_javascript_keep_indents_on_empty_lines = false
ij_javascript_keep_line_breaks = true
ij_javascript_keep_simple_blocks_in_one_line = false
ij_javascript_keep_simple_methods_in_one_line = false
ij_javascript_line_comment_add_space = true
ij_javascript_line_comment_at_first_column = false
ij_javascript_method_brace_style = end_of_line
ij_javascript_method_call_chain_wrap = off
ij_javascript_method_parameters_new_line_after_left_paren = false
ij_javascript_method_parameters_right_paren_on_new_line = false
ij_javascript_method_parameters_wrap = off
ij_javascript_object_literal_wrap = on_every_item
ij_javascript_parentheses_expression_new_line_after_left_paren = false
ij_javascript_parentheses_expression_right_paren_on_new_line = false
ij_javascript_place_assignment_sign_on_next_line = false
ij_javascript_prefer_as_type_cast = false
ij_javascript_prefer_parameters_wrap = false
ij_javascript_reformat_c_style_comments = false
ij_javascript_space_after_colon = true
ij_javascript_space_after_comma = true
ij_javascript_space_after_dots_in_rest_parameter = false
ij_javascript_space_after_generator_mult = true
ij_javascript_space_after_property_colon = true
ij_javascript_space_after_quest = true
ij_javascript_space_after_type_colon = true
ij_javascript_space_after_unary_not = false
ij_javascript_space_before_async_arrow_lparen = true
ij_javascript_space_before_catch_keyword = true
ij_javascript_space_before_catch_left_brace = true
ij_javascript_space_before_catch_parentheses = true
ij_javascript_space_before_class_lbrace = true
ij_javascript_space_before_class_left_brace = true
ij_javascript_space_before_colon = true
ij_javascript_space_before_comma = false
ij_javascript_space_before_do_left_brace = true
ij_javascript_space_before_else_keyword = true
ij_javascript_space_before_else_left_brace = true
ij_javascript_space_before_finally_keyword = true
ij_javascript_space_before_finally_left_brace = true
ij_javascript_space_before_for_left_brace = true
ij_javascript_space_before_for_parentheses = true
ij_javascript_space_before_for_semicolon = false
ij_javascript_space_before_function_left_parenth = true
ij_javascript_space_before_generator_mult = false
ij_javascript_space_before_if_left_brace = true
ij_javascript_space_before_if_parentheses = true
ij_javascript_space_before_method_call_parentheses = false
ij_javascript_space_before_method_left_brace = true
ij_javascript_space_before_method_parentheses = false
ij_javascript_space_before_property_colon = false
ij_javascript_space_before_quest = true
ij_javascript_space_before_switch_left_brace = true
ij_javascript_space_before_switch_parentheses = true
ij_javascript_space_before_try_left_brace = true
ij_javascript_space_before_type_colon = false
ij_javascript_space_before_unary_not = false
ij_javascript_space_before_while_keyword = true
ij_javascript_space_before_while_left_brace = true
ij_javascript_space_before_while_parentheses = true
ij_javascript_spaces_around_additive_operators = true
ij_javascript_spaces_around_arrow_function_operator = true
ij_javascript_spaces_around_assignment_operators = true
ij_javascript_spaces_around_bitwise_operators = true
ij_javascript_spaces_around_equality_operators = true
ij_javascript_spaces_around_logical_operators = true
ij_javascript_spaces_around_multiplicative_operators = true
ij_javascript_spaces_around_relational_operators = true
ij_javascript_spaces_around_shift_operators = true
ij_javascript_spaces_around_unary_operator = false
ij_javascript_spaces_within_array_initializer_brackets = false
ij_javascript_spaces_within_brackets = false
ij_javascript_spaces_within_catch_parentheses = false
ij_javascript_spaces_within_for_parentheses = false
ij_javascript_spaces_within_if_parentheses = false
ij_javascript_spaces_within_imports = false
ij_javascript_spaces_within_interpolation_expressions = false
ij_javascript_spaces_within_method_call_parentheses = false
ij_javascript_spaces_within_method_parentheses = false
ij_javascript_spaces_within_object_literal_braces = false
ij_javascript_spaces_within_object_type_braces = true
ij_javascript_spaces_within_parentheses = false
ij_javascript_spaces_within_switch_parentheses = false
ij_javascript_spaces_within_type_assertion = false
ij_javascript_spaces_within_union_types = true
ij_javascript_spaces_within_while_parentheses = false
ij_javascript_special_else_if_treatment = true
ij_javascript_ternary_operation_signs_on_next_line = false
ij_javascript_ternary_operation_wrap = off
ij_javascript_union_types_wrap = on_every_item
ij_javascript_use_chained_calls_group_indents = false
ij_javascript_use_double_quotes = true
ij_javascript_use_explicit_js_extension = global
ij_javascript_use_path_mapping = always
ij_javascript_use_public_modifier = false
ij_javascript_use_semicolon_after_statement = true
ij_javascript_var_declaration_wrap = normal
ij_javascript_while_brace_force = never
ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false

[{*.jhm,*.xslt,*.xul,*.rng,*.xsl,*.xsd,*.ant,*.wadl,*.tld,*.fxml,*.jrxml,*.xml,*.jnlp,*.wsdl,*.wsdd,*.pom,*.xjb}]
ij_xml_block_comment_at_first_column = true
ij_xml_keep_indents_on_empty_lines = false
ij_xml_line_comment_at_first_column = true

[{*.kt,*.kts}]
ij_kotlin_align_in_columns_case_branch = false
ij_kotlin_align_multiline_binary_operation = false
ij_kotlin_align_multiline_extends_list = false
ij_kotlin_align_multiline_method_parentheses = false
ij_kotlin_align_multiline_parameters = true
ij_kotlin_align_multiline_parameters_in_calls = false
ij_kotlin_assignment_wrap = off
ij_kotlin_blank_lines_after_class_header = 0
ij_kotlin_blank_lines_around_block_when_branches = 0
ij_kotlin_block_comment_at_first_column = true
ij_kotlin_call_parameters_new_line_after_left_paren = false
ij_kotlin_call_parameters_right_paren_on_new_line = false
ij_kotlin_call_parameters_wrap = off
ij_kotlin_catch_on_new_line = false
ij_kotlin_class_annotation_wrap = split_into_lines
ij_kotlin_continuation_indent_for_chained_calls = true
ij_kotlin_continuation_indent_for_expression_bodies = true
ij_kotlin_continuation_indent_in_argument_lists = true
ij_kotlin_continuation_indent_in_elvis = true
ij_kotlin_continuation_indent_in_if_conditions = true
ij_kotlin_continuation_indent_in_parameter_lists = true
ij_kotlin_continuation_indent_in_supertype_lists = true
ij_kotlin_else_on_new_line = false
ij_kotlin_enum_constants_wrap = off
ij_kotlin_extends_list_wrap = off
ij_kotlin_field_annotation_wrap = split_into_lines
ij_kotlin_finally_on_new_line = false
ij_kotlin_if_rparen_on_new_line = false
ij_kotlin_import_nested_classes = false
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
ij_kotlin_keep_blank_lines_before_right_brace = 2
ij_kotlin_keep_blank_lines_in_code = 2
ij_kotlin_keep_blank_lines_in_declarations = 2
ij_kotlin_keep_first_column_comment = true
ij_kotlin_keep_indents_on_empty_lines = false
ij_kotlin_keep_line_breaks = true
ij_kotlin_lbrace_on_next_line = false
ij_kotlin_line_comment_add_space = false
ij_kotlin_line_comment_at_first_column = true
ij_kotlin_method_annotation_wrap = split_into_lines
ij_kotlin_method_call_chain_wrap = off
ij_kotlin_method_parameters_new_line_after_left_paren = false
ij_kotlin_method_parameters_right_paren_on_new_line = false
ij_kotlin_method_parameters_wrap = off
ij_kotlin_name_count_to_use_star_import = 2147483647
ij_kotlin_name_count_to_use_star_import_for_members = 2147483647
ij_kotlin_parameter_annotation_wrap = off
ij_kotlin_space_after_comma = true
ij_kotlin_space_after_extend_colon = true
ij_kotlin_space_after_type_colon = true
ij_kotlin_space_before_catch_parentheses = true
ij_kotlin_space_before_comma = false
ij_kotlin_space_before_extend_colon = true
ij_kotlin_space_before_for_parentheses = true
ij_kotlin_space_before_if_parentheses = true
ij_kotlin_space_before_lambda_arrow = true
ij_kotlin_space_before_type_colon = false
ij_kotlin_space_before_when_parentheses = true
ij_kotlin_space_before_while_parentheses = true
ij_kotlin_spaces_around_additive_operators = true
ij_kotlin_spaces_around_assignment_operators = true
ij_kotlin_spaces_around_equality_operators = true
ij_kotlin_spaces_around_function_type_arrow = true
ij_kotlin_spaces_around_logical_operators = true
ij_kotlin_spaces_around_multiplicative_operators = true
ij_kotlin_spaces_around_range = false
ij_kotlin_spaces_around_relational_operators = true
ij_kotlin_spaces_around_unary_operator = false
ij_kotlin_spaces_around_when_arrow = true
ij_kotlin_variable_annotation_wrap = off
ij_kotlin_while_on_new_line = false
ij_kotlin_wrap_elvis_expressions = 1
ij_kotlin_wrap_expression_body_functions = 0
ij_kotlin_wrap_first_method_in_call_chain = false

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

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

[{.asciidoctorconfig,*.adoc,*.asciidoc,*.ad}]
ij_asciidoc_formatting_enabled = true
ij_asciidoc_one_sentence_per_line = true

[{.eslintrc,.stylelintrc,jest.config,.babelrc,bowerrc,*.json,*.jsb3,*.jsb2}]
indent_size = 2
ij_json_keep_blank_lines_in_code = 0
ij_json_keep_indents_on_empty_lines = false
ij_json_keep_line_breaks = true
ij_json_space_after_colon = true
ij_json_space_after_comma = true
ij_json_space_before_colon = true
ij_json_space_before_comma = false
ij_json_spaces_within_braces = false
ij_json_spaces_within_brackets = false
ij_json_wrap_long_lines = false

[{spring.handlers,spring.schemas,*.properties}]
ij_properties_align_group_field_declarations = false


================================================
FILE: .fleet/run.json
================================================
{
  "configurations": [
    {
      "name": "run gpx-animator",
      "type": "gradle",
      "tasks": [
        "run"
      ]
    }
  ]
}

================================================
FILE: .fleet/settings.json
================================================
{
    "backend.maxHeapSizeMb": 2048
}

================================================
FILE: .gitattributes
================================================
*.bat text eol=crlf
gradlew eol=lf


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''

---

**Describe the bug**
A clear and concise description of what the bug is.

**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**
A clear and concise description of what you expected to happen.

**Screenshots**
If applicable, add screenshots to help explain your problem.

**Desktop (please complete the following information):**
 - OS: [e.g. Linux, MacOS, Windows]
 - OS Version [e.g. 15.1.1]
 - Browser [e.g. chrome, safari]
 - Browser Version [e.g. 22]

**Smartphone (please complete the following information):**
 - Device: [e.g. iPhone 16 Pro Max, Samsung Galaxy S24+]
 - OS: [e.g. Android, iOS]
 - OS Version [e.g. 15.1.1]
 - Browser [e.g. stock browser, safari]
 - Browser Version [e.g. 22]

**Additional context**
Add any other context about the problem here.


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''

---

**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

**Describe the solution you'd like**
A clear and concise description of what you want to happen.

**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.

**Additional context**
Add any other context or screenshots about the feature request here.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - package-ecosystem: "Gradle"
    directory: "/"
    schedule:
      interval: "daily"
      time: "01:00"
    commit-message:
      prefix: "⬆️ "


================================================
FILE: .github/workflows/add-to-project.yml
================================================
name: Adds all issues to project board

on:
  issues:
    types:
      - opened
  pull_request_target:
    types:
      - opened

jobs:
  add-to-project:
    if: github.repository_owner == 'gpx-animator'
    name: Add issue to project board
    runs-on: ubuntu-latest
    steps:
      - uses: actions/add-to-project@v2
        with:
          project-url: https://github.com/orgs/gpx-animator/projects/2
          github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }}


================================================
FILE: .github/workflows/gradle.yml
================================================
name: Java CI with Gradle

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v6
    - name: Set up JDK 25
      uses: actions/setup-java@v5
      with:
        java-version: '25'
        distribution: 'temurin'
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    - name: Build with Gradle
      run: ./gradlew assemble
    - uses: actions/upload-artifact@v7
      if: failure()
      with:
        name: testreports
        path: /home/runner/work/gpx-animator/gpx-animator/build/reports/


================================================
FILE: .gitignore
================================================
# Gradle build system
/.gradle

# Build artefacts
/bin
/build
/out
/target

# Yarn/Node/NPM
/node_modules

# Eclipse project file
/.settings
/.classpath
/.project

# IntelliJ IDEA project files
/*.iml
/*.iws
/*.ipr
/.idea

# Theia project files
/.theia

# VS Code project files
/.vscode

# OS files
.DS_Store
$RECYCLE.BIN
[Dd]esktop.ini
Thumbs.db
*.lnk

# Video animation output
*.mp4

# Files copied at build time
/src/main/resources/CHANGELOG.md
/src/main/resources/LICENSE.md

# Install4J
/install/gpx-animator.install4j~
/install/install4j_images/
/install/media/


================================================
FILE: .gitpod.Dockerfile
================================================
FROM gitpod/workspace-full-vnc
USER root
RUN apt-get update \
    && bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && sdk install java 25.0.1-tem" \
    && bash -c 'echo export JAVA_TOOL_OPTIONS=\"\$JAVA_TOOL_OPTIONS -Dsun.java2d.xrender=false\" >> /home/gitpod/.bashrc' \
    && apt-get install -y openjfx libopenjfx-java matchbox \
    && apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
    


================================================
FILE: .gitpod.yml
================================================
image:
  file: .gitpod.Dockerfile

tasks:
  - init: ./gradlew assemble

ports:
  - port: 6080
    onOpen: open-preview
  - port: 5900
    onOpen: ignore
  - port: 35900
    onOpen: ignore

github:
  prebuilds:
    # enable for the master/default branch (defaults to true)
    master: true
    # enable for all branches in this repo (defaults to false)
    branches: true
    # enable for pull requests coming from this repo (defaults to true)
    pullRequests: true
    # enable for pull requests coming from forks (defaults to false)
    pullRequestsFromForks: true
    # add a check to pull requests (defaults to true)
    addCheck: true
    # add a "Review in Gitpod" button as a comment to pull requests (defaults to false)
    addComment: true
    # add a "Review in Gitpod" button to the pull request's description (defaults to false)
    addBadge: false
    # add a label once the prebuild is ready to pull requests (defaults to false)
    addLabel: false


================================================
FILE: .run/GPX Animator (de) HiDPI.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="run (de_CH) HiDPI" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="env">
        <map>
          <entry key="GDK_SCALE" value="2" />
        </map>
      </option>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="run" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list />
      </option>
      <option name="vmOptions" value="-Duser.country=CH -Duser.language=de" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>


================================================
FILE: .run/GPX Animator (de).run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="run (de_CH)" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="run" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list />
      </option>
      <option name="vmOptions" value="-Duser.country=CH -Duser.language=de" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/GPX Animator (en) HiDPI.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="run (en_US) HiDPI" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="env">
        <map>
          <entry key="GDK_SCALE" value="2" />
        </map>
      </option>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="run" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list />
      </option>
      <option name="vmOptions" value="-Duser.country=US -Duser.language=en" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>


================================================
FILE: .run/GPX Animator (en).run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="run (en_US)" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="run" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list />
      </option>
      <option name="vmOptions" value="-Duser.country=US -Duser.language=en" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/check test.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="check test" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="check" />
          <option value="test" />
        </list>
      </option>
      <option name="vmOptions" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/check.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="check" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="check" />
        </list>
      </option>
      <option name="vmOptions" value="" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .run/test.run.xml
================================================
<component name="ProjectRunConfigurationManager">
  <configuration default="false" name="test" type="GradleRunConfiguration" factoryName="Gradle">
    <ExternalSystemSettings>
      <option name="executionName" />
      <option name="externalProjectPath" value="$PROJECT_DIR$" />
      <option name="externalSystemIdString" value="GRADLE" />
      <option name="scriptParameters" value="" />
      <option name="taskDescriptions">
        <list />
      </option>
      <option name="taskNames">
        <list>
          <option value="test" />
        </list>
      </option>
      <option name="vmOptions" value="" />
    </ExternalSystemSettings>
    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
    <DebugAllEnabled>false</DebugAllEnabled>
    <method v="2" />
  </configuration>
</component>

================================================
FILE: .sdkmanrc
================================================
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=25.0.1-tem


================================================
FILE: CHANGELOG.md
================================================
# Changelog

Please report any bugs and feature requests via our
[GitHub Issue Tracker](https://github.com/gpx-animator/gpx-animator/issues).
For questions and support requests, please use
[GitHub Discussions](https://github.com/gpx-animator/gpx-animator/discussions).

## Version 1.9.0

**Release date: work in progress 🚧**

* Upgrade to Java 25 LTS

### Features

* Add option to freeze map before/after showing photos

### Fixes

* Fix format error when reading date and time from GPX file
* Fix missing command-line option to customize information text
* Fix missing command-line option for pre draw line width
* Fix missing command-line option to select the video codec
* Fix missing help text for preview length
* Fix error message when using invalid video resolution
* Fix boolean CLI options to accept true/false  
  Attention: You might need to modify your scripts if you make use of one of the following options:
  - `--keep-idle`: removed, use `--skip-idle false` instead
  - `--skip-idle`: needs `true` or `false` as an argument
  - `--track-icon-mirror`: needs `true` or `false` as an argument
  - `--pre-draw-track`: needs `true` or `false` as an argument

### Other

---

## Version 1.8.1

**Release date: 2023-04-07**

### Fixed bugs

* Portrait photos are now displayed in the correct orientation
* Portrait photos are now displayed in the correct size
* Parsing date and time offset of photos now support missing patterns
* Fix missing CLI option for `--keep-first-frame`
* Fix reading wrong comments from GPX files

### Maintenance
* 
* Better error message for missing implementation of CLI option 

---

## Version 1.8.0

**Release date: 2023-02-22**

### New features

* Support for Apple Silicon (M1/M2) processors
* Support for MPEG-H Part2/HEVC (H.265) codec
* Support for multi-track GPX files
* Preview the rendering of the map
* Make the content of the information box configurable
* Show the time left when rendering the video
* Configure the width of the pre-draw line 
* Smooth line drawing between track points
* Delete cached map tiles in preferences dialog
* New configuration option to specify the user agent when downloading map data
* Support for API keys in map template URLs
* New speed unit (min/500m)
* Time per distance speed units now display as m:ss
* GPS status with timeout (OK/LOST)
* New menu entry to show the protocol (for support requests)
* Optionally configure different icon at the end of each track

### Fixed bugs

* Filter unsupported map types (now all shown maps should work)
* Photos are now displayed correctly oriented based on their metadata
* No more automatically selecting Cambodia map after map update
* Command line parameter "--tail-color-fadeout" now works as expected

### Maintenance

* GPX Animator has a new home: [https://github.com/gpx-animator/gpx-animator](https://github.com/gpx-animator/gpx-animator)
* The GitHub repository now uses the [All Contributors](https://allcontributors.org/) bot and CLI

---

## Version 1.7.0

**Release date: 2021-08-14**

### New features

* Realtime preview while rendering is in progress (can be disabled)
* System notifications when rendering stops or finishes
* Map data update over the air (manually via `File` menu)
* Specify a separate font for waypoints (optional)
* Read speed from GPX file (if present) for more accurate speed data
* All important features in the menu are now accessible via hotkeys
* Recently opened files can be accessed via hotkeys
* All dialogs can be closed using the `Esc` key
* License information can be found in the `Help` menu
* New plugin support for extending GPX Animator easily
* Delay the start of the animation (keep first frame)
* Force mandatory map attributions (if needed)
* Disable tail color fadeout on request

### Fixed bugs

* Accidentally cropping of photos
* Crazy path information with dots in filenames
* Incorrect handling of keep last frame option
* Incorrect handling of photo directory in saved configurations
* Incorrect handling of background image in saved configurations
* Fixed oblique right text alignment
* Fixed incorrect path handling when saving a configuration
* Fixed links in dialogs not opening the browser
* Fixed `NoSuchElementException` when loading empty GPX files
* Fixed a bunch of (possible) `NullPointerException`s

### Maintenance

* Improve some German translations
* Replaced the end of life [Xuggler](http://www.xuggle.com/xuggler/status) library with [JavaCV](https://github.com/bytedeco/javacv)
* Updating Java to v16
* Switching to Zulu JDK in preparation for native Apple M1 support

---

## Version 1.6.1

Release date: 2021-03-14

* Fixing date time parsing error when time zone information is missing
* Fixing date from the 1970s when forced point time interval option was set
* Fixing waypoints do not require a time anymore
* Fixing negative total time crashing the rendering process
* Accepting uppercase file endings of GPX and PNG files
* Adding trim options to command line help

---

## Version 1.6.0

Release date: 2021-01-09

* Adding multiple GPX files at once
* Adding an animation to smoothly fade photos in and out
* Providing alternative speed units (km/h, mph, min/km, min/mi, knots...)
* Adding support for moving map
* Adding support for pre-drawing a track
* Adding support to change the pre-draw color per track
* New error dialog with additional internal information for better error reports
* New and clear error message on missing track data in GPX file
* Fixing `NullPointerException` when starting GPX Animator the first time
* Fixing `NullPointerException` when showing the Changelog
* Fixing a bug causing image series export to stop working
* Migrating to Java 15
* Fixing a bunch of compiler warnings
* Adding a Motorcycle icon
* Adding support for choosing an external PNG file as a track icon
* Track icons can now be mirrored to match the general direction
* Adding font selection for the text in the animation
* Margin for track, logo, attribution and information can be set separately
* Positions of logo, attribution, and information are now configurable
* Logo, attribution, and information can now be hidden
* Adding support for background images (including transparency in PNG files)
* Adding support for track point comments in GPX files
* Fixing error in video frame size calculation with user specified bounding box
* Fixing some errors in animation length calculation when total time was set
* Fixing errors with incomplete latitude/longitude (bounding box) settings
* Fixing 21 broken background maps
* Removing 8 broken background maps
* Up to 15 % faster rendering

---

## Version 1.5.2

Release date: 2020-08-21

* Improved error messages
* Fixing a bug which prevented disabling the text in the animation.
* Fixing a bug in percentage calculator (never reached 100%)
* Fixing crazy behaviour of Latitude and Longitude spinner
* Fixing spinners not being able to go negative using the down arrow on first attempt
* Automatic repair of broken files produced by Sigma Rox 12 bicycle computer
* Show correct version number when using a saved file from an older version

---

## Version 1.5.1

Release date: 2020-08-07

* Fixing a bug that prevents photos from being shown in the animation
* Fixing a bug that does not load the photos' directory from saved files
* Fixing a bug that broke the command line use since v1.4
* Fixing a bug that shows an old status message on the progress bar

---

## Version 1.5

Release date: 2020-07-03

**Most important changes for users:**
* Show the changelog on the first start after install/update
* Adding a button to easily select common video resolutions
* Adding a bunch of new track icons
* Adding profile picture / logo to the animation
* Making video background color configurable
* Fixing UI on HiDPI (high-resolution) displays
* Fixing loading of *Keep Last Frame* configuration option
* Default output directory is no longer the application directory
* Saving a configuration as a default setting
* New application wide settings (_File > Preferences_)
* Adding preferences to set a custom default track color
* Adding preferences to configure the map tile cache
* Tile cache now enabled by default (24 hour caching)
* New installers for Windows, macOS and Linux systems
* Integration of automatic application updates using the installer
* New translation for German users (give feedback, please)
* New support e-mail address on the website
* New application icon and splash screen

**Most important changes for developers:**
* GPX-Animator now uses Gradle to build the project
* Integrating Spotbugs to search for potential bugs automatically
* Integrating PMD to search for potential bugs automatically
* Default Java version for GPX Animator is now Java 11 LTS
* Using logging instead direct console output
* Internationalizing the codebase for easier translation

---

## Version 1.4

Release date: 2019-12-20

* showing speed in animation
* adding photos to the animation
* adding coordinates to the animation
* asking before overwriting an existing output file
* adding link to the FAQ in the help menu
* adding "Open Recent File" menu
* adding new map source: OpenTopoMap
* adding optional map tile cache to reduce download size
* adding optional icons to the current track position
* allow negative time offset for GPX tracks
* UI consistency: Make all labels upper case words
* GPX-Animator now has a custom domain: https://gpx-animator.app
* fixed incorrect zoom factor calculation
* fixed time offset problem with negative time offset values
* fixed a lot of minor issues

---

## Version 1.3.1

Release date: 2018-07-31

* fixed some issues and added compatibility for Java 9+

---

## Version 1.3.0

Release date: 2015-11-22

* configurable bounding box

---

## Version 1.2.4

Release date: 2015-11-02

* fixed #18 (error saving configuration)

---

## Version 1.2.3

Release date: 2015-08-23

* fixed NPE on empty attribution
* fixed not showing marker when tail was empty or zero
* updated maps
* removed unused --debug option

---

## Version 1.2.2

Release date: 2015-01-18

* fixed NPE when adding new track
* preselect different color to newly added tracks

---

## Version 1.2.1

Release date: 2015-01-11

* handle all ISO 8601 date formats in GPX
* remember directory in file dialogs
* store relative paths in project XML file

---

## Version 1.2.0

Release date: 2014-02-03

* preparation for interactive map view configuration
* fixed bug in computing video dimensions

---

## Version 1.1.0

Release date: 2013-06-24

* configurable map attribution
* display track label in GUI tab title
* hide inactive marker after tail timeout
* added program icon
* fixed reading of alpha channel
* fixed alpha channel interpolation for tail
* fixed parsing of GPX dates with milliseconds

---

## Version 1.0.0

Release date: 2013-03-23

* added configuration GUI
* direct video rendering support
* minor rendering improvements

---

## Version 0.8

Release date: 2013-02-09

* added waypoint support

---

## Version 0.7

Release date: 2013-02-05

* added support for forced time intervals of GPS points
* configurable flashback color and duration

---

## Version 0.6

Release date: 2013-02-04

* added video dimension settings
* added track offset support (per track)
* skipping idle video frames

---

## Version 0.5

Release date: 2013-02-03

* outlining texts
* improved user experience ;-)
* fixing some indexed PNG background map tiles

---

## Version 0.4

Release date: 2013-02-03

* indicate inactive locations
* track multi-segment support
* direct color specification

---

## Version 0.3

Release date: 2013-02-03

* background map support

---

## Version 0.2

Release date: 2013-02-02

* configurable hues
* more parameters to configure
* marker labels
* multi-track support
* improved tail highlighting - now based on time
* customizable tail length

---

## Version 0.1

Release date: 2013-01-31

* initial version


================================================
FILE: LICENSE.md
================================================
Apache License
==============

_Version 2.0, January 2004_  
_&lt;<http://www.apache.org/licenses/>&gt;_

### Terms and Conditions for use, reproduction, and distribution

#### 1. Definitions

“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.

“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.

“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.

“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.

“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.

“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.

“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).

“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.

“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”

“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.

#### 2. Grant of Copyright License

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.

#### 3. Grant of Patent License

Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.

#### 4. Redistribution

You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:

* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
  this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
  changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
  all copyright, patent, trademark, and attribution notices from the Source form
  of the Work, excluding those notices that do not pertain to any part of the
  Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
  Derivative Works that You distribute must include a readable copy of the
  attribution notices contained within such NOTICE file, excluding those notices
  that do not pertain to any part of the Derivative Works, in at least one of the
  following places: within a NOTICE text file distributed as part of the
  Derivative Works; within the Source form or documentation, if provided along
  with the Derivative Works; or, within a display generated by the Derivative
  Works, if and wherever such third-party notices normally appear. The contents of
  the NOTICE file are for informational purposes only and do not modify the
  License. You may add Your own attribution notices within Derivative Works that
  You distribute, alongside or as an addendum to the NOTICE text from the Work,
  provided that such additional attribution notices cannot be construed as
  modifying the License.

You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.

#### 5. Submission of Contributions

Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.

#### 6. Trademarks

This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.

#### 7. Disclaimer of Warranty

Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.

#### 8. Limitation of Liability

In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.

#### 9. Accepting Warranty or Additional Liability

While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

_END OF TERMS AND CONDITIONS_

### APPENDIX: How to apply the Apache License to your work

To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets `[]` replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same “printed page” as the copyright notice for easier identification within
third-party archives.

    Copyright Contributors to the [name of the project] project.
    
    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.


================================================
FILE: README.md
================================================
# GPX Animator
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-38-orange.svg?style=flat-square)](#contributors)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

## Introduction

GPX Animator generates a top-down view map video from one or more GPX files generated by most standard GPS tracking devices.

GPX Animator has a graphical user interface that works on most operating systems, but works with a pure command-line interface as well.

More information and downloadable executables can be found at https://gpx-animator.app.

## Basic usage

```
# help
java -jar gpx-animator-x.y.z-all.jar --help

# create movie with default settings
java -jar gpx-animator-x.y.z-all.jar --input track.gpx
```
(where `x.y.z` refers to the version of the jar you built or downloaded)

## Advanced command line example

This example takes GPX file `input.gpx` as input, uses Google Maps as background map, makes the background non-transparent, makes the map movable by placing a 640x640 viewport over the map, forces the video to be 120000ms (2 minutes) long, makes the dot trail 10000ms (10 seconds) long, pre-draws the full track in grey (RGB color code #808080), hides the attribution overlay, and places the default information (lat/lng, speed, time) overlay at the bottom left. Output is stored in `movie.mp4`.

```bash
java -jar ./build/libs/gpx-animator-x.y.z-all.jar
	  --tms-url-template 'https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={zoom}'
	  --background-map-visibility 1.0
	  --viewport-height 640 --viewport-width 640
	  --total-time 120000
	  --tail-duration 10000
	  --pre-draw-track true
	  --pre-draw-track-color '#808080'
	  --attribution-position hidden
	  --information-position 'bottom left'
	  --input input.gpx
	  --output movie.mp4
```
(where `x.y.z` refers to the version of the jar you built or downloaded)

## Contributors

Special thanks for all these wonderful people who had helped this project so far ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
  <tbody>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/McPringle"><img src="https://avatars.githubusercontent.com/u/1254039?v=4?s=100" width="100px;" alt="Marcus Fihlon"/><br /><sub><b>Marcus Fihlon</b></sub></a><br /><a href="#projectManagement-McPringle" title="Project Management">📆</a> <a href="#ideas-McPringle" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=McPringle" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/zdila"><img src="https://avatars.githubusercontent.com/u/636095?v=4?s=100" width="100px;" alt="Martin Ždila"/><br /><sub><b>Martin Ždila</b></sub></a><br /><a href="#projectManagement-zdila" title="Project Management">📆</a> <a href="#ideas-zdila" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=zdila" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://retiredtechie.fitchfamily.org/"><img src="https://avatars.githubusercontent.com/u/4681938?v=4?s=100" width="100px;" alt="n76"/><br /><sub><b>n76</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=n76" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/markus-schmidlin"><img src="https://avatars.githubusercontent.com/u/13030829?v=4?s=100" width="100px;" alt="Markus Schmidlin"/><br /><sub><b>Markus Schmidlin</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=markus-schmidlin" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/martinfrancois"><img src="https://avatars.githubusercontent.com/u/14319020?v=4?s=100" width="100px;" alt="François Martin"/><br /><sub><b>François Martin</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=martinfrancois" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/maebli"><img src="https://avatars.githubusercontent.com/u/1138612?v=4?s=100" width="100px;" alt="Maebli"/><br /><sub><b>Maebli</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=maebli" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/rindy22"><img src="https://avatars.githubusercontent.com/u/56276884?v=4?s=100" width="100px;" alt="rindy22"/><br /><sub><b>rindy22</b></sub></a><br /><a href="#ideas-rindy22" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=rindy22" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/bat-bloke"><img src="https://avatars.githubusercontent.com/u/57795480?v=4?s=100" width="100px;" alt="Andy Oakey"/><br /><sub><b>Andy Oakey</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=bat-bloke" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/fgaignat"><img src="https://avatars.githubusercontent.com/u/23083528?v=4?s=100" width="100px;" alt="fgaignat"/><br /><sub><b>fgaignat</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=fgaignat" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/charlysog"><img src="https://avatars.githubusercontent.com/u/63605339?v=4?s=100" width="100px;" alt="charlysog"/><br /><sub><b>charlysog</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Acharlysog" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/waschulte"><img src="https://avatars.githubusercontent.com/u/59023045?v=4?s=100" width="100px;" alt="waschulte"/><br /><sub><b>waschulte</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Awaschulte" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/SirCremefresh"><img src="https://avatars.githubusercontent.com/u/20863779?v=4?s=100" width="100px;" alt="Donato Wolfisberg"/><br /><sub><b>Donato Wolfisberg</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=SirCremefresh" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/galz10"><img src="https://avatars.githubusercontent.com/u/38544478?v=4?s=100" width="100px;" alt="Gal Zahavi"/><br /><sub><b>Gal Zahavi</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=galz10" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/poorlymac"><img src="https://avatars.githubusercontent.com/u/16620846?v=4?s=100" width="100px;" alt="poorlymac"/><br /><sub><b>poorlymac</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=poorlymac" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/antonio-barber-67273bba/"><img src="https://avatars.githubusercontent.com/u/21110513?v=4?s=100" width="100px;" alt="Antonio D Barber"/><br /><sub><b>Antonio D Barber</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=abarber7" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/herrwusel"><img src="https://avatars.githubusercontent.com/u/8242787?v=4?s=100" width="100px;" alt="herrwusel"/><br /><sub><b>herrwusel</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Aherrwusel" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/rammmiro"><img src="https://avatars.githubusercontent.com/u/32325306?v=4?s=100" width="100px;" alt="Ramiro Martínez Pinilla"/><br /><sub><b>Ramiro Martínez Pinilla</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Arammmiro" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.futurewater.nl/"><img src="https://avatars.githubusercontent.com/u/12559676?v=4?s=100" width="100px;" alt="Peter Droogers"/><br /><sub><b>Peter Droogers</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Apdroogers" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/fwieringen"><img src="https://avatars.githubusercontent.com/u/4232879?v=4?s=100" width="100px;" alt="Friso van Wieringen"/><br /><sub><b>Friso van Wieringen</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Afwieringen" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://thomer.com/"><img src="https://avatars.githubusercontent.com/u/1020105?v=4?s=100" width="100px;" alt="Thomer Gil"/><br /><sub><b>Thomer Gil</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Athomergil" title="Bug reports">🐛</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=thomergil" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/mundry"><img src="https://avatars.githubusercontent.com/u/1453314?v=4?s=100" width="100px;" alt="mundry"/><br /><sub><b>mundry</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=mundry" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="http://blog.mrtrustor.net/"><img src="https://avatars.githubusercontent.com/u/2864678?v=4?s=100" width="100px;" alt="Théo Chamley"/><br /><sub><b>Théo Chamley</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=MrTrustor" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/triskaidekafeliks"><img src="https://avatars.githubusercontent.com/u/19534176?v=4?s=100" width="100px;" alt="triskaidekafeliks"/><br /><sub><b>triskaidekafeliks</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=triskaidekafeliks" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/krugerk"><img src="https://avatars.githubusercontent.com/u/4656811?v=4?s=100" width="100px;" alt="krugerk"/><br /><sub><b>krugerk</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Akrugerk" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/piiskop"><img src="https://avatars.githubusercontent.com/u/14224528?v=4?s=100" width="100px;" alt="peacecop kalmer:"/><br /><sub><b>peacecop kalmer:</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Apiiskop" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/rneppi"><img src="https://avatars.githubusercontent.com/u/28830856?v=4?s=100" width="100px;" alt="rneppi"/><br /><sub><b>rneppi</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Arneppi" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/szolnokit"><img src="https://avatars.githubusercontent.com/u/49479918?v=4?s=100" width="100px;" alt="szolnokit"/><br /><sub><b>szolnokit</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Aszolnokit" title="Bug reports">🐛</a> <a href="#infra-szolnokit" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=szolnokit" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/franzkroepfl"><img src="https://avatars.githubusercontent.com/u/6333880?v=4?s=100" width="100px;" alt="Franz Kröpfl"/><br /><sub><b>Franz Kröpfl</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Afkroepfl" title="Bug reports">🐛</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="http://rifter.org/"><img src="https://avatars.githubusercontent.com/u/27846815?v=4?s=100" width="100px;" alt="Stefan Weißwange"/><br /><sub><b>Stefan Weißwange</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Astefanweisswange" title="Bug reports">🐛</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/scordio"><img src="https://avatars.githubusercontent.com/u/26772046?v=4?s=100" width="100px;" alt="Stefano Cordio"/><br /><sub><b>Stefano Cordio</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=scordio" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Interactiondesigner"><img src="https://avatars.githubusercontent.com/u/17220369?v=4?s=100" width="100px;" alt="Interactiondesigner"/><br /><sub><b>Interactiondesigner</b></sub></a><br /><a href="#design-Interactiondesigner" title="Design">🎨</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/Melancholic"><img src="https://avatars.githubusercontent.com/u/2463361?v=4?s=100" width="100px;" alt="Andrey N."/><br /><sub><b>Andrey N.</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=Melancholic" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/ky0n"><img src="https://avatars.githubusercontent.com/u/30866028?v=4?s=100" width="100px;" alt="Hendrik"/><br /><sub><b>Hendrik</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/issues?q=author%3Aky0n" title="Bug reports">🐛</a> <a href="https://github.com/gpx-animator/gpx-animator/commits?author=ky0n" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/FadriPestalozzi"><img src="https://avatars.githubusercontent.com/u/16454272?v=4?s=100" width="100px;" alt="FadriPestalozzi"/><br /><sub><b>FadriPestalozzi</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=FadriPestalozzi" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/blacksun777"><img src="https://avatars.githubusercontent.com/u/11344657?v=4?s=100" width="100px;" alt="blacksun777"/><br /><sub><b>blacksun777</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=blacksun777" title="Code">💻</a></td>
    </tr>
    <tr>
      <td align="center" valign="top" width="14.28%"><a href="https://mastodon.social/@reinhapa"><img src="https://avatars.githubusercontent.com/u/4694567?v=4?s=100" width="100px;" alt="Patrick Reinhart"/><br /><sub><b>Patrick Reinhart</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=reinhapa" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://github.com/danielmischler"><img src="https://avatars.githubusercontent.com/u/23777?v=4?s=100" width="100px;" alt="Daniel Mischler"/><br /><sub><b>Daniel Mischler</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=danielmischler" title="Code">💻</a></td>
      <td align="center" valign="top" width="14.28%"><a href="https://bitbucket.org/onixred"><img src="https://avatars.githubusercontent.com/u/26665874?v=4?s=100" width="100px;" alt="Andrey"/><br /><sub><b>Andrey</b></sub></a><br /><a href="https://github.com/gpx-animator/gpx-animator/commits?author=onixred" title="Code">💻</a></td>
    </tr>
  </tbody>
</table>

<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

## Contributing

### Good First Issues

For your first contribution to this repository, you can take a look at the issues listed here: [Good first issue](https://github.com/gpx-animator/gpx-animator/contribute).

### Gitpod Online IDE

You can open this project in a preconfigured Gitpod online IDE based on Theia (Visual Studio Code) and edit, run, test, debug and commit directly from your browser.

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

### Slack Channel

There is a public Slack channel for GPX Animator available, which is hosted by the [Java User Group Switzerland](https://www.jug.ch/). If you are not already a member of this workspace, you can request a free invitation link with your email address (and nothing more) here: [Join Slack Workspace.](http://slack.jug.ch/)

After you have entered the Slack Workspace, join the #gpx-animator channel.

## Build

GPX Animator uses the [Gradle](https://gradle.org/) build system to build a JAR file. You do not need Gradle installed on your system. This project uses the Gradle Wrapper.

```
./gradlew assemble
# successful build puts .jar file in build/libs/
```

After a successful build, the JAR file can be found in the `build/libs/` directory.

Tests can be temporarily skipped by running

```
./gradlew assemble -x test
```

## Run

To run GPX Animator from source:

```
./gradlew run
```

To run GPX Animator from source with command line parameters:

```
./gradlew run --args="--input ./src/test/resources/gpx/bikeride.gpx --output test.mp4"
```

If necessary, the project will be (re)compiled.

## Test

To run tests in `src/test/`:

```
./gradlew test
```

## GPX Animator as Lib

if you want use GPX Animator as Lib see manual

### Gradle
1. Add the JitPack maven repository to the list of repositories: [jitpack](https://jitpack.io)

```
repositories {
	....
	maven { url 'https://jitpack.io' }
}
```
2. Add the dependency in dependencies block: 'com.github.gpx-animator:gpx-animator:{TAG}'
```
dependencies {
    ...
    implementation 'com.github.gpx-animator:gpx-animator:v1.8.2'
}

``` 

### Maven
1. Add the JitPack maven repository to the list of repositories: [jitpack](https://jitpack.io)
```xml
<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>
```
2. Add the dependency in dependencies block:
```xml
<dependency>
    <groupId>com.github.gpx-animator</groupId>
    <artifactId>gpx-animator</artifactId>
    <version>Tag</version>
</dependency>
```

see details [jitpack.io/#gpx-animator/](https://jitpack.io/#gpx-animator/gpx-animator/)   

## Related projects

- [gopro-map-sync](https://github.com/thomergil/gopro-map-sync): uses GPX Animator to synchronize a moving map video with GoPro footage.

## Credits

Icons included in application and their source:

* Airplane icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Bicycle icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Bus icon made by [monkik](https://www.flaticon.com/authors/monkik) from [flaticon](https://www.flaticon.com/).
* Car icon made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [flaticon](https://www.flaticon.com/).
* Jogging icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Riding icon made by [mynamepong](https://www.flaticon.com/authors/mynamepong) from [flaticon](https://www.flaticon.com/).
* Sailing icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Ship icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Tramway icon made by [Freepik](https://www.flaticon.com/authors/freepik) from [flaticon](https://www.flaticon.com/).
* Train icon made by [Smashicons](https://www.flaticon.com/authors/smashicons) from [flaticon](https://www.flaticon.com/).
* Trekking icon made by [monkik](https://www.flaticon.com/authors/monkik) from [flaticon](https://www.flaticon.com/).
* Motorcycle icon made by [poorlymac](https://github.com/poorlymac) using images from [ducati](https://www.ducati.com/us/en/bikes/multistrada)

Sounds included in application and their source:

* Success sound made by [nckn](https://freesound.org/people/nckn/sounds/256113/) from [freesound](https://freesound.org/)
* Error sound made by [lluiset7](https://freesound.org/people/lluiset7/sounds/141334/) from [freesound](https://freesound.org/)

Test files (GPX files and images) and their source:

* Bike ride provided by [McPringle](https://github.com/McPringle/) via [Komoot](https://www.komoot.de/tour/100558986)

To create the installers, we use a free license of [Install4J](https://www.ej-technologies.com/products/install4j/overview.html) for open-source projects.

[![Install4J multi-platform installer builder](https://www.ej-technologies.com/images/product_banners/install4j_large.png)](https://www.ej-technologies.com/products/install4j/overview.html)


================================================
FILE: build.gradle
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */

plugins {
    id 'application'
    id 'com.gradleup.shadow' version '9.4.1'
    id 'com.github.spotbugs' version '6.5.4'
    id 'pmd'
    id 'checkstyle'
    id 'java-library'
    id 'org.bytedeco.gradle-javacpp-platform' version '1.5.10'
    id 'io.freefair.lombok' version '9.5.0'
    id 'maven-publish'
}

version = '1.9.0-SNAPSHOT'
group = 'app.gpx-animator'

application {
    mainClass.set('app.gpx_animator.Main')
}

java {
// Before updating Java, check Lombok Gradle Plugin compatibility:
// https://github.com/freefair/gradle-plugins#compatibility-matrix
    sourceCompatibility = JavaVersion.VERSION_25
    targetCompatibility = JavaVersion.VERSION_25
}

repositories {
    mavenCentral()
}

configurations {
    developmentOnly
}

// We can set this on the command line, too: -PjavacppPlatform="linux-x86,linux-x86_64,macosx-x86_64,macosx-arm64,windows-x86,windows-x86_64"
ext {
    javacppPlatform = 'linux-x86,linux-x86_64,macosx-x86_64,macosx-arm64,windows-x86,windows-x86_64'
}

dependencies {
    compileOnly 'com.github.spotbugs:spotbugs-annotations:4.9.8'
    implementation 'org.jetbrains:annotations:26.1.0'
    implementation 'org.bytedeco:javacv:1.5.13'
    implementation 'org.bytedeco:ffmpeg-platform-gpl:8.0.1-1.5.13'
    implementation 'jakarta.xml.bind:jakarta.xml.bind-api:4.0.5'
    implementation 'org.glassfish.jaxb:jaxb-runtime:4.0.8'
    implementation 'javax.activation:activation:1.1.1'
    implementation 'org.slf4j:slf4j-api:2.0.17'
    implementation 'ch.qos.logback:logback-classic:1.5.32'
    implementation 'com.drewnoakes:metadata-extractor:2.20.0'
    implementation 'org.imgscalr:imgscalr-lib:4.2'
    implementation 'commons-io:commons-io:20030203.000550'
    implementation 'com.jgoodies:jgoodies-forms:1.9.0'
    implementation 'com.vladsch.flexmark:flexmark-all:0.64.8'
    implementation 'org.reflections:reflections:0.10.2'
    implementation 'org.apache.maven:maven-artifact:3.9.15'
    implementation 'org.apache.commons:commons-lang3:3.20.0'
    testCompileOnly 'com.github.spotbugs:spotbugs-annotations:4.9.8'
    testImplementation 'com.github.romankh3:image-comparison:4.4.0'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:6.0.3'
    testRuntimeOnly    'org.junit.jupiter:junit-jupiter-engine:6.0.3'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:6.0.3'
    testImplementation 'org.junit.platform:junit-platform-launcher:6.0.3'
    testRuntimeOnly    'org.junit.platform:junit-platform-engine:6.0.3'
}

test.classpath += configurations.developmentOnly
run.classpath += configurations.developmentOnly

test {
    useJUnitPlatform { }
    maxParallelForks = 4
    minHeapSize = "1G"
    maxHeapSize = "2G"
}

shadowJar {
    mergeServiceFiles()
}

spotbugs {
    excludeFilter = file("${projectDir}/config/spotbugs/exclude.xml")
}

tasks.spotbugsMain {
    reports.create("html") {
        required = true
    }
    reports.create("xml") {
        required = true
    }
}

tasks.spotbugsTest {
    reports.create("html") {
        required = true
    }
    reports.create("xml") {
        required = true
    }
}

checkstyle {
    configFile = file("${projectDir}/config/checkstyle/checkstyle.xml")
    toolVersion = "13.4.2"
}

pmd {
    toolVersion = "7.24.0"
    ruleSets = []
    ruleSetFiles = files("${projectDir}/config/pmd/pmd-rules.xml")
}

tasks.named('wrapper') {
    distributionType = Wrapper.DistributionType.ALL
}

tasks.withType(JavaCompile).configureEach {
    options.encoding = "UTF-8"
    options.compilerArgs += ["-Xlint:deprecation", "-Xlint:unchecked"]
}

tasks.register('copyFiles', Copy) {
    from(".")
    include("CHANGELOG.md", "LICENSE.md")
    into("./src/main/resources")
}

tasks.register('deleteFiles', Delete) {
    delete("./src/main/resources/CHANGELOG.md", "./src/main/resources/LICENSE.md")
}

tasks.register('writeBuildInfo', WriteProperties) {
    destinationFile = layout.buildDirectory.file('generated-resources/build-info.properties')
    property('version', project.version.toString())
}
sourceSets.main.resources.srcDir(layout.buildDirectory.dir('generated-resources'))
tasks.processResources { dependsOn 'writeBuildInfo' }
tasks.named('processResources') {
    dependsOn(writeBuildInfo)
}

publishing {
    afterEvaluate {
        components.java.withVariantsFromConfiguration(configurations.shadowRuntimeElements) {
            skip()
        }
    }
    publications {
        release(MavenPublication) {
            from components.java
        }
    }
}

processResources.dependsOn copyFiles
clean.dependsOn deleteFiles
assemble.dependsOn check


================================================
FILE: config/checkstyle/checkstyle.xml
================================================
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
        "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
        "https://checkstyle.org/dtds/configuration_1_3.dtd">

<!--

  Checkstyle configuration for the GPX Animator project.

  Checkstyle is very configurable. Be sure to read the documentation at
  https://checkstyle.org (or in your downloaded distribution).

  Most Checks are configurable, be sure to consult the documentation.

  To completely disable a check, just comment it out or delete it from the file.
  To suppress certain violations please review suppression filters.

  Finally, it is worth reading the documentation.

-->

<module name="Checker">
    <!--
        If you set the basedir property below, then all reported file
        names will be relative to the specified directory. See
        https://checkstyle.org/5.x/config.html#Checker

        <property name="basedir" value="${basedir}"/>
    -->
    <property name="severity" value="error"/>

    <property name="fileExtensions" value="java, properties, xml"/>

    <!-- Excludes all 'module-info.java' files              -->
    <!-- See https://checkstyle.org/config_filefilters.html -->
    <module name="BeforeExecutionExclusionFileFilter">
        <property name="fileNamePattern" value="module\-info\.java$"/>
    </module>

    <!-- https://checkstyle.org/config_filters.html#SuppressionFilter -->
    <module name="SuppressionFilter">
        <property name="file" value="${org.checkstyle.sun.suppressionfilter.config}"
                  default="checkstyle-suppressions.xml" />
        <property name="optional" value="true"/>
    </module>

    <!-- Checks that a package-info.java file exists for each package.     -->
    <!-- See https://checkstyle.org/config_javadoc.html#JavadocPackage -->
    <!-- <module name="JavadocPackage"/> -->

    <!-- Checks whether files end with a new line.                        -->
    <!-- See https://checkstyle.org/config_misc.html#NewlineAtEndOfFile -->
    <module name="NewlineAtEndOfFile"/>

    <!-- Checks that property files contain the same keys.         -->
    <!-- See https://checkstyle.org/config_misc.html#Translation -->
    <module name="Translation"/>

    <!-- Checks for Size Violations.                    -->
    <!-- See https://checkstyle.org/config_sizes.html -->
    <module name="FileLength"/>
    <module name="LineLength">
        <property name="fileExtensions" value="java"/>
        <property name="max" value="150"/>
    </module>

    <!-- Checks for whitespace                               -->
    <!-- See https://checkstyle.org/config_whitespace.html -->
    <module name="FileTabCharacter"/>

    <!-- Miscellaneous other checks.                   -->
    <!-- See https://checkstyle.org/config_misc.html -->
    <module name="RegexpSingleline">
        <property name="format" value="\s+$"/>
        <property name="minimum" value="0"/>
        <property name="maximum" value="0"/>
        <property name="message" value="Line has trailing spaces."/>
    </module>

    <module name="RegexpSingleline">
        <property name="format" value="System\.(out|err)\.print(ln|f){0,1}"/>
        <property name="message" value="Don't use System.out or System.err directly, use loggers instead."/>
    </module>

    <!-- Checks for Headers                                -->
    <!-- See https://checkstyle.org/config_header.html   -->
    <!-- <module name="Header"> -->
    <!--   <property name="headerFile" value="${checkstyle.header.file}"/> -->
    <!--   <property name="fileExtensions" value="java"/> -->
    <!-- </module> -->

    <module name="SuppressWarningsFilter"/>

    <module name="TreeWalker">
        <module name="SuppressWarnings"/>
        <module name="SuppressWarningsHolder"/>

        <!-- Checks for Javadoc comments.                     -->
        <!-- See https://checkstyle.org/config_javadoc.html -->
        <module name="InvalidJavadocPosition"/>
        <!-- <module name="JavadocMethod"/> -->
        <!-- <module name="JavadocType"/> -->
        <!-- <module name="JavadocVariable"/> -->
        <module name="JavadocStyle"/>
        <!-- <module name="MissingJavadocMethod"/> -->

        <!-- Checks for Naming Conventions.                  -->
        <!-- See https://checkstyle.org/config_naming.html -->
        <module name="ConstantName"/>
        <module name="LocalFinalVariableName"/>
        <module name="LocalVariableName"/>
        <module name="MemberName"/>
        <module name="MethodName"/>
        <module name="PackageName"/>
        <module name="ParameterName"/>
        <module name="StaticVariableName"/>
        <module name="TypeName"/>

        <!-- Checks for imports                              -->
        <!-- See https://checkstyle.org/config_import.html -->
        <module name="AvoidStarImport"/>
        <module name="IllegalImport"/> <!-- defaults to sun.* packages -->
        <module name="RedundantImport"/>
        <module name="UnusedImports">
            <property name="processJavadoc" value="false"/>
        </module>

        <!-- Checks for Size Violations.                    -->
        <!-- See https://checkstyle.org/config_sizes.html -->
        <module name="MethodLength"/>
        <module name="ParameterNumber"/>

        <!-- Checks for whitespace                               -->
        <!-- See https://checkstyle.org/config_whitespace.html -->
        <module name="EmptyForIteratorPad"/>
        <module name="GenericWhitespace"/>
        <module name="MethodParamPad"/>
        <module name="NoWhitespaceAfter"/>
        <module name="NoWhitespaceBefore"/>
        <module name="OperatorWrap"/>
        <module name="ParenPad"/>
        <module name="TypecastParenPad"/>
        <module name="WhitespaceAfter"/>
        <module name="WhitespaceAround"/>

        <!-- Modifier Checks                                    -->
        <!-- See https://checkstyle.org/config_modifiers.html -->
        <module name="ModifierOrder"/>
        <module name="RedundantModifier"/>

        <!-- Checks for blocks. You know, those {}'s         -->
        <!-- See https://checkstyle.org/config_blocks.html -->
        <module name="AvoidNestedBlocks"/>
        <module name="EmptyBlock"/>
        <module name="LeftCurly"/>
        <module name="NeedBraces"/>
        <module name="RightCurly"/>

        <!-- Checks for common coding problems               -->
        <!-- See https://checkstyle.org/config_coding.html -->
        <module name="EmptyStatement"/>
        <module name="EqualsHashCode"/>
        <module name="HiddenField">
            <property name="ignoreConstructorParameter" value="true"/>
            <property name="ignoreSetter" value="true"/>
        </module>
        <module name="IllegalInstantiation"/>
        <module name="InnerAssignment"/>
        <!-- <module name="MagicNumber"/> -->
        <module name="MissingSwitchDefault"/>
        <module name="MultipleVariableDeclarations"/>
        <module name="SimplifyBooleanExpression"/>
        <module name="SimplifyBooleanReturn"/>

        <!-- Checks for class design                         -->
        <!-- See https://checkstyle.org/config_design.html -->
        <module name="DesignForExtension"/>
        <module name="FinalClass"/>
        <module name="HideUtilityClassConstructor"/>
        <module name="InterfaceIsType"/>
        <module name="VisibilityModifier"/>

        <!-- Miscellaneous other checks.                   -->
        <!-- See https://checkstyle.org/config_misc.html -->
        <module name="ArrayTypeStyle"/>
        <module name="FinalParameters"/>
        <module name="TodoComment"/>
        <module name="UpperEll"/>

        <!-- https://checkstyle.org/config_filters.html#SuppressionXpathFilter -->
        <module name="SuppressionXpathFilter">
            <property name="file" value="${org.checkstyle.sun.suppressionxpathfilter.config}"
                      default="checkstyle-xpath-suppressions.xml" />
            <property name="optional" value="true"/>
        </module>

    </module>

</module>


================================================
FILE: config/pmd/pmd-rules.xml
================================================
<?xml version="1.0"?>
<ruleset name="Custom Rules"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">

    <description>Project specific PMD Ruleset</description>

    <rule ref="category/java/errorprone.xml">
        <exclude name="NonSerializableClass" />
    </rule>
    <rule name="ProhibitedNonNullAnnotations"
          language="java"
          message="Avoid using these non-null annotations, use 'org.jetbrains.annotations.NotNull' instead."
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
        <description>
            Avoid using these non-null annotations, use 'org.jetbrains.annotations.NotNull' or 'lombok.NonNull' instead.
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
                    <![CDATA[
//Name[pmd-java:typeIs('javax.annotation.Nonnull')] |
//Name[pmd-java:typeIs('org.springframework.lang.NonNull')] |
//Name[pmd-java:typeIs('org.jspecify.annotations.NonNull')] |
//Name[pmd-java:typeIs('org.eclipse.jdt.annotation.NonNull')] |
//Name[pmd-java:typeIs('org.checkerframework.checker.nullness.qual.NonNull')] |
//Name[pmd-java:typeIs('com.drew.lang.annotations.NotNull')] |
//Name[pmd-java:typeIs('com.sun.istack.NotNull')]
]]>
                </value>
            </property>
        </properties>
    </rule>
    <rule name="ProhibitedNullableAnnotations"
          language="java"
          message="Avoid using these nullable annotations, use 'org.jetbrains.annotations.Nullable' instead."
          class="net.sourceforge.pmd.lang.rule.xpath.XPathRule">
        <description>
            Avoid using these nullable annotations, use 'org.jetbrains.annotations.Nullable' instead.
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
                    <![CDATA[
//Name[pmd-java:typeIs('javax.annotation.Nullable')] |
//Name[pmd-java:typeIs('org.springframework.lang.Nullable')] |
//Name[pmd-java:typeIs('org.jspecify.annotations.Nullable')] |
//Name[pmd-java:typeIs('org.eclipse.jdt.annotation.Nullable')] |
//Name[pmd-java:typeIs('org.checkerframework.checker.nullness.qual.Nullable')] |
//Name[pmd-java:typeIs('com.drew.lang.annotations.Nullable')] |
//Name[pmd-java:typeIs('com.sun.istack.Nullable')]
]]>
                </value>
            </property>
        </properties>
    </rule>
</ruleset>


================================================
FILE: config/spotbugs/exclude.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
  <Match>
    <!-- Check is broken and does not clearly report where the fault is. -->
    <Bug pattern="CT_CONSTRUCTOR_THROW, PI_DO_NOT_REUSE_PUBLIC_IDENTIFIERS_CLASS_NAMES" />
  </Match>
</FindBugsFilter>


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-all.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================
org.gradle.configuration-cache=true


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

#
# Copyright © 2015 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.
#
# SPDX-License-Identifier: Apache-2.0
#

##############################################################################
#
#   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/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/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

# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit

# 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



# 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
    if ! command -v java >/dev/null 2>&1
    then
        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
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
    case $MAX_FD in #(
      max*)
        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        MAX_FD=$( ulimit -H -n ) ||
            warn "Could not query maximum file descriptor limit"
    esac
    case $MAX_FD in  #(
      '' | soft) :;; #(
      *)
        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
        # shellcheck disable=SC2039,SC3045
        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" )

    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


# 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"'

# Collect all arguments for the java command:
#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
#     and any embedded shellness will be escaped.
#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
#     treated as '${Hostname}' itself on the command line.

set -- \
        "-Dorg.gradle.appname=$APP_BASE_NAME" \
        -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
        "$@"

# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
    die "xargs is not available"
fi

# 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
@rem SPDX-License-Identifier: Apache-2.0
@rem

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

@rem Set local scope for the variables, and ensure extensions are enabled
setlocal EnableExtensions

set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
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% equ 0 goto execute

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

"%COMSPEC%" /c exit 1

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

if exist "%JAVA_EXE%" goto execute

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

"%COMSPEC%" /c exit 1

:execute
@rem Setup the command line



@rem Execute Gradle
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
@rem which allows us to clear the local environment before executing the java command
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel

:exitWithErrorLevel
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
"%COMSPEC%" /c exit %ERRORLEVEL%


================================================
FILE: install/gpx-animator.install4j
================================================
<?xml version="1.0" encoding="UTF-8"?>
<install4j version="12.0" transformSequenceNumber="12">
  <directoryPresets config="../src/main/resources" />
  <application name="GPX Animator" applicationId="4628-8280-7282-2798" mediaDir="media" compression="9" lzmaCompression="true" shortName="gpx-animator" publisher="Marcus Fihlon" publisherWeb="https://gpx-animator.app" version="1.8.1" allPathsRelative="true" backupOnSave="true" macVolumeId="ad5267b5253dce6a" javaMinVersion="17" javaMaxVersion="17">
    <jreBundles jdkProviderId="Adoptium" release="25/jdk-25.0.1+8" />
  </application>
  <files keepModificationTimes="true" missingFilesStrategy="error">
    <mountPoints>
      <mountPoint id="58" />
    </mountPoints>
    <entries>
      <fileEntry mountPoint="58" file="../build/libs/gpx-animator-1.8.1-all.jar" />
    </entries>
  </files>
  <launchers>
    <launcher name="${compiler:sys.shortName}" id="59" menuName="GPX Animator" checkUpdater="true">
      <executable name="${compiler:sys.shortName}" iconSet="true" executableMode="gui" changeWorkingDirectory="false" />
      <splashScreen show="true" bitmapFile="../src/main/resources/splash.png" />
      <java mainClass="app.gpx_animator.Main">
        <classPath>
          <archive location="gpx-animator-1.8.1-all.jar" />
        </classPath>
      </java>
      <iconImageFiles>
        <file path="../src/main/resources/icon_16.png" />
        <file path="../src/main/resources/icon_32.png" />
        <file path="../src/main/resources/icon_48.png" />
        <file path="../src/main/resources/icon_128.png" />
      </iconImageFiles>
    </launcher>
  </launchers>
  <installerGui autoUpdateDescriptorUrl="https://download.gpx-animator.app/updates.xml">
    <applications>
      <application id="installer" beanClass="com.install4j.runtime.beans.applications.InstallerApplication">
        <serializedBean>
          <property name="frameHeight" type="int" value="600" />
          <property name="frameWidth" type="int" value="800" />
        </serializedBean>
        <startup>
          <screen id="1" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0">
            <actions>
              <action id="22" beanClass="com.install4j.runtime.beans.actions.misc.RequestPrivilegesAction" actionElevationType="none" rollbackBarrierExitCode="0" />
              <action id="247" beanClass="com.install4j.runtime.beans.actions.control.SetInstallationDirectoryAction" actionElevationType="none" />
            </actions>
          </screen>
        </startup>
        <screens>
          <screen id="2" beanClass="com.install4j.runtime.beans.screens.WelcomeScreen" styleId="41" rollbackBarrierExitCode="0">
            <actions>
              <action id="7" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" multiExec="true">
                <serializedBean>
                  <property name="excludedVariables" type="array" elementType="string" length="1">
                    <element index="0">sys.installationDir</element>
                  </property>
                </serializedBean>
                <condition>context.getBooleanVariable("sys.streamlinedInstallation")</condition>
              </action>
            </actions>
            <formComponents>
              <formComponent id="3" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
                <serializedBean>
                  <property name="labelText" type="string">${form:welcomeMessage}</property>
                </serializedBean>
                <visibilityScript>!context.isConsole()</visibilityScript>
              </formComponent>
              <formComponent id="4" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
                <serializedBean>
                  <property name="consoleScript">
                    <object class="com.install4j.api.beans.ScriptProperty">
                      <property name="value" type="string">String message = context.getMessage("ConsoleWelcomeLabel", context.getApplicationName());
return console.askOkCancel(message, true);
</property>
                    </object>
                  </property>
                </serializedBean>
              </formComponent>
              <formComponent id="5" beanClass="com.install4j.runtime.beans.formcomponents.StreamlinedInstallationChooserComponent" useExternalParametrization="true" externalParametrizationName="Update Alert" externalParametrizationMode="include">
                <serializedBean>
                  <property name="streamlinedInstallationStrategy" type="enum" class="com.install4j.runtime.beans.formcomponents.StreamlinedInstallationStrategy" value="UPDATE_ONLY" />
                </serializedBean>
                <externalParametrizationPropertyNames>
                  <propertyName>streamlinedInstallationStrategy</propertyName>
                </externalParametrizationPropertyNames>
              </formComponent>
              <formComponent id="6" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetTop="20">
                <serializedBean>
                  <property name="labelText" type="string">${i18n:ClickNext}</property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="8" beanClass="com.install4j.runtime.beans.screens.InstallationDirectoryScreen" rollbackBarrierExitCode="0">
            <condition>!context.getBooleanVariable("sys.streamlinedInstallation")</condition>
            <actions>
              <action id="11" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" multiExec="true">
                <serializedBean>
                  <property name="excludedVariables" type="array" elementType="string" length="1">
                    <element index="0">sys.installationDir</element>
                  </property>
                </serializedBean>
                <condition>context.getVariable("sys.responseFile") == null</condition>
              </action>
            </actions>
            <formComponents>
              <formComponent id="9" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="25">
                <serializedBean>
                  <property name="labelText" type="string">${i18n:SelectDirLabel(${compiler:sys.fullName})}</property>
                </serializedBean>
              </formComponent>
              <formComponent id="10" beanClass="com.install4j.runtime.beans.formcomponents.InstallationDirectoryChooserComponent" useExternalParametrization="true" externalParametrizationName="Installation Directory Chooser" externalParametrizationMode="include">
                <serializedBean>
                  <property name="requestFocus" type="boolean" value="true" />
                </serializedBean>
                <externalParametrizationPropertyNames>
                  <propertyName>suggestAppDir</propertyName>
                  <propertyName>validateApplicationId</propertyName>
                  <propertyName>existingDirWarning</propertyName>
                  <propertyName>checkWritable</propertyName>
                  <propertyName>manualEntryAllowed</propertyName>
                  <propertyName>checkFreeSpace</propertyName>
                  <propertyName>showRequiredDiskSpace</propertyName>
                  <propertyName>showFreeDiskSpace</propertyName>
                  <propertyName>allowSpacesOnUnix</propertyName>
                  <propertyName>validationScript</propertyName>
                  <propertyName>standardValidation</propertyName>
                </externalParametrizationPropertyNames>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="12" beanClass="com.install4j.runtime.beans.screens.ComponentsScreen" rollbackBarrierExitCode="0">
            <formComponents>
              <formComponent id="13" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent">
                <serializedBean>
                  <property name="labelText" type="string">${i18n:SelectComponentsLabel2}</property>
                </serializedBean>
                <visibilityScript>!context.isConsole()</visibilityScript>
              </formComponent>
              <formComponent id="14" beanClass="com.install4j.runtime.beans.formcomponents.ComponentSelectorComponent" useExternalParametrization="true" externalParametrizationName="Installation Components" externalParametrizationMode="include">
                <serializedBean>
                  <property name="fillVertical" type="boolean" value="true" />
                </serializedBean>
                <externalParametrizationPropertyNames>
                  <propertyName>selectionChangedScript</propertyName>
                </externalParametrizationPropertyNames>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="15" beanClass="com.install4j.runtime.beans.screens.InstallationScreen" rollbackBarrier="true" rollbackBarrierExitCode="0">
            <actions>
              <action id="17" beanClass="com.install4j.runtime.beans.actions.InstallFilesAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit" errorMessage="${i18n:FileCorrupted}" />
              <action id="18" beanClass="com.install4j.runtime.beans.actions.desktop.CreateDefaultStartMenuEntriesAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                <serializedBean>
                  <property name="folderName" type="string">${installer:sys.programGroupName}</property>
                  <property name="linkDirectory" type="string">${installer:sys.symlinkDir}</property>
                </serializedBean>
                <condition>!context.getBooleanVariable("sys.programGroupDisabled")</condition>
              </action>
              <action id="19" beanClass="com.install4j.runtime.beans.actions.desktop.RegisterAddRemoveAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                <serializedBean>
                  <property name="itemName" type="string">${compiler:sys.fullName} ${compiler:sys.version}</property>
                </serializedBean>
              </action>
            </actions>
            <formComponents>
              <formComponent id="16" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent">
                <serializedBean>
                  <property name="initialStatusMessage" type="string">${i18n:WizardPreparing}</property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="20" beanClass="com.install4j.runtime.beans.screens.FinishedScreen" styleId="41" rollbackBarrierExitCode="0" finishScreen="true">
            <formComponents>
              <formComponent id="21" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
                <serializedBean>
                  <property name="labelText" type="string">${form:finishedMessage}</property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
        </screens>
      </application>
      <application id="uninstaller" beanClass="com.install4j.runtime.beans.applications.UninstallerApplication">
        <serializedBean>
          <property name="customMacosExecutableName" type="string">${i18n:UninstallerMenuEntry(${compiler:sys.fullName})}</property>
          <property name="useCustomMacosExecutableName" type="boolean" value="true" />
        </serializedBean>
        <startup>
          <screen id="23" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0">
            <actions>
              <action id="33" beanClass="com.install4j.runtime.beans.actions.misc.LoadResponseFileAction" rollbackBarrierExitCode="0" />
              <action id="34" beanClass="com.install4j.runtime.beans.actions.misc.RequireInstallerPrivilegesAction" actionElevationType="none" rollbackBarrierExitCode="0" />
            </actions>
          </screen>
        </startup>
        <screens>
          <screen id="24" beanClass="com.install4j.runtime.beans.screens.UninstallWelcomeScreen" styleId="41" rollbackBarrierExitCode="0">
            <formComponents>
              <formComponent id="25" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
                <serializedBean>
                  <property name="labelText" type="string">${form:welcomeMessage}</property>
                </serializedBean>
                <visibilityScript>!context.isConsole()</visibilityScript>
              </formComponent>
              <formComponent id="26" beanClass="com.install4j.runtime.beans.formcomponents.ConsoleHandlerFormComponent">
                <serializedBean>
                  <property name="consoleScript">
                    <object class="com.install4j.api.beans.ScriptProperty">
                      <property name="value" type="string">String message = context.getMessage("ConfirmUninstall", context.getApplicationName());
return console.askYesNo(message, true);
</property>
                    </object>
                  </property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="27" beanClass="com.install4j.runtime.beans.screens.UninstallationScreen" rollbackBarrierExitCode="0">
            <actions>
              <action id="29" beanClass="com.install4j.runtime.beans.actions.UninstallFilesAction" actionElevationType="elevated" rollbackBarrierExitCode="0" />
            </actions>
            <formComponents>
              <formComponent id="28" beanClass="com.install4j.runtime.beans.formcomponents.ProgressComponent">
                <serializedBean>
                  <property name="initialStatusMessage" type="string">${i18n:UninstallerPreparing}</property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
          <screen id="32" beanClass="com.install4j.runtime.beans.screens.UninstallFailureScreen" rollbackBarrierExitCode="0" finishScreen="true" />
          <screen id="30" beanClass="com.install4j.runtime.beans.screens.UninstallSuccessScreen" styleId="41" rollbackBarrierExitCode="0" finishScreen="true">
            <formComponents>
              <formComponent id="31" beanClass="com.install4j.runtime.beans.formcomponents.MultilineLabelComponent" insetBottom="10">
                <serializedBean>
                  <property name="labelText" type="string">${form:successMessage}</property>
                </serializedBean>
              </formComponent>
            </formComponents>
          </screen>
        </screens>
      </application>
      <application name="Background update downloader" id="160" beanClass="com.install4j.runtime.beans.applications.CustomApplication" automaticLauncherIntegration="true" launchSchedule="always">
        <serializedBean>
          <property name="customIconImageFiles">
            <add>
              <object class="com.install4j.api.beans.ExternalFile">
                <string>${compiler:sys.install4jHome}/resource/updater_16.png</string>
              </object>
            </add>
            <add>
              <object class="com.install4j.api.beans.ExternalFile">
                <string>${compiler:sys.install4jHome}/resource/updater_32.png</string>
              </object>
            </add>
            <add>
              <object class="com.install4j.api.beans.ExternalFile">
                <string>${compiler:sys.install4jHome}/resource/updater_48.png</string>
              </object>
            </add>
            <add>
              <object class="com.install4j.api.beans.ExternalFile">
                <string>${compiler:sys.install4jHome}/resource/updater_128.png</string>
              </object>
            </add>
            <add>
              <object class="com.install4j.api.beans.ExternalFile">
                <string>${compiler:sys.install4jHome}/resource/updater_256.png</string>
              </object>
            </add>
          </property>
          <property name="executableName" type="string">gpx-animator-updater</property>
          <property name="frameHeight" type="int" value="480" />
          <property name="frameWidth" type="int" value="640" />
          <property name="useCustomIcon" type="boolean" value="true" />
          <property name="vmParameters" type="string">-Dapple.awt.UIElement=true</property>
          <property name="windowTitle" type="string">${compiler:sys.fullName}</property>
        </serializedBean>
        <startup>
          <screen id="161" beanClass="com.install4j.runtime.beans.screens.StartupScreen" rollbackBarrierExitCode="0">
            <actions>
              <action name="Check prerequsites" id="162" beanClass="com.install4j.runtime.beans.actions.control.RunScriptAction" rollbackBarrierExitCode="0" failureStrategy="quit">
                <serializedBean>
                  <property name="script">
                    <object class="com.install4j.api.beans.ScriptProperty">
                      <property name="value" type="string">import java.nio.file.*;

Path dir = context.getInstallationDirectory().toPath();
// quit if the current installation is on a read only file system, for example a disk image on macOS
// or if the directory is not writeable on Linux/Unix. 
// If there is no  "Request privileges" action in the installer, the condition should be
// simply Files.isWritable(dir); 
return !Files.getFileStore(dir).isReadOnly() &amp;&amp; (Util.isWindows() || Util.isMacOS() || Files.isWritable(dir));
</property>
                    </object>
                  </property>
                </serializedBean>
              </action>
              <action id="163" beanClass="com.install4j.runtime.beans.actions.update.CheckForUpdateAction" actionElevationType="none" failureStrategy="quit">
                <serializedBean>
                  <property name="url" type="string">${installer:updatesUrl?:${compiler:sys.updatesUrl}}</property>
                  <property name="variable" type="string">updateDescriptor</property>
                </serializedBean>
              </action>
              <action name="Update descriptor entry" id="164" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction" failureStrategy="quit">
                <serializedBean>
                  <property name="failIfNull" type="boolean" value="true" />
                  <property name="script">
                    <object class="com.install4j.api.beans.ScriptProperty">
                      <property name="value" type="string">UpdateDescriptorEntry entry = ((UpdateDescriptor)context.getVariable("updateDescriptor")).getPossibleUpdateEntry();

if (entry == null) {
    return null;
} else if (entry.isArchive() &amp;&amp; !entry.isSingleBundle()) {
    // only installers and single bundle archives on macOS are supported
    return null;
} else if (entry.isDownloaded()) {
    // update has been downloaded already
    return null;
} else {
    return entry;
}</property>
                    </object>
                  </property>
                  <property name="variableName" type="string">updateDescriptorEntry</property>
                </serializedBean>
              </action>
              <group name="Update available" id="165" beanClass="com.install4j.runtime.beans.groups.ActionGroup">
                <serializedBean>
                  <property name="conditionExpression">
                    <object class="com.install4j.api.beans.ScriptProperty">
                      <property name="value" type="string">context.getVariable("updateDescriptorEntry") != null</property>
                    </object>
                  </property>
                </serializedBean>
                <beans>
                  <action name="New version" id="166" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction">
                    <serializedBean>
                      <property name="script">
                        <object class="com.install4j.api.beans.ScriptProperty">
                          <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getNewVersion()</property>
                        </object>
                      </property>
                      <property name="variableName" type="string">updaterNewVersion</property>
                    </serializedBean>
                  </action>
                  <action name="Download URL" id="167" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction">
                    <serializedBean>
                      <property name="script">
                        <object class="com.install4j.api.beans.ScriptProperty">
                          <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getURL().toExternalForm()</property>
                        </object>
                      </property>
                      <property name="variableName" type="string">updaterDownloadUrl</property>
                    </serializedBean>
                  </action>
                  <action name="Download location" id="168" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction">
                    <serializedBean>
                      <property name="script">
                        <object class="com.install4j.api.beans.ScriptProperty">
                          <property name="value" type="string">context.getVariable("sys.updateStorageDir") + File.separator + ((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).getFileName()</property>
                        </object>
                      </property>
                      <property name="variableName" type="string">updaterDownloadFile</property>
                    </serializedBean>
                  </action>
                  <action id="169" beanClass="com.install4j.runtime.beans.actions.net.DownloadFileAction" failureStrategy="quit">
                    <serializedBean>
                      <property name="targetFile">
                        <object class="java.io.File">
                          <string>${installer:updaterDownloadFile}</string>
                        </object>
                      </property>
                      <property name="url" type="string">${installer:updaterDownloadUrl}</property>
                    </serializedBean>
                  </action>
                  <group name="Installer" id="170" beanClass="com.install4j.runtime.beans.groups.ActionGroup">
                    <serializedBean>
                      <property name="conditionExpression">
                        <object class="com.install4j.api.beans.ScriptProperty">
                          <property name="value" type="string">!((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive()</property>
                        </object>
                      </property>
                    </serializedBean>
                    <beans>
                      <action id="171" beanClass="com.install4j.runtime.beans.actions.files.SetModeAction" actionElevationType="elevated">
                        <serializedBean>
                          <property name="files" type="array" class="java.io.File" length="1">
                            <element index="0">
                              <object class="java.io.File">
                                <string>${installer:updaterDownloadFile}</string>
                              </object>
                            </element>
                          </property>
                          <property name="mode" type="string">755</property>
                        </serializedBean>
                      </action>
                      <action id="172" beanClass="com.install4j.runtime.beans.actions.update.ScheduleUpdateAction" actionElevationType="none" failureStrategy="quit">
                        <serializedBean>
                          <property name="installerFile">
                            <object class="java.io.File">
                              <string>${installer:updaterDownloadFile}</string>
                            </object>
                          </property>
                          <property name="version" type="string">${installer:updaterNewVersion}</property>
                        </serializedBean>
                      </action>
                    </beans>
                  </group>
                  <group name="Single Bundle Archive" id="173" beanClass="com.install4j.runtime.beans.groups.ActionGroup">
                    <serializedBean>
                      <property name="conditionExpression">
                        <object class="com.install4j.api.beans.ScriptProperty">
                          <property name="value" type="string">((UpdateDescriptorEntry)context.getVariable("updateDescriptorEntry")).isArchive()</property>
                        </object>
                      </property>
                    </serializedBean>
                    <beans>
                      <action name="Staging Directory" id="174" beanClass="com.install4j.runtime.beans.actions.control.SetVariableAction">
                        <serializedBean>
                          <property name="script">
                            <object class="com.install4j.api.beans.ScriptProperty">
                              <property name="value" type="string">String dirName = context.getVariable("updaterDownloadFile") + "_dir";
new File(dirName).mkdirs();
return dirName;</property>
                            </object>
                          </property>
                          <property name="variableName" type="string">updaterStagingDir</property>
                        </serializedBean>
                      </action>
                      <action name="Delete Staging Directory" id="175" beanClass="com.install4j.runtime.beans.actions.files.DeleteFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                        <serializedBean>
                          <property name="backupForRollback" type="boolean" value="false" />
                          <property name="files" type="array" class="java.io.File" length="1">
                            <element index="0">
                              <object class="java.io.File">
                                <string>${installer:updaterStagingDir}</string>
                              </object>
                            </element>
                          </property>
                          <property name="recursive" type="boolean" value="true" />
                        </serializedBean>
                        <condition>new File((String)context.getVariable("updaterStagingDir")).exists()</condition>
                      </action>
                      <action id="176" beanClass="com.install4j.runtime.beans.actions.files.ExtractDmgFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit">
                        <serializedBean>
                          <property name="archiveFile">
                            <object class="java.io.File">
                              <string>${installer:updaterDownloadFile}</string>
                            </object>
                          </property>
                          <property name="destinationDirectory">
                            <object class="java.io.File">
                              <string>${installer:updaterStagingDir}</string>
                            </object>
                          </property>
                          <property name="fileFilter">
                            <object class="com.install4j.api.beans.ScriptProperty">
                              <property name="value" type="string">// only extract app bundle, no other top level files

import com.install4j.api.unix.UnixFileSystem;

File realFile = new File(dmgMountPoint, file.getPath());

return file.getParent() != null || (file.getName().endsWith(".app") &amp;&amp; realFile.isDirectory() &amp;&amp; !UnixFileSystem.getFileInformation(realFile).isLink());</property>
                            </object>
                          </property>
                        </serializedBean>
                        <condition>((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")</condition>
                      </action>
                      <action id="177" beanClass="com.install4j.runtime.beans.actions.files.ExtractTarFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0" failureStrategy="quit">
                        <serializedBean>
                          <property name="archiveFile">
                            <object class="java.io.File">
                              <string>${installer:updaterDownloadFile}</string>
                            </object>
                          </property>
                          <property name="destinationDirectory">
                            <object class="java.io.File">
                              <string>${installer:updaterStagingDir}</string>
                            </object>
                          </property>
                          <property name="fileFilter">
                            <object class="com.install4j.api.beans.ScriptProperty">
                              <property name="value" type="string">// only extract app bundle, no other top level files
file.getParent() != null || (file.getName().endsWith(".app") &amp;&amp; directory)</property>
                            </object>
                          </property>
                        </serializedBean>
                        <condition>!((String)context.getVariable("updaterDownloadFile")).endsWith(".dmg")</condition>
                      </action>
                      <action id="178" beanClass="com.install4j.runtime.beans.actions.update.ScheduleUpdateAction" actionElevationType="none" failureStrategy="quit">
                        <serializedBean>
                          <property name="installerFile">
                            <object class="java.io.File">
                              <string>${installer:updaterStagingDir}</string>
                            </object>
                          </property>
                          <property name="version" type="string">${installer:updaterNewVersion}</property>
                        </serializedBean>
                      </action>
                      <action name="Delete archive" id="179" beanClass="com.install4j.runtime.beans.actions.files.DeleteFileAction" actionElevationType="elevated" rollbackBarrierExitCode="0">
                        <serializedBean>
                          <property name="backupForRollback" type="boolean" value="false" />
                          <property name="files" type="array" class="java.io.File" length="1">
                            <element index="0">
                              <object class="java.io.File">
                                <string>${installer:updaterDownloadFile}</string>
                              </object>
                            </element>
                          </property>
                        </serializedBean>
                      </action>
                    </beans>
                  </group>
                </beans>
              </group>
            </actions>
          </screen>
        </startup>
      </application>
    </applications>
    <styles defaultStyleId="35">
      <style name="Standard" id="35" beanClass="com.install4j.runtime.beans.styles.FormStyle">
        <formComponents>
          <formComponent name="Header" id="36" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetTop="0" insetBottom="0">
            <serializedBean>
              <property name="styleId" type="string">48</property>
            </serializedBean>
          </formComponent>
          <group name="Main" id="37" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup">
            <beans>
              <formComponent id="38" beanClass="com.install4j.runtime.beans.styles.ContentComponent" insetTop="10" insetLeft="20" insetBottom="10" insetRight="20" />
              <formComponent name="Watermark" id="39" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" insetTop="0" insetLeft="5" insetBottom="0" useExternalParametrization="true" externalParametrizationName="Custom watermark" externalParametrizationMode="include">
                <serializedBean>
                  <property name="enabledTitleText" type="boolean" value="false" />
                  <property name="labelText" type="string">install4j</property>
                </serializedBean>
                <externalParametrizationPropertyNames>
                  <propertyName>labelText</propertyName>
                </externalParametrizationPropertyNames>
              </formComponent>
              <formComponent name="Footer" id="40" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetTop="0" insetBottom="0">
                <serializedBean>
                  <property name="styleId" type="string">52</property>
                </serializedBean>
              </formComponent>
            </beans>
          </group>
        </formComponents>
      </style>
      <style name="Banner" id="41" beanClass="com.install4j.runtime.beans.styles.FormStyle">
        <formComponents>
          <group id="42" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" useExternalParametrization="true" externalParametrizationName="Customize banner image" externalParametrizationMode="include">
            <serializedBean>
              <property name="backgroundColor">
                <object class="com.install4j.runtime.beans.LightOrDarkColor">
                  <object class="java.awt.Color">
                    <int>255</int>
                    <int>255</int>
                    <int>255</int>
                    <int>255</int>
                  </object>
                  <object class="java.awt.Color">
                    <int>49</int>
                    <int>52</int>
                    <int>53</int>
                    <int>255</int>
                  </object>
                </object>
              </property>
              <property name="borderSides">
                <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
                  <property name="bottom" type="boolean" value="true" />
                </object>
              </property>
              <property name="imageEdgeBackgroundColor">
                <object class="com.install4j.runtime.beans.LightOrDarkColor">
                  <object class="java.awt.Color">
                    <int>27</int>
                    <int>143</int>
                    <int>220</int>
                    <int>255</int>
                  </object>
                  <object class="java.awt.Color">
                    <int>0</int>
                    <int>73</int>
                    <int>150</int>
                    <int>255</int>
                  </object>
                </object>
              </property>
              <property name="imageFile">
                <object class="com.install4j.api.beans.ExternalFile">
                  <string>${compiler:sys.install4jHome}/resource/styles/wizard.png</string>
                </object>
              </property>
              <property name="insets">
                <object class="java.awt.Insets">
                  <int>5</int>
                  <int>10</int>
                  <int>10</int>
                  <int>10</int>
                </object>
              </property>
            </serializedBean>
            <beans>
              <formComponent id="43" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" insetTop="0">
                <serializedBean>
                  <property name="labelWidgetStyle" id="LabelWidgetStyle0">
                    <property name="fontDescriptor">
                      <property name="fontSizePercent" type="int" value="130" />
                      <property name="fontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" />
                      <property name="fontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" />
                    </property>
                  </property>
                  <property name="labelWidgetStyleId" type="null" />
                </serializedBean>
              </formComponent>
              <formComponent id="44" beanClass="com.install4j.runtime.beans.formcomponents.SeparatorComponent" />
              <formComponent id="45" beanClass="com.install4j.runtime.beans.styles.ContentComponent" insetTop="10" insetBottom="0" />
            </beans>
            <externalParametrizationPropertyNames>
              <propertyName>imageAnchor</propertyName>
              <propertyName>imageEdgeBackgroundColor</propertyName>
              <propertyName>imageFile</propertyName>
            </externalParametrizationPropertyNames>
          </group>
          <formComponent id="46" beanClass="com.install4j.runtime.beans.styles.NestedStyleComponent" insetBottom="0">
            <serializedBean>
              <property name="styleId" type="string">52</property>
            </serializedBean>
          </formComponent>
        </formComponents>
      </style>
      <group name="Style components" id="47" beanClass="com.install4j.runtime.beans.groups.StyleGroup">
        <beans>
          <style name="Standard header" id="48" beanClass="com.install4j.runtime.beans.styles.FormStyle">
            <serializedBean>
              <property name="fillVertical" type="boolean" value="false" />
              <property name="standalone" type="boolean" value="false" />
              <property name="verticalAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="NORTH" />
            </serializedBean>
            <formComponents>
              <group id="49" beanClass="com.install4j.runtime.beans.groups.VerticalFormComponentGroup" useExternalParametrization="true" externalParametrizationName="Customize title bar" externalParametrizationMode="include">
                <serializedBean>
                  <property name="backgroundColor">
                    <object class="com.install4j.runtime.beans.LightOrDarkColor">
                      <object class="java.awt.Color">
                        <int>255</int>
                        <int>255</int>
                        <int>255</int>
                        <int>255</int>
                      </object>
                      <object class="java.awt.Color">
                        <int>49</int>
                        <int>52</int>
                        <int>53</int>
                        <int>255</int>
                      </object>
                    </object>
                  </property>
                  <property name="borderSides">
                    <object class="com.install4j.runtime.beans.formcomponents.BorderSides">
                      <property name="bottom" type="boolean" value="true" />
                    </object>
                  </property>
                  <property name="imageAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="NORTHEAST" />
                  <property name="imageEdgeBorderWidth" type="int" value="2" />
                  <property name="imageFile">
                    <object class="com.install4j.api.beans.ExternalFile">
                      <string>icon:${installer:sys.installerApplicationMode}_header.png</string>
                    </object>
                  </property>
                  <property name="imageInsets">
                    <object class="java.awt.Insets">
                      <int>0</int>
                      <int>5</int>
                      <int>1</int>
                      <int>1</int>
                    </object>
                  </property>
                  <property name="insets">
                    <object class="java.awt.Insets">
                      <int>0</int>
                      <int>20</int>
                      <int>0</int>
                      <int>10</int>
                    </object>
                  </property>
                </serializedBean>
                <beans>
                  <formComponent name="Title" id="50" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent">
                    <serializedBean>
                      <property name="labelWidgetStyle" id="LabelWidgetStyle0">
                        <property name="fontDescriptor">
                          <property name="fontStyle" type="enum" class="com.install4j.runtime.beans.formcomponents.FontStyle" value="BOLD" />
                          <property name="fontType" type="enum" class="com.install4j.runtime.beans.formcomponents.FontType" value="DERIVED" />
                        </property>
                      </property>
                      <property name="labelWidgetStyleId" type="null" />
                    </serializedBean>
                  </formComponent>
                  <formComponent name="Subtitle" id="51" beanClass="com.install4j.runtime.beans.styles.ScreenTitleComponent" insetLeft="8">
                    <serializedBean>
                      <property name="titleType" type="enum" class="com.install4j.runtime.beans.styles.TitleType" value="SUB_TITLE" />
                    </serializedBean>
                  </formComponent>
                </beans>
                <externalParametrizationPropertyNames>
                  <propertyName>backgroundColor</propertyName>
                  <propertyName>foregroundColor</propertyName>
                  <propertyName>imageAnchor</propertyName>
                  <propertyName>imageFile</propertyName>
                  <propertyName>imageOverlap</propertyName>
                </externalParametrizationPropertyNames>
              </group>
            </formComponents>
          </style>
          <style name="Standard footer" id="52" beanClass="com.install4j.runtime.beans.styles.FormStyle">
            <serializedBean>
              <property name="fillVertical" type="boolean" value="false" />
              <property name="standalone" type="boolean" value="false" />
              <property name="verticalAnchor" type="enum" class="com.install4j.api.beans.Anchor" value="SOUTH" />
            </serializedBean>
            <formComponents>
              <group id="53" beanClass="com.install4j.runtime.beans.groups.HorizontalFormComponentGroup">
                <serializedBean>
                  <property name="alignFirstLabel" type="boolean" value="false" />
                  <property name="insets">
                    <object class="java.awt.Insets">
                      <int>3</int>
                      <int>5</int>
                      <int>8</int>
                      <int>5</int>
                    </object>
                  </property>
                </serializedBean>
                <beans>
                  <formComponent id="54" beanClass="com.install4j.runtime.beans.formcomponents.SpringComponent" />
                  <formComponent name="Back button" id="55" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
                    <serializedBean>
                      <property name="buttonText" type="string">&lt; ${i18n:ButtonBack}</property>
                      <property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="PREVIOUS" />
                    </serializedBean>
                  </formComponent>
                  <formComponent name="Next button" id="56" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent">
                    <serializedBean>
                      <property name="buttonText" type="string">${i18n:ButtonNext} &gt;</property>
                      <property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="NEXT" />
                    </serializedBean>
                  </formComponent>
                  <formComponent name="Cancel button" id="57" beanClass="com.install4j.runtime.beans.styles.StandardControlButtonComponent" insetLeft="5">
                    <serializedBean>
                      <property name="buttonText" type="string">${i18n:ButtonCancel}</property>
                      <property name="controlButtonType" type="enum" class="com.install4j.api.context.ControlButtonType" value="CANCEL" />
                    </serializedBean>
                  </formComponent>
                </beans>
              </group>
            </formComponents>
          </style>
        </beans>
      </group>
    </styles>
    <widgetStyles defaultWidgetStyleId="118">
      <widgetStyle name="Standard" id="118" beanClass="com.install4j.runtime.beans.widgets.WidgetStyleCollection" />
    </widgetStyles>
  </installerGui>
  <mediaSets>
    <unixInstaller name="Unix Installer" id="60" />
    <windows name="Windows 64 Bit" id="62" architecture="64" />
    <windows name="Windows 32 Bit" id="63" architecture="32" />
    <macosArchive name="macOS Single Bundle Archive" id="246" architecture="universal" dmgStylingMode="none" launcherId="59">
      <topLevelFiles>
        <symlink name="Applications" target="/Applications" />
      </topLevelFiles>
    </macosArchive>
  </mediaSets>
</install4j>


================================================
FILE: jitpack.yml
================================================
jdk:
  - openjdk17

================================================
FILE: package.json
================================================
{
  "devDependencies": {
    "all-contributors-cli": "^6.24.0"
  }
}


================================================
FILE: renovate.json
================================================
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "config:base",
    ":disableDependencyDashboard"
  ],
  "assignees": [
    "McPringle"
  ],
  "reviewers": [
    "McPringle"
  ],
  "packageRules": [
    {
      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
      "automerge": true,
      "automergeType": "branch",
      "commitMessagePrefix" : "⬆️ "
    },
    {
      "matchDepTypes": ["devDependencies"],
      "automerge": true,
      "automergeType": "branch",
      "commitMessagePrefix" : "⬆️ "
    }
  ],
  "platformAutomerge": true
}

================================================
FILE: settings.gradle
================================================
rootProject.name = 'gpx-animator'


================================================
FILE: src/main/java/app/gpx_animator/Main.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator;

import app.gpx_animator.core.UserException;
import app.gpx_animator.core.renderer.Renderer;
import app.gpx_animator.core.renderer.RenderingContext;
import app.gpx_animator.core.renderer.cache.TileCache;
import app.gpx_animator.ui.UIMode;
import app.gpx_animator.ui.cli.CommandLineConfigurationFactory;
import app.gpx_animator.ui.swing.MainFrame;
import org.jetbrains.annotations.NonNls;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;


public final class Main {

    @NonNls
    private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

    private Main() throws InstantiationException {
        throw new InstantiationException("This is the main class and can't be instantiated!");
    }

    @SuppressWarnings("PMD.AvoidCatchingGenericException")
    public static void main(final String... args) {
        try {
            start(args);
        } catch (final UserException e) {
            LOGGER.error(e.getMessage());
            System.exit(1);
        } catch (final Exception e) {
            LOGGER.error("Very bad, exception caught in main method!", e);
            System.exit(2);
        }
    }

    @SuppressWarnings("PMD.AvoidCatchingGenericException")
    public static void start(final String... args) throws Exception { // NOSONAR - Catching all uncatched exceptions in main method.
        final var cf = new CommandLineConfigurationFactory(args);
        final var configuration = cf.getConfiguration().validate();

        new Thread(TileCache::ageCache).start();

        if (cf.isGui() && !GraphicsEnvironment.isHeadless()) {
            UIMode.setMode(UIMode.EXPERT);
            EventQueue.invokeLater(() -> {
                try {
                    final var frame = MainFrame.getInstance();
                    frame.setVisible(true);
                    frame.setConfiguration(configuration);
                } catch (final Exception e) {
                    LOGGER.error(e.getMessage(), e);
                }
            });
        } else {
            UIMode.setMode(UIMode.CLI);
            new Renderer(configuration).render(new RenderingContext() {
                @Override
                public void setProgress1(final int pct, final String message) {
                    LOGGER.info("{}% {}", pct, message);
                }

                @Override
                public boolean isCancelled1() {
                    return false;
                }
            });
        }
    }
}


================================================
FILE: src/main/java/app/gpx_animator/core/Constants.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator.core;

import org.slf4j.LoggerFactory;

import java.awt.Font;
import java.io.IOException;
import java.util.Properties;

@SuppressWarnings("checkstyle:NoWhitespaceBefore") // For the ";" after the class declaration which is needed to use an enum for constants only
public enum Constants {
    ;

    public static final String APPNAME = "GPX Animator"; //NON-NLS

    public static final String VERSION = loadVersionString();

    public static final String APPNAME_VERSION = APPNAME.concat(" ").concat(VERSION);

    public static final String COPYRIGHT = "Copyright Contributors to the GPX Animator project."; //NON-NLS

    public static final String OS_NAME = System.getProperty("os.name");

    public static final String OS_VERSION = System.getProperty("os.version");

    public static final String OS_ARCH = System.getProperty("os.arch");

    public static final Font DEFAULT_FONT = new Font(Font.MONOSPACED, Font.PLAIN, 12);

    public static final String UPDATES_URL = "https://download.gpx-animator.app/updates.xml";

    public static final String USER_AGENT = String.format("%s %s on %s %s (%s)", //NON-NLS
            Constants.APPNAME, Constants.VERSION, Constants.OS_NAME, Constants.OS_VERSION, Constants.OS_ARCH);

    private static String loadVersionString() {

        final var properties = new Properties();
        try (var inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("build-info.properties")) {
            if (inputStream != null) {
                properties.load(inputStream);
            }
        } catch (IOException e) {
            LoggerFactory.getLogger(Constants.class).warn("Could not load build-info.properties", e);
        }
        return properties.getProperty("version", "<UNKNOWN VERSION>");
    }
}


================================================
FILE: src/main/java/app/gpx_animator/core/Help.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator.core;

import app.gpx_animator.core.configuration.Configuration;
import app.gpx_animator.core.configuration.TrackConfiguration;
import app.gpx_animator.core.configuration.adapter.FontXmlAdapter;
import app.gpx_animator.core.preferences.Preferences;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

import java.io.PrintWriter;


public final class Help {

    private Help() throws InstantiationException {
        throw new InstantiationException("Help is a Utility class and can't be instantiated!");
    }

    @SuppressWarnings("PMD.AvoidDuplicateLiterals")
    public static void printHelp(final OptionHelpWriter w) {
        final var resourceBundle = Preferences.getResourceBundle();

        final var cfg = Configuration.createBuilder().build();
        final var tc = TrackConfiguration.createBuilder().build();

        w.writeOptionHelp(Option.ATTRIBUTION, "text", false, cfg.getAttribution()); //NON-NLS
        w.writeOptionHelp(Option.ATTRIBUTION_POSITION, "position", false, cfg.getAttributionPosition()); //NON-NLS
        w.writeOptionHelp(Option.ATTRIBUTION_MARGIN, "attribution-margin", false, cfg.getAttributionMargin()); //NON-NLS
        w.writeOptionHelp(Option.BACKGROUND_COLOR, "background-color", false, cfg.getBackgroundColor()); // NON-NLS
        w.writeOptionHelp(Option.BACKGROUND_IMAGE, "background-image", false, cfg.getBackgroundImage()); // NON-NLS
        w.writeOptionHelp(Option.BACKGROUND_MAP_VISIBILITY, "background-map-visibility", false, cfg.getBackgroundMapVisibility()); //NON-NLS
        w.writeOptionHelp(Option.COLOR, "color", true, resourceBundle.getString("help.option.color.default")); //NON-NLS
        w.writeOptionHelp(Option.FLASHBACK_COLOR, "ARGBcolor", false, "opaque white - #ffffffff"); // TODO cfg.getFlashbackColor()  NON-NLS
        w.writeOptionHelp(Option.FLASHBACK_DURATION, "duration", false, cfg.getFlashbackDuration()); //NON-NLS
        w.writeOptionHelp(Option.FONT, "font", false, new FontXmlAdapter().marshal(cfg.getFont()));
        w.writeOptionHelp(Option.FORCED_POINT_TIME_INTERVAL, "milliseconds", true, tc.getForcedPointInterval()); //NON-NLS
        w.writeOptionHelp(Option.FPS, "fps", false, cfg.getFps()); //NON-NLS
        w.writeOptionHelp(Option.GUI, "gui", false, resourceBundle.getString("help.option.gui.default"));
        w.writeOptionHelp(Option.HEIGHT, "height", false, cfg.getHeight()); //NON-NLS
        w.writeOptionHelp(Option.HELP, "help", false, null); //TODO --help-info-vars
        w.writeOptionHelp(Option.INPUT, "input", true, tc.getInputGpx()); //NON-NLS
        w.writeOptionHelp(Option.INPUT_MUSIC, "input-music", false, cfg.getInputMusic()); //NON-NLS
        w.writeOptionHelp(Option.TRIM_GPX_START, "trim-gpx-start", true, tc.getTrimGpxStart()); //NON-NLS
        w.writeOptionHelp(Option.TRIM_GPX_END, "trim-gpx-end", true, tc.getTrimGpxEnd()); //NON-NLS
        w.writeOptionHelp(Option.INFORMATION, "text", false, cfg.getInformation().replace("\n", "\\n")); //NON-NLS
        w.writeOptionHelp(Option.INFORMATION_POSITION, "information-position", false, cfg.getInformationPosition());
        w.writeOptionHelp(Option.INFORMATION_MARGIN, "information-margin", false, cfg.getInformationMargin()); //NON-NLS
        w.writeOptionHelp(Option.COMMENT_POSITION, "comment-position", false, cfg.getCommentPosition());
        w.writeOptionHelp(Option.COMMENT_MARGIN, "comment-margin", false, cfg.getCommentMargin()); //NON-NLS
        w.writeOptionHelp(Option.TRACK_ICON, "trackIcon", true, tc.getTrackIcon()); //NON-NLS
        w.writeOptionHelp(Option.TRACK_ICON_FILE, "trackIconFile", true, tc.getInputIcon()); //NON-NLS
        w.writeOptionHelp(Option.TRACK_ICON_MIRROR, "mirrorTrackIcon", true, tc.isTrackIconMirrored()); //NON-NLS
        w.writeOptionHelp(Option.KEEP_FIRST_FRAME, "keep-first-frame", false, cfg.getKeepFirstFrame()); //NON-NLS
        w.writeOptionHelp(Option.KEEP_LAST_FRAME, "keep-last-frame", false, cfg.getKeepLastFrame()); //NON-NLS
        w.writeOptionHelp(Option.LABEL, "label", true, tc.getLabel()); //NON-NLS
        w.writeOptionHelp(Option.LINE_WIDTH, "width", true, tc.getLineWidth()); //NON-NLS
        w.writeOptionHelp(Option.LOGO_POSITION, "logo-position", false, cfg.getLogoPosition()); //NON-NLS
        w.writeOptionHelp(Option.LOGO_MARGIN, "logo-margin", false, cfg.getLogoMargin()); //NON-NLS
        w.writeOptionHelp(Option.MARGIN, "margin", false, cfg.getMargin()); //NON-NLS
        w.writeOptionHelp(Option.MARKER_SIZE, "size", false, cfg.getMarkerSize()); //NON-NLS
        w.writeOptionHelp(Option.MAX_LAT, "latitude", false, cfg.getMaxLat()); //NON-NLS
        w.writeOptionHelp(Option.MAX_LON, "longitude", false, cfg.getMaxLon()); //NON-NLS
        w.writeOptionHelp(Option.MIN_LAT, "latitude", false, cfg.getMinLat()); //NON-NLS
        w.writeOptionHelp(Option.MIN_LON, "longitude", false, cfg.getMinLon()); //NON-NLS
        w.writeOptionHelp(Option.OUTPUT, "output", false, cfg.getOutput()); //NON-NLS
        w.writeOptionHelp(Option.PHOTO_TIME, "milliseconds", false, cfg.getPhotoTime()); //NON-NLS
        w.writeOptionHelp(Option.PHOTO_FREEZE_FRAME_TIME, "milliseconds", false, cfg.getPhotoFreezeFrameTime()); //NON-NLS
        w.writeOptionHelp(Option.PHOTO_DIR, "directory", false, cfg.getPhotoDirectory()); //NON-NLS
        w.writeOptionHelp(Option.PRE_DRAW_TRACK, "predraw-track", false, cfg.isPreDrawTrack()); // NON-NLS
        w.writeOptionHelp(Option.PRE_DRAW_TRACK_COLOR, "predraw-track-color", true, tc.getPreDrawTrackColor()); // NON-NLS
        w.writeOptionHelp(Option.PREVIEW_LENGTH, "preview-length", false, cfg.getPreviewLength()); // NON-NLS
        w.writeOptionHelp(Option.SKIP_IDLE, "skip-idle", false, cfg.isSkipIdle());
        w.writeOptionHelp(Option.SPEEDUP, "speedup", false, cfg.getSpeedup()); //NON-NLS
        w.writeOptionHelp(Option.TAIL_DURATION, "time", false, cfg.getTailDuration()); //NON-NLS
        w.writeOptionHelp(Option.TAIL_COLOR, "tail-color", false, cfg.getTailColor()); //NON-NLS
        w.writeOptionHelp(Option.TAIL_COLOR_FADEOUT, "tail-color-fadeout", false, true); //NON-NLS
        w.writeOptionHelp(Option.TIME_OFFSET, "milliseconds", true, tc.getTimeOffset()); //NON-NLS
        w.writeOptionHelp(Option.TMS_URL_TEMPLATE, "tms-url-template", false, cfg.getTmsUrlTemplate()); //NON-NLS
        w.writeOptionHelp(Option.TMS_USER_AGENT, "tms-user-agent", false, cfg.getTmsUserAgent()); //NON-NLS
        w.writeOptionHelp(Option.TOTAL_TIME, "time", false, cfg.getTotalTime()); //NON-NLS
        w.writeOptionHelp(Option.SPEED_UNIT, "speed", false, cfg.getSpeedUnit()); //NON-NLS
        w.writeOptionHelp(Option.VIEWPORT_WIDTH, "viewport-width", false, cfg.getViewportWidth()); //NON-NLS
        w.writeOptionHelp(Option.VIEWPORT_HEIGHT, "viewport-height", false, cfg.getViewportHeight()); //NON-NLS
        w.writeOptionHelp(Option.VIEWPORT_INERTIA, "viewport-inertia", false, cfg.getViewportInertia()); //NON-NLS
        w.writeOptionHelp(Option.WAYPOINT_SIZE, "size", false, cfg.getWaypointSize()); //NON-NLS
        w.writeOptionHelp(Option.WIDTH, "width", false, cfg.getWidth()); //NON-NLS
        w.writeOptionHelp(Option.ZOOM, "zoom", false, cfg.getZoom()); //NON-NLS
        w.writeOptionHelp(Option.GPS_TIMEOUT, "milliseconds", false, cfg.getGpsTimeout()); //NON-NLS
        w.writeOptionHelp(Option.VERSION, "version", false, null); //NON-NLS
    }

    public interface OptionHelpWriter {
        void writeOptionHelp(Option option, String argument, boolean track, Object defaultValue);
    }

    @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "ClassCanBeRecord"}) // This class is not serializable
    public static final class PrintWriterOptionHelpWriter implements OptionHelpWriter {

        @SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "it's just a generic printer")
        private final PrintWriter pw;

        public PrintWriterOptionHelpWriter(final PrintWriter pw) {
            this.pw = pw;
        }

        @Override
        public void writeOptionHelp(final Option option, final String argument, final boolean track, final Object defaultValue) {
            final var resourceBundle = Preferences.getResourceBundle();

            pw.print("--");
            pw.print(option.getName());
            if (argument != null) {
                pw.print(" <");
                pw.print(argument);
                pw.print(">");
            }
            pw.println();
            //noinspection MagicCharacter
            pw.print('\t');
            pw.print(option.getHelp());
            if (track) {
                pw.print("; ");
                pw.print(resourceBundle.getString("help.options.multiple"));
            }
            if (defaultValue != null) {
                pw.print("; ");
                pw.print(resourceBundle.getString("help.options.default"));
                pw.print(" = ");
                pw.print(defaultValue);
            }
            pw.println();
        }
    }

}


================================================
FILE: src/main/java/app/gpx_animator/core/Option.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator.core;

import app.gpx_animator.core.preferences.Preferences;
import lombok.Getter;
import org.jetbrains.annotations.NonNls;

import java.util.HashMap;

@Getter
@SuppressWarnings("DuplicateStringLiteralInspection")
public enum Option {

    GUI("gui"),
    INPUT("input"),
    INPUT_MUSIC("input-music"),
    OUTPUT("output"),
    VIDEO_CODEC("video-codec"),
    MUSIC_CODEC("music-codec"),
    LABEL("label"),
    COLOR("color"),
    MARGIN("margin"),
    TIME_OFFSET("time-offset"),
    TRIM_GPX_START("trim-gpx-start"),
    TRIM_GPX_END("trim-gpx-end"),
    FORCED_POINT_TIME_INTERVAL("forced-point-time-interval"),
    SPEEDUP("speedup"),
    LINE_WIDTH("line-width"),
    PRE_DRAW_LINE_WIDTH("pre-draw-line-width"),
    TAIL_DURATION("tail-duration"),
    TAIL_COLOR("tail-color"),
    TAIL_COLOR_FADEOUT("tail-color-fadeout"),
    FPS("fps"),
    MARKER_SIZE("marker-size"),
    WAYPOINT_SIZE("waypoint-size"),
    MIN_LAT("min-lat"),
    MAX_LAT("max-lat"),
    MIN_LON("min-lon"),
    MAX_LON("max-lon"),
    WIDTH("width"),
    HEIGHT("height"),
    ZOOM("zoom"),
    VIEWPORT_WIDTH("viewport-width"),
    VIEWPORT_HEIGHT("viewport-height"),
    VIEWPORT_INERTIA("viewport-inertia"),
    FONT("font"),
    WAYPOINT_FONT("waypoint-font"),
    TMS_URL_TEMPLATE("tms-url-template"),
    TMS_API_KEY("tms-api-key"),
    TMS_USER_AGENT("tms-user-agent"),
    BACKGROUND_MAP_VISIBILITY("background-map-visibility"),
    TOTAL_TIME("total-time"),
    BACKGROUND_COLOR("background-color"),
    BACKGROUND_IMAGE("background-image"),
    FLASHBACK_COLOR("flashback-color"),
    FLASHBACK_DURATION("flashback-duration"),
    KEEP_FIRST_FRAME("keep-first-frame"),
    KEEP_LAST_FRAME("keep-last-frame"),
    SKIP_IDLE("skip-idle"),
    PRE_DRAW_TRACK("pre-draw-track"),
    PRE_DRAW_TRACK_COLOR("pre-draw-track-color"),
    LOGO("logo"),
    LOGO_POSITION("logo-position"),
    LOGO_MARGIN("logo-margin"),
    ATTRIBUTION("attribution"),
    ATTRIBUTION_POSITION("attribution-position"),
    ATTRIBUTION_MARGIN("attribution-margin"),
    INFORMATION("information"),
    INFORMATION_POSITION("information-position"),
    INFORMATION_MARGIN("information-margin"),
    COMMENT_POSITION("comment-position"),
    COMMENT_MARGIN("comment-margin"),
    PHOTO_DIR("photo-dir"),
    PHOTO_FREEZE_FRAME_TIME("photo-freeze-frame-time"),
    PHOTO_TIME("photo-time"),
    PHOTO_ANIMATION_DURATION("photo-animation-duration"),
    HELP("help"),
    TRACK_ICON("track-icon"),
    TRACK_ICON_FILE("track-icon-file"),
    TRACK_ICON_MIRROR("track-icon-mirror"),
    SPEED_UNIT("speed-unit"),
    PREVIEW_LENGTH("preview-length"),
    PREVIEW("preview"),
    GPS_TIMEOUT("gps-timeout"),
    VERSION("version");

    private static final java.util.Map<String, Option> OPTION_MAP = new HashMap<>();

    static {
        for (final var option : Option.values()) {
            OPTION_MAP.put(option.name, option);
        }
    }

    private final String name;
    private final String help;

    Option(@NonNls final String key) {
        final var resourceBundle = Preferences.getResourceBundle();

        this.name = key;
        this.help = resourceBundle.getString("option.help.".concat(key)); //NON-NLS
    }

    public static Option fromName(final String name) {
        return OPTION_MAP.get(name);
    }

}


================================================
FILE: src/main/java/app/gpx_animator/core/UserException.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator.core;

import java.io.Serial;

public class UserException extends Exception {

    @Serial
    private static final long serialVersionUID = 4742238182942265693L;

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

    public UserException(final String message) {
        super(message);
    }

}


================================================
FILE: src/main/java/app/gpx_animator/core/configuration/Configuration.java
================================================
/*
 *  Copyright Contributors to the GPX Animator project.
 *
 *  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.
 */
package app.gpx_animator.core.configuration;

import app.gpx_animator.core.Constants;
import app.gpx_animator.core.UserException;
import app.gpx_animator.core.configuration.adapter.ColorXmlAdapter;
import app.gpx_animator.core.configuration.adapter.FileXmlAdapter;
import app.gpx_animator.core.configuration.adapter.FontXmlAdapter;
import app.gpx_animator.core.data.MusicCodec;
import app.gpx_animator.core.data.Position;
import app.gpx_animator.core.data.SpeedUnit;
import app.gpx_animator.core.data.VideoCodec;
import app.gpx_animator.core.preferences.Preferences;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlElementWrapper;
import jakarta.xml.bind.annotation.XmlRootElement;
import jakarta.xml.bind.annotation.XmlTransient;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ResourceBundle;
import java.util.stream.Collectors;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not serializable, it uses XML transformation
public final class Configuration {

    private static final VideoCodec DEFAULT_VIDEO_CODEC = VideoCodec.H264;
    private static final MusicCodec DEFAULT_MUSIC_CODEC = MusicCodec.AAC;
    private static final Color DEFAULT_BACKGROUND_COLOR = Color.white;
    private static final int DEFAULT_MARGIN = 20;
    private static final int DEFAULT_VIEWPORT_INERTIA = 50;
    private static final String DEFAULT_INFORMATION = "%SPEED%\n%LATLON%\n%DATETIME%";
    private static final SpeedUnit DEFAULT_SPEED_UNIT = SpeedUnit.KMH;
    public static final long DEFAULT_PHOTO_ANIMATION_DURATION = 700L;
    public static final Position DEFAULT_ATTRIBUTION_POSITION = Position.BOTTOM_LEFT;
    public static final long DEFAULT_GPS_TIMEOUT = 60000L;

    private int margin = DEFAULT_MARGIN;
    private Integer width;
    private Integer height;
    private Integer zoom;

    private Integer viewportWidth;
    private Integer viewportHeight;
    private Integer viewportInertia = DEFAULT_VIEWPORT_INERTIA;

    private boolean preDrawTrack;

    private Double speedup;
    private long tailDuration;
    @XmlJavaTypeAdapter(ColorXmlAdapter.class)
    private Color tailColor;
    private boolean tailColorFadeout;
    private double fps;
    private Long totalTime;

    private float backgroundMapVisibility;
    private String tmsUrlTemplate;
    private String tmsApiKey;
    private String tmsUserAgent;

    private boolean skipIdle;

    @XmlJavaTypeAdapter(ColorXmlAdapter.class)
    private Color backgroundColor = DEFAULT_BACKGROUND_COLOR;
    @XmlJavaTypeAdapter(FileXmlAdapter.class)
    private File backgroundImage;

    @XmlJavaTypeAdapter(ColorXmlAdapter.class)
    private Color flashbackColor;
    private Long flashbackDuration;

    private Long keepFirstFrame;
    private Long keepLastFrame;

    @XmlJavaTypeAdapter(FileXmlAdapter.class)
    private File output;
    private VideoCodec videoCodec;
    private MusicCodec musicCodec;
    @XmlJavaTypeAdapter(FileXmlAdapter.class)
    private File inputMusic;
    private String attribution;
    private Position attributionPosition = DEFAULT_ATTRIBUTION_POSITION;
    private int attributionMargin = DEFAULT_MARGIN;
    private String information = DEFAULT_INFORMATION;
    private Position informationPosition = Position.BOTTOM_RIGHT;
    private int informationMargin = DEFAULT_MARGIN;
    private Position commentPosition = Position.BOTTOM_CENTER;
    private int commentMargin = DEFAULT_MARGIN;

    @XmlJavaTypeAdapter(FontXmlAdapter.class)
    private Font font;

    private Double markerSize;

    @XmlJavaTypeAdapter(FontXmlAdapter.class)
    private Font waypointFont;
    private Double waypointSize;

    private Double minLon;
    private Double maxLon;
    private Double minLat;
    private Double maxLat;

    @XmlJavaTypeAdapter(FileXmlAdapter.class)
    private File logo;
    private Position logoPosition = Position.TOP_LEFT;
    private int logoMargin = DEFAULT_MARGIN;

    @XmlJavaTypeAdapter(FileXmlAdapter.class)
    private File photoDirectory;
    private Long photoFreezeFrameTime = 0L;
    private Long photoTime;
    private Long photoAnimationDuration = DEFAULT_PHOTO_ANIMATION_DURATION;

    private SpeedUnit speedUnit;

    @XmlTransient
    private boolean preview = false;
    @XmlTransient
    private Long previewLength;
    private long gpsTimeout = DEFAULT_GPS_TIMEOUT;

    @XmlElementWrapper
    @XmlElement(name = "trackConfiguration") //NON-NLS
    private List<TrackConfiguration> trackConfigurationList;


    // for JAXB
    private Configuration() {
    }

    @SuppressWarnings({"checkstyle:ParameterNumber", "java:S107"})
    private Configuration(
            final int margin, final Integer width, final Integer heig
Download .txt
gitextract_zrhr46wq/

├── .all-contributorsrc
├── .editorconfig
├── .fleet/
│   ├── run.json
│   └── settings.json
├── .gitattributes
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   ├── dependabot.yml
│   └── workflows/
│       ├── add-to-project.yml
│       └── gradle.yml
├── .gitignore
├── .gitpod.Dockerfile
├── .gitpod.yml
├── .run/
│   ├── GPX Animator (de) HiDPI.run.xml
│   ├── GPX Animator (de).run.xml
│   ├── GPX Animator (en) HiDPI.run.xml
│   ├── GPX Animator (en).run.xml
│   ├── check test.run.xml
│   ├── check.run.xml
│   └── test.run.xml
├── .sdkmanrc
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── build.gradle
├── config/
│   ├── checkstyle/
│   │   └── checkstyle.xml
│   ├── pmd/
│   │   └── pmd-rules.xml
│   └── spotbugs/
│       └── exclude.xml
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── install/
│   └── gpx-animator.install4j
├── jitpack.yml
├── package.json
├── renovate.json
├── settings.gradle
└── src/
    ├── main/
    │   ├── java/
    │   │   └── app/
    │   │       └── gpx_animator/
    │   │           ├── Main.java
    │   │           ├── core/
    │   │           │   ├── Constants.java
    │   │           │   ├── Help.java
    │   │           │   ├── Option.java
    │   │           │   ├── UserException.java
    │   │           │   ├── configuration/
    │   │           │   │   ├── Configuration.java
    │   │           │   │   ├── TrackConfiguration.java
    │   │           │   │   └── adapter/
    │   │           │   │       ├── ColorXmlAdapter.java
    │   │           │   │       ├── FileXmlAdapter.java
    │   │           │   │       ├── FontXmlAdapter.java
    │   │           │   │       └── TrackIconXmlAdapter.java
    │   │           │   ├── data/
    │   │           │   │   ├── MapTemplate.java
    │   │           │   │   ├── MusicCodec.java
    │   │           │   │   ├── Photo.java
    │   │           │   │   ├── Position.java
    │   │           │   │   ├── SpeedUnit.java
    │   │           │   │   ├── TrackIcon.java
    │   │           │   │   ├── VideoCodec.java
    │   │           │   │   ├── entity/
    │   │           │   │   │   ├── MyPoint.java
    │   │           │   │   │   ├── Track.java
    │   │           │   │   │   ├── TrackPoint.java
    │   │           │   │   │   ├── TrackSegment.java
    │   │           │   │   │   ├── TrackType.java
    │   │           │   │   │   └── WayPoint.java
    │   │           │   │   └── gpx/
    │   │           │   │       ├── GPX.java
    │   │           │   │       ├── GpxContentHandler.java
    │   │           │   │       ├── GpxParser.java
    │   │           │   │       └── GpxPoint.java
    │   │           │   ├── preferences/
    │   │           │   │   └── Preferences.java
    │   │           │   ├── renderer/
    │   │           │   │   ├── ImageRenderer.java
    │   │           │   │   ├── Metadata.java
    │   │           │   │   ├── Renderer.java
    │   │           │   │   ├── RenderingContext.java
    │   │           │   │   ├── TextRenderer.java
    │   │           │   │   ├── cache/
    │   │           │   │   │   └── TileCache.java
    │   │           │   │   ├── framewriter/
    │   │           │   │   │   ├── FileFrameWriter.java
    │   │           │   │   │   ├── FrameWriter.java
    │   │           │   │   │   ├── NullFrameWriter.java
    │   │           │   │   │   └── VideoFrameWriter.java
    │   │           │   │   └── plugins/
    │   │           │   │       ├── AttributionPlugin.java
    │   │           │   │       ├── BackgroundColorPlugin.java
    │   │           │   │       ├── BackgroundImagePlugin.java
    │   │           │   │       ├── BackgroundMapPlugin.java
    │   │           │   │       ├── CommentPlugin.java
    │   │           │   │       ├── InformationPlugin.java
    │   │           │   │       ├── LogoPlugin.java
    │   │           │   │       ├── PhotoPlugin.java
    │   │           │   │       ├── PreviewPlugin.java
    │   │           │   │       └── RendererPlugin.java
    │   │           │   └── util/
    │   │           │       ├── DateUtil.java
    │   │           │       ├── FormatUtil.java
    │   │           │       ├── MapUtil.java
    │   │           │       ├── Notification.java
    │   │           │       ├── PluginUtil.java
    │   │           │       ├── PointUtil.java
    │   │           │       ├── RenderUtil.java
    │   │           │       ├── Sound.java
    │   │           │       └── Utils.java
    │   │           └── ui/
    │   │               ├── UIMode.java
    │   │               ├── cli/
    │   │               │   └── CommandLineConfigurationFactory.java
    │   │               └── swing/
    │   │                   ├── ColorSelector.java
    │   │                   ├── DurationEditor.java
    │   │                   ├── DurationFormatter.java
    │   │                   ├── DurationSpinnerModel.java
    │   │                   ├── EmptyNullSpinnerModel.java
    │   │                   ├── EmptyZeroNumberEditor.java
    │   │                   ├── ErrorDialog.java
    │   │                   ├── EscapeDialog.java
    │   │                   ├── FileSelector.java
    │   │                   ├── FontChooser.java
    │   │                   ├── FontSelector.java
    │   │                   ├── GeneralSettingsPanel.java
    │   │                   ├── JPlaceholderTextField.java
    │   │                   ├── MainFrame.java
    │   │                   ├── MarkdownDialog.java
    │   │                   ├── MarkdownFileDialog.java
    │   │                   ├── PreferencesDialog.java
    │   │                   ├── PreviewDialog.java
    │   │                   ├── ProtocolDialog.java
    │   │                   ├── TrackSettingsPanel.java
    │   │                   └── UsageDialog.java
    │   └── resources/
    │       ├── ABOUT.md
    │       ├── i18n/
    │       │   ├── Messages.properties
    │       │   └── Messages_de.properties
    │       └── logback.xml
    └── test/
        ├── java/
        │   └── app/
        │       └── gpx_animator/
        │           ├── MemoryAppender.java
        │           ├── MissingTranslationsTest.java
        │           ├── core/
        │           │   ├── configuration/
        │           │   │   └── adapter/
        │           │   │       └── FontXmlAdapterTest.java
        │           │   ├── data/
        │           │   │   ├── SpeedUnitTest.java
        │           │   │   └── gpx/
        │           │   │       └── GpxContentHandlerTest.java
        │           │   ├── renderer/
        │           │   │   └── plugins/
        │           │   │       └── PhotoPluginTest.java
        │           │   └── util/
        │           │       ├── DateUtilTest.java
        │           │       ├── PointUtilTest.java
        │           │       ├── RenderUtilTest.java
        │           │       └── UtilsTest.java
        │           └── ui/
        │               ├── cli/
        │               │   ├── CommandLineConfigurationFactoryTest.java
        │               │   ├── CommandLineIT.java
        │               │   └── OptionParam.java
        │               └── swing/
        │                   ├── DurationFormatterTest.java
        │                   └── DurationSpinnerModelTest.java
        └── resources/
            └── gpx/
                ├── bikeride.gpx
                └── comment.gpx
Download .txt
SYMBOL INDEX (784 symbols across 94 files)

FILE: src/main/java/app/gpx_animator/Main.java
  class Main (line 33) | public final class Main {
    method Main (line 38) | private Main() throws InstantiationException {
    method main (line 42) | @SuppressWarnings("PMD.AvoidCatchingGenericException")
    method start (line 55) | @SuppressWarnings("PMD.AvoidCatchingGenericException")

FILE: src/main/java/app/gpx_animator/core/Constants.java
  type Constants (line 24) | @SuppressWarnings("checkstyle:NoWhitespaceBefore") // For the ";" after ...
    method loadVersionString (line 49) | private static String loadVersionString() {

FILE: src/main/java/app/gpx_animator/core/Help.java
  class Help (line 28) | public final class Help {
    method Help (line 30) | private Help() throws InstantiationException {
    method printHelp (line 34) | @SuppressWarnings("PMD.AvoidDuplicateLiterals")
    type OptionHelpWriter (line 107) | public interface OptionHelpWriter {
      method writeOptionHelp (line 108) | void writeOptionHelp(Option option, String argument, boolean track, ...
    class PrintWriterOptionHelpWriter (line 111) | @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "ClassCanBeRecord...
      method PrintWriterOptionHelpWriter (line 117) | public PrintWriterOptionHelpWriter(final PrintWriter pw) {
      method writeOptionHelp (line 121) | @Override

FILE: src/main/java/app/gpx_animator/core/Option.java
  type Option (line 24) | @Getter
    method Option (line 112) | Option(@NonNls final String key) {
    method fromName (line 119) | public static Option fromName(final String name) {

FILE: src/main/java/app/gpx_animator/core/UserException.java
  class UserException (line 20) | public class UserException extends Exception {
    method UserException (line 25) | public UserException(final String message, final Throwable cause) {
    method UserException (line 29) | public UserException(final String message) {

FILE: src/main/java/app/gpx_animator/core/configuration/Configuration.java
  class Configuration (line 45) | @XmlRootElement
    method Configuration (line 153) | private Configuration() {
    method Configuration (line 156) | @SuppressWarnings({"checkstyle:ParameterNumber", "java:S107"})
    method createBuilder (line 234) | public static Builder createBuilder() {
    method getMargin (line 238) | public int getMargin() {
    method getWidth (line 242) | public Integer getWidth() {
    method getHeight (line 246) | public Integer getHeight() {
    method getViewportWidth (line 250) | public Integer getViewportWidth() {
    method getViewportHeight (line 254) | public Integer getViewportHeight() {
    method getViewportInertia (line 258) | public Integer getViewportInertia() {
    method getZoom (line 262) | public Integer getZoom() {
    method getSpeedup (line 266) | public Double getSpeedup() {
    method getSpeedUnit (line 270) | public SpeedUnit getSpeedUnit() {
    method getTailDuration (line 274) | public long getTailDuration() {
    method getTailColor (line 278) | public Color getTailColor() {
    method isTailColorFadeout (line 282) | public boolean isTailColorFadeout() {
    method getFps (line 286) | public double getFps() {
    method getTotalTime (line 290) | public Long getTotalTime() {
    method getBackgroundMapVisibility (line 294) | public float getBackgroundMapVisibility() {
    method getTmsUrlTemplate (line 298) | public String getTmsUrlTemplate() {
    method getTmsApiKey (line 302) | public String getTmsApiKey() {
    method getTmsUserAgent (line 306) | public String getTmsUserAgent() {
    method isSkipIdle (line 310) | public boolean isSkipIdle() {
    method isPreDrawTrack (line 314) | public boolean isPreDrawTrack() {
    method getBackgroundColor (line 318) | public Color getBackgroundColor() {
    method getBackgroundImage (line 322) | public File getBackgroundImage() {
    method getFlashbackColor (line 326) | public Color getFlashbackColor() {
    method getFlashbackDuration (line 330) | public Long getFlashbackDuration() {
    method getKeepFirstFrame (line 334) | public Long getKeepFirstFrame() {
    method getKeepLastFrame (line 338) | public Long getKeepLastFrame() {
    method getOutput (line 342) | public File getOutput() {
    method getVideoCodec (line 354) | public VideoCodec getVideoCodec() {
    method getMusicCodec (line 358) | public MusicCodec getMusicCodec() {
    method getInputMusic (line 362) | public File getInputMusic() {
    method getAttribution (line 366) | public String getAttribution() {
    method getInformation (line 370) | public String getInformation() {
    method getFont (line 374) | public Font getFont() {
    method getMarkerSize (line 378) | public Double getMarkerSize() {
    method getWaypointFont (line 382) | public Font getWaypointFont() {
    method getWaypointSize (line 386) | public Double getWaypointSize() {
    method getMinLon (line 390) | public Double getMinLon() {
    method getMaxLon (line 394) | public Double getMaxLon() {
    method getMinLat (line 398) | public Double getMinLat() {
    method getMaxLat (line 402) | public Double getMaxLat() {
    method getLogo (line 406) | public File getLogo() {
    method getLogoPosition (line 410) | public Position getLogoPosition() {
    method getLogoMargin (line 414) | public int getLogoMargin() {
    method getAttributionPosition (line 418) | public Position getAttributionPosition() {
    method getAttributionMargin (line 422) | public int getAttributionMargin() {
    method getInformationPosition (line 426) | public Position getInformationPosition() {
    method getInformationMargin (line 430) | public int getInformationMargin() {
    method getCommentPosition (line 434) | public Position getCommentPosition() {
    method getCommentMargin (line 438) | public int getCommentMargin() {
    method getPhotoDirectory (line 442) | public File getPhotoDirectory() {
    method getPhotoFreezeFrameTime (line 446) | public Long getPhotoFreezeFrameTime() {
    method getPhotoTime (line 450) | public Long getPhotoTime() {
    method getPhotoAnimationDuration (line 454) | public Long getPhotoAnimationDuration() {
    method isPreview (line 458) | public boolean isPreview() {
    method getPreviewLength (line 462) | public Long getPreviewLength() {
    method getGpsTimeout (line 466) | public long getGpsTimeout() {
    method getTrackConfigurationList (line 472) | public List<TrackConfiguration> getTrackConfigurationList() {
    method validateFile (line 476) | private static File validateFile(final File file) {
    method validate (line 480) | public Configuration validate() throws UserException {
    class Builder (line 514) | @SuppressWarnings({"PMD.AvoidFieldNameMatchingMethodName", "checkstyle...
      method build (line 576) | public Configuration build() {
      method margin (line 598) | public Builder margin(final int margin) {
      method height (line 603) | public Builder height(final Integer height) {
      method width (line 608) | public Builder width(final Integer width) {
      method viewportHeight (line 613) | public Builder viewportHeight(final Integer viewportHeight) {
      method viewportWidth (line 618) | public Builder viewportWidth(final Integer viewportWidth) {
      method viewportInertia (line 623) | public Builder viewportInertia(final Integer viewportInertia) {
      method zoom (line 628) | public Builder zoom(final Integer zoom) {
      method speedup (line 633) | public Builder speedup(final Double speedup) {
      method tailDuration (line 638) | public Builder tailDuration(final long tailDuration) {
      method tailColor (line 643) | public Builder tailColor(final Color tailColor) {
      method tailColorFadeout (line 648) | public Builder tailColorFadeout(final boolean tailColorFadeout) {
      method fps (line 653) | public Builder fps(final double fps) {
      method totalTime (line 658) | public Builder totalTime(final Long totalTime) {
      method backgroundMapVisibility (line 663) | public Builder backgroundMapVisibility(final float backgroundMapVisi...
      method tmsUrlTemplate (line 668) | public Builder tmsUrlTemplate(final String tmsUrlTemplate) {
      method tmsApiKey (line 673) | public Builder tmsApiKey(final String tmsApiKey) {
      method tmsUserAgent (line 678) | public Builder tmsUserAgent(final String tmsUserAgent) {
      method skipIdle (line 683) | public Builder skipIdle(final boolean skipIdle) {
      method backgroundColor (line 688) | public Builder backgroundColor(final Color backgroundColor) {
      method backgroundImage (line 693) | public Builder backgroundImage(final File backgroundImage) {
      method preDrawTrack (line 698) | public Builder preDrawTrack(final boolean preDrawTrack) {
      method flashbackColor (line 703) | public Builder flashbackColor(final Color flashbackColor) {
      method flashbackDuration (line 708) | public Builder flashbackDuration(final Long flashbackDuration) {
      method keepFirstFrame (line 713) | public Builder keepFirstFrame(final Long keepFirstFrame) {
      method keepLastFrame (line 718) | public Builder keepLastFrame(final Long keepLastFrame) {
      method output (line 723) | public Builder output(final File output) {
      method videoCodec (line 728) | public Builder videoCodec(final VideoCodec videoCodec) {
      method musicCodec (line 733) | public Builder musicCodec(final MusicCodec musicCodec) {
      method inputMusic (line 738) | public Builder inputMusic(final File inputMusic) {
      method attribution (line 743) | public Builder attribution(final String attribution) {
      method information (line 748) | public Builder information(final String information) {
      method font (line 753) | public Builder font(final Font font) {
      method markerSize (line 758) | public Builder markerSize(final Double markerSize) {
      method waypointFont (line 763) | public Builder waypointFont(final Font waypointFont) {
      method waypointSize (line 768) | public Builder waypointSize(final Double waypointSize) {
      method minLat (line 773) | public Builder minLat(final Double minLat) {
      method maxLat (line 778) | public Builder maxLat(final Double maxLat) {
      method minLon (line 783) | public Builder minLon(final Double minLon) {
      method maxLon (line 788) | public Builder maxLon(final Double maxLon) {
      method logo (line 793) | public Builder logo(final File logo) {
      method logoPosition (line 798) | public Builder logoPosition(final Position logoPosition) {
      method logoMargin (line 803) | public Builder logoMargin(final int logoMargin) {
      method attributionPosition (line 808) | public Builder attributionPosition(final Position attributionPositio...
      method attributionMargin (line 813) | public Builder attributionMargin(final int attributionMargin) {
      method informationPosition (line 818) | public Builder informationPosition(final Position informationPositio...
      method informationMargin (line 823) | public Builder informationMargin(final int informationMargin) {
      method commentPosition (line 828) | public Builder commentPosition(final Position commentPosition) {
      method commentMargin (line 833) | public Builder commentMargin(final int commentMargin) {
      method photoDirectory (line 838) | public Builder photoDirectory(final File photoDirectory) {
      method photoFreezeFrameTime (line 843) | public Builder photoFreezeFrameTime(final Long photoFreezeFrameTime) {
      method photoTime (line 848) | public Builder photoTime(final Long photoTime) {
      method photoAnimationDuration (line 853) | public Builder photoAnimationDuration(final Long photoAnimationDurat...
      method addTrackConfiguration (line 858) | public Builder addTrackConfiguration(final TrackConfiguration trackC...
      method speedUnit (line 863) | public Builder speedUnit(final SpeedUnit speedUnit) {
      method preview (line 868) | public Builder preview(final boolean preview) {
      method previewLength (line 873) | public Builder previewLength(final Long previewLength) {
      method gpsTimeout (line 878) | public Builder gpsTimeout(final long gpsTimeout) {

FILE: src/main/java/app/gpx_animator/core/configuration/TrackConfiguration.java
  class TrackConfiguration (line 29) | @XmlAccessorType(XmlAccessType.FIELD)
    method TrackConfiguration (line 68) | private TrackConfiguration() {
    method TrackConfiguration (line 72) | @SuppressWarnings({"checkstyle:ParameterNumber", "java:S107"})
    method createBuilder (line 95) | public static Builder createBuilder() {
    method getTrackIcon (line 99) | public TrackIcon getTrackIcon() {
    method isTrackIconMirrored (line 103) | public boolean isTrackIconMirrored() {
    method getInputGpx (line 107) | public File getInputGpx() {
    method getInputIcon (line 111) | public File getInputIcon() {
    method getLabel (line 115) | public String getLabel() {
    method getColor (line 119) | public Color getColor() {
    method getPreDrawTrackColor (line 123) | public Color getPreDrawTrackColor() {
    method getTimeOffset (line 127) | public Long getTimeOffset() {
    method getForcedPointInterval (line 131) | public Long getForcedPointInterval() {
    method getTrimGpxStart (line 135) | public Long getTrimGpxStart() {
    method getTrimGpxEnd (line 139) | public Long getTrimGpxEnd() {
    method getLineWidth (line 143) | public float getLineWidth() {
    method getPreDrawLineWidth (line 147) | public float getPreDrawLineWidth() {
    method getInputEndIcon (line 151) | public File getInputEndIcon() {
    method isMirrorTrackEndIcon (line 155) | public boolean isMirrorTrackEndIcon() {
    method getTrackEndIcon (line 159) | public TrackIcon getTrackEndIcon() {
    class Builder (line 164) | @SuppressWarnings({"PMD.AvoidFieldNameMatchingMethodName", "checkstyle...
      method Builder (line 187) | private Builder() {
      method build (line 191) | public TrackConfiguration build() {
      method inputGpx (line 199) | public Builder inputGpx(final File inputGpx) {
      method label (line 204) | public Builder label(final String label) {
      method color (line 210) | public Builder color(final Color color) {
      method preDrawTrackColor (line 216) | public Builder preDrawTrackColor(final Color preDrawTrackColor) {
      method timeOffset (line 222) | public Builder timeOffset(final Long timeOffset) {
      method forcedPointInterval (line 228) | public Builder forcedPointInterval(final Long forcedPointInterval) {
      method trimGpxStart (line 234) | public Builder trimGpxStart(final Long trimGpxStart) {
      method trimGpxEnd (line 240) | public Builder trimGpxEnd(final Long trimGpxEnd) {
      method lineWidth (line 246) | public Builder lineWidth(final float lineWidth) {
      method preDrawLineWidth (line 251) | public Builder preDrawLineWidth(final float preDrawLineWidth) {
      method trackIcon (line 256) | public Builder trackIcon(final TrackIcon trackIcon) {
      method inputIcon (line 261) | public Builder inputIcon(final File inputIcon) {
      method mirrorTrackIcon (line 266) | public Builder mirrorTrackIcon(final boolean mirrorTrackIcon) {
      method trackEndIcon (line 271) | public Builder trackEndIcon(final TrackIcon trackEndIcon) {
      method inputEndIcon (line 276) | public Builder inputEndIcon(final File inputEndIcon) {
      method mirrorTrackEndIcon (line 281) | public Builder mirrorTrackEndIcon(final boolean mirrorTrackEndIcon) {

FILE: src/main/java/app/gpx_animator/core/configuration/adapter/ColorXmlAdapter.java
  class ColorXmlAdapter (line 23) | public final class ColorXmlAdapter extends XmlAdapter<String, Color> {
    method unmarshal (line 25) | @Override
    method marshal (line 30) | @Override

FILE: src/main/java/app/gpx_animator/core/configuration/adapter/FileXmlAdapter.java
  class FileXmlAdapter (line 23) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method FileXmlAdapter (line 28) | @SuppressWarnings("PMD.NullAssignment")
    method unmarshal (line 33) | @Override
    method marshal (line 43) | @Override
    method relativize (line 50) | private String relativize(final Path path) {

FILE: src/main/java/app/gpx_animator/core/configuration/adapter/FontXmlAdapter.java
  class FontXmlAdapter (line 24) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method unmarshal (line 27) | @Override
    method marshal (line 32) | @Override
    method encode (line 37) | private String encode(@NonNull final Font font) {
    method getStyle (line 44) | private String getStyle(@NonNull final Font font) {

FILE: src/main/java/app/gpx_animator/core/configuration/adapter/TrackIconXmlAdapter.java
  class TrackIconXmlAdapter (line 21) | public final class TrackIconXmlAdapter extends XmlAdapter<String, TrackI...
    method unmarshal (line 23) | @Override
    method marshal (line 28) | @Override

FILE: src/main/java/app/gpx_animator/core/data/MapTemplate.java
  method toString (line 26) | @Override

FILE: src/main/java/app/gpx_animator/core/data/MusicCodec.java
  type MusicCodec (line 34) | @Getter
    method toString (line 43) | @Override
    method fillComboBox (line 48) | public static void fillComboBox(@NotNull final JComboBox<MusicCodec> c...
    method parse (line 52) | public static MusicCodec parse(final String codecName, final MusicCode...

FILE: src/main/java/app/gpx_animator/core/data/Position.java
  type Position (line 27) | public enum Position {
    method toString (line 39) | @Override
    method parse (line 44) | public static Position parse(@NotNull final String p) {
    method fillComboBox (line 48) | public static void fillComboBox(@NotNull final JComboBox<Position> com...

FILE: src/main/java/app/gpx_animator/core/data/SpeedUnit.java
  type Calculation (line 25) | interface Calculation {
    method calc (line 26) | double calc(double kmh);
  type SpeedUnit (line 29) | public enum SpeedUnit {
    method fillComboBox (line 46) | public static void fillComboBox(final JComboBox<SpeedUnit> comboBox) {
    method SpeedUnit (line 56) | SpeedUnit(final String abbreviation, final Calculation calculation, fi...
    method toString (line 62) | @Override
    method getAbbreviation (line 67) | public String getAbbreviation() {
    method isDisplayMinutes (line 71) | public boolean isDisplayMinutes() {
    method convertSpeed (line 75) | public double convertSpeed(final double speed) {
    method parse (line 79) | public static SpeedUnit parse(final String unitString, final SpeedUnit...

FILE: src/main/java/app/gpx_animator/core/data/TrackIcon.java
  class TrackIcon (line 29) | public final class TrackIcon {
    method getAllTrackIcons (line 42) | public static Vector<TrackIcon> getAllTrackIcons() {
    method TrackIcon (line 66) | public TrackIcon(@NonNull final String key) {
    method TrackIcon (line 70) | public TrackIcon(@NonNull final String key, @NonNull final String name) {
    method toString (line 75) | @Override
    method equals (line 80) | @Override
    method hashCode (line 92) | @Override
    method getKey (line 97) | public @NonNull String getKey() {
    method getName (line 101) | public @NonNull String getName() {
    method getFilename (line 105) | public String getFilename() {

FILE: src/main/java/app/gpx_animator/core/data/VideoCodec.java
  type VideoCodec (line 27) | public enum VideoCodec {
    method VideoCodec (line 35) | VideoCodec(@NonNull final String codecName, final int codecId) {
    method getCodecName (line 40) | public String getCodecName() {
    method getCodecId (line 44) | public int getCodecId() {
    method toString (line 48) | @Override
    method fillComboBox (line 53) | public static void fillComboBox(@NotNull final JComboBox<VideoCodec> c...
    method parse (line 57) | public static VideoCodec parse(final String codecName, final VideoCode...

FILE: src/main/java/app/gpx_animator/core/data/entity/MyPoint.java
  type MyPoint (line 3) | public interface MyPoint {
    method getLatitude (line 5) | Double getLatitude();
    method getLongitude (line 6) | Double getLongitude();
    method getTime (line 7) | Long getTime();

FILE: src/main/java/app/gpx_animator/core/data/entity/Track.java
  class Track (line 13) | @With

FILE: src/main/java/app/gpx_animator/core/data/entity/TrackPoint.java
  class TrackPoint (line 27) | @Getter

FILE: src/main/java/app/gpx_animator/core/data/entity/TrackSegment.java
  class TrackSegment (line 23) | @Value

FILE: src/main/java/app/gpx_animator/core/data/entity/TrackType.java
  type TrackType (line 9) | public enum TrackType {
    method getTrackType (line 16) | public static @NotNull TrackType getTrackType(@NotNull final String va...

FILE: src/main/java/app/gpx_animator/core/data/entity/WayPoint.java
  class WayPoint (line 27) | @Getter

FILE: src/main/java/app/gpx_animator/core/data/gpx/GPX.java
  type GPX (line 7) | public enum GPX {
    method GPX (line 23) | GPX(@NotNull final String name) {
    method getName (line 27) | public @NotNull String getName() {
    method toString (line 31) | @Override
    method getElement (line 36) | public static @NotNull GPX getElement(@NotNull final String value) {

FILE: src/main/java/app/gpx_animator/core/data/gpx/GpxContentHandler.java
  class GpxContentHandler (line 43) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method GpxContentHandler (line 57) | public GpxContentHandler() {
    method startElement (line 61) | @Override
    method characters (line 96) | @Override
    method endElement (line 104) | @Override
    method parseDateTime (line 168) | private @Nullable ZonedDateTime parseDateTime(@Nullable final String d...
    method getTrack (line 186) | public @Nullable Track getTrack() {
    method getWayPoints (line 190) | public @NotNull List<WayPoint> getWayPoints() {
    type CharacterConsumer (line 194) | sealed interface CharacterConsumer {
      method accept (line 195) | void accept(char[] ch, int start, int length);
      method getValue (line 196) | String getValue();
      method isEmpty (line 197) | boolean isEmpty();
    class StringCharacterConsumer (line 200) | static final class StringCharacterConsumer implements CharacterConsumer {
      method accept (line 203) | @Override
      method getValue (line 208) | @Override
      method isEmpty (line 213) | @Override
    type NoOpConsumer (line 218) | enum NoOpConsumer implements CharacterConsumer {
      method accept (line 221) | @Override
      method getValue (line 226) | @Override
      method isEmpty (line 231) | @Override

FILE: src/main/java/app/gpx_animator/core/data/gpx/GpxParser.java
  class GpxParser (line 35) | public final class GpxParser {
    method GpxParser (line 39) | private GpxParser() throws InstantiationException {
    method parseGpx (line 43) | public static void parseGpx(final File inputGpx, final DefaultHandler ...
    method parseGpx (line 52) | @SuppressWarnings("PMD.AvoidCatchingGenericException") // Need to catc...
    method decompressStream (line 77) | @SuppressWarnings("PMD.CloseResource") // The returned stream will be ...

FILE: src/main/java/app/gpx_animator/core/data/gpx/GpxPoint.java
  class GpxPoint (line 25) | public final class GpxPoint extends Point2D.Double {
    method GpxPoint (line 34) | public GpxPoint(final double x, final double y, final TrackPoint track...
    method getTrackPoint (line 41) | public TrackPoint getTrackPoint() {
    method getTime (line 45) | public long getTime() {
    method getSpeed (line 49) | public java.lang.Double getSpeed() {
    method equals (line 53) | @Override
    method hashCode (line 76) | @Override

FILE: src/main/java/app/gpx_animator/core/preferences/Preferences.java
  class Preferences (line 29) | public final class Preferences {
    method getResourceBundle (line 46) | public static ResourceBundle getResourceBundle() {
    method getConfigurationDir (line 50) | public static String getConfigurationDir() {
    method getChangelogVersion (line 54) | public static String getChangelogVersion() {
    method setChangelogVersion (line 58) | public static void setChangelogVersion(final String changelogVersion) {
    method getLastWorkingDir (line 62) | public static String getLastWorkingDir() {
    method setLastWorkingDir (line 74) | public static void setLastWorkingDir(final String lastWorkingDir) {
    method setPreviewEnabled (line 78) | public static void setPreviewEnabled(final Boolean previewEnabled) {
    method isPreviewEnabled (line 82) | public static boolean isPreviewEnabled() {
    method getRecentFiles (line 86) | public static List<File> getRecentFiles() {
    method addRecentFile (line 93) | public static void addRecentFile(final File file) {
    method getTileCacheDir (line 102) | public static String getTileCacheDir() {
    method setTileCacheDir (line 109) | public static void setTileCacheDir(final String tileCacheDir) {
    method getTileCacheTimeLimit (line 113) | public static long getTileCacheTimeLimit() {
    method setTileCacheTimeLimit (line 118) | public static void setTileCacheTimeLimit(final long tileCacheTimeLimit) {
    method getTrackColorRandom (line 122) | public static boolean getTrackColorRandom() {
    method setTrackColorRandom (line 126) | public static void setTrackColorRandom(final boolean trackColorRandom) {
    method getTrackColorDefault (line 130) | public static Color getTrackColorDefault() {
    method setTrackColorDefault (line 136) | public static void setTrackColorDefault(final Color trackColorDefault) {
    method Preferences (line 142) | private Preferences() {

FILE: src/main/java/app/gpx_animator/core/renderer/ImageRenderer.java
  class ImageRenderer (line 25) | public abstract class ImageRenderer {
    method renderImage (line 35) | public void renderImage(@NonNull final BufferedImage image, @NonNull f...

FILE: src/main/java/app/gpx_animator/core/renderer/Renderer.java
  class Renderer (line 76) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method Renderer (line 104) | public Renderer(@NonNull final Configuration cfg) throws UserException {
    method lonToX (line 109) | private static double lonToX(final Double lon) {
    method latToY (line 113) | private static double latToY(final double lat) {
    method blendTailColor (line 117) | private static Color blendTailColor(@NonNull final Color tailColor,
    method render (line 128) | @SuppressWarnings({ "checkstyle:InnerAssignment" }) // Checkstyle 8.37...
    method calculateMinMaxValues (line 211) | private void calculateMinMaxValues(final boolean userSpecifiedWidth,
    method renderFrames (line 232) | @SuppressWarnings({ "ParameterNumber", "java:S107", "java:S3776" }) //...
    method calculateSpeedupAndReturnFrames (line 305) | private int calculateSpeedupAndReturnFrames(@NonNull final List<Render...
    method preDrawTracks (line 330) | private void preDrawTracks(@NonNull final BufferedImage bi,
    method createBufferedImage (line 337) | private BufferedImage createBufferedImage(final int width,
    method applyViewport (line 348) | private BufferedImage applyViewport(@NonNull final BufferedImage bi,
    method renderFlashback (line 394) | private float renderFlashback(final float skip,
    method drawBackground (line 407) | private void drawBackground(@NonNull final List<RendererPlugin> plugins,
    method parseGPX (line 415) | private void parseGPX(@NonNull final List<Long[]> spanList,
    method calculateRealHeight (line 449) | private int calculateRealHeight(final double scale,
    method calculateRealWidth (line 458) | private int calculateRealWidth(final boolean userSpecifiedWidth,
    method translateCoordinatesToZeroZero (line 468) | private void translateCoordinatesToZeroZero(final double scale,
    method mergeConnectedSpans (line 480) | private void mergeConnectedSpans(@NonNull final List<Long[]> spanList,
    method calculateZoomFactor (line 511) | private Integer calculateZoomFactor(@NonNull final RenderingContext rc,
    method calculateScaleFactor (line 533) | private double calculateScaleFactor(final int width,
    method trimGpxData (line 540) | private void trimGpxData(@NonNull final TreeMap<Long, Point2D> timePoi...
    method keepFrame (line 556) | private void keepFrame(@NonNull final List<RendererPlugin> plugins,
    method drawWaypoints (line 584) | private void drawWaypoints(@NonNull final BufferedImage bi,
    method createMarker (line 611) | private Ellipse2D.Double createMarker(@NonNull final Double size,
    method toTimePointMap (line 616) | private void toTimePointMap(@NonNull final TreeMap<Long, Point2D> time...
    method drawMarker (line 700) | @SuppressWarnings("PMD.AssignmentInOperand") // assignment in operand ...
    method drawSimpleCircleOnGraphics2D (line 756) | private void drawSimpleCircleOnGraphics2D(@NonNull final Point2D point,
    method drawIconOnGraphics2D (line 768) | private void drawIconOnGraphics2D(@NonNull final Point2D point,
    method drawIconFileOnGraphics2D (line 777) | private void drawIconFileOnGraphics2D(@NonNull final Point2D point,
    method drawImageOnGraphics2D (line 786) | private void drawImageOnGraphics2D(@NonNull final Point2D point,
    method paint (line 803) | @SuppressWarnings("PMD.AssignmentInOperand") // assignment in operand ...
    method getTime (line 878) | private long getTime(final int frame) {
    method printText (line 882) | private void printText(@NonNull final Graphics2D g2,
    class NamedPoint (line 909) | @Data
    class RemainingTimeCalculator (line 917) | private static class RemainingTimeCalculator {
      method RemainingTimeCalculator (line 926) | RemainingTimeCalculator(@NonNull final LocalDateTime renderStartTime,
      method getSecondsLeft (line 933) | private String getSecondsLeft(final int frame) {

FILE: src/main/java/app/gpx_animator/core/renderer/RenderingContext.java
  type RenderingContext (line 18) | public interface RenderingContext {
    method setProgress1 (line 20) | void setProgress1(int pct, String message);
    method isCancelled1 (line 22) | boolean isCancelled1();

FILE: src/main/java/app/gpx_animator/core/renderer/TextRenderer.java
  class TextRenderer (line 35) | public abstract class TextRenderer extends ImageRenderer {
    method TextRenderer (line 45) | protected TextRenderer(@NonNull final Font font) {
    method getFontMetrics (line 50) | private FontMetrics getFontMetrics() {
    method calculateTextWidth (line 57) | private int calculateTextWidth(@NonNull final String text) {
    method calculateTextHeight (line 67) | private int calculateTextHeight(@NonNull final String text) {
    method renderText (line 80) | public void renderText(@NonNull final String text, @NonNull final Posi...
    method calculateHorizontalPosition (line 118) | private int calculateHorizontalPosition(@NonNull final TextAlignment a...
    method calculateVerticalPosition (line 126) | private int calculateVerticalPosition(final int lineNum, final int lin...
    type TextAlignment (line 130) | public enum TextAlignment {
      method forPosition (line 134) | public static TextAlignment forPosition(@NonNull final Position posi...

FILE: src/main/java/app/gpx_animator/core/renderer/cache/TileCache.java
  class TileCache (line 37) | public final class TileCache {
    method TileCache (line 44) | private TileCache() throws InstantiationException {
    method ageCache (line 65) | public static void ageCache() {
    method ageCache (line 69) | private static void ageCache(final long tileCacheTimeLimit) {
    method clear (line 88) | public static void clear() {
    method getSize (line 92) | public static long getSize() {
    method getTile (line 108) | public static BufferedImage getTile(final String url, final String use...
    method unCachedGetTile (line 125) | private static BufferedImage unCachedGetTile(final String url, final S...
    method cachedGetTile (line 145) | private static BufferedImage cachedGetTile(final String url, final Str...
    method cachingEnabled (line 200) | private static boolean cachingEnabled(final String tileCachePath) {
    method ageCacheFile (line 221) | private static void ageCacheFile(final File cacheFile, final Long tile...
    method hashName (line 234) | private static String hashName(final String url) throws UserException {
    method bytesToHex (line 245) | private static String bytesToHex(final byte... hash) {

FILE: src/main/java/app/gpx_animator/core/renderer/framewriter/FileFrameWriter.java
  class FileFrameWriter (line 31) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method FileFrameWriter (line 42) | public FileFrameWriter(final String frameFilePattern, final String ima...
    method addFrame (line 53) | @Override
    method close (line 64) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/framewriter/FrameWriter.java
  type FrameWriter (line 22) | public interface FrameWriter {
    method addFrame (line 24) | void addFrame(BufferedImage bi) throws UserException;
    method close (line 26) | void close();

FILE: src/main/java/app/gpx_animator/core/renderer/framewriter/NullFrameWriter.java
  class NullFrameWriter (line 22) | public class NullFrameWriter implements FrameWriter {
    method addFrame (line 24) | @Override
    method close (line 27) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/framewriter/VideoFrameWriter.java
  class VideoFrameWriter (line 36) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method VideoFrameWriter (line 44) | public VideoFrameWriter(@NonNull final File file, @NonNull final Video...
    method addFrame (line 82) | @Override
    method close (line 101) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/AttributionPlugin.java
  class AttributionPlugin (line 30) | @SuppressWarnings("unused")
    method AttributionPlugin (line 37) | public AttributionPlugin(@NonNull final Configuration configuration) {
    method getOrder (line 51) | @Override
    method renderFrame (line 56) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundColorPlugin.java
  class BackgroundColorPlugin (line 27) | @SuppressWarnings("unused")
    method BackgroundColorPlugin (line 32) | public BackgroundColorPlugin(@NonNull final Configuration configuratio...
    method getOrder (line 36) | @Override
    method renderBackground (line 41) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundImagePlugin.java
  class BackgroundImagePlugin (line 30) | @SuppressWarnings("unused")
    method BackgroundImagePlugin (line 35) | public BackgroundImagePlugin(@NonNull final Configuration configuratio...
    method getOrder (line 48) | @Override
    method renderBackground (line 53) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundMapPlugin.java
  class BackgroundMapPlugin (line 35) | @SuppressWarnings("unused")
    method BackgroundMapPlugin (line 57) | public BackgroundMapPlugin(@NonNull final Configuration configuration) {
    method setMetadata (line 64) | @Override
    method setRenderingContext (line 73) | @Override
    method getOrder (line 79) | @Override
    method renderBackground (line 84) | @Override
    method yToTileY (line 156) | private static double yToTileY(final int zoom, final double minY) {
    method xToTileX (line 161) | private static double xToTileX(final int zoom, final double minX) {
    method lonToTileX (line 166) | private static double lonToTileX(final int zoom, final double lon) {
    method latToTileY (line 171) | private static double latToTileY(final int zoom, final double lat) {
    method xToLon (line 176) | private static double xToLon(final double x) {
    method yToLat (line 181) | private static double yToLat(final double y) {

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/CommentPlugin.java
  class CommentPlugin (line 29) | @SuppressWarnings("unused")
    method CommentPlugin (line 37) | public CommentPlugin(@NonNull final Configuration configuration) {
    method getOrder (line 43) | @Override
    method renderFrame (line 48) | @Override
    method getCommentString (line 67) | private String getCommentString(@Nullable final Point2D marker) {

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/InformationPlugin.java
  class InformationPlugin (line 37) | @SuppressWarnings("unused")
    method InformationPlugin (line 57) | public InformationPlugin(@NonNull final Configuration configuration) {
    method setMetadata (line 69) | @Override
    method getOrder (line 76) | @Override
    method renderFrame (line 81) | @Override
    method getLatLonString (line 120) | private String getLatLonString(@NonNull final Point2D point) {
    method getSpeedString (line 129) | public String getSpeedString(final Point2D point, final long time, fin...
    method getTime (line 144) | private long getTime(@NonNull final Point2D point) {
    method calculateSpeedForDisplay (line 152) | private double calculateSpeedForDisplay(final GpxPoint point, final lo...
    method calculateSpeed (line 170) | private double calculateSpeed(final GpxPoint point, final long time) {

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/LogoPlugin.java
  class LogoPlugin (line 31) | @SuppressWarnings("unused")
    method LogoPlugin (line 38) | public LogoPlugin(@NonNull final Configuration configuration) throws U...
    method getOrder (line 54) | @Override
    method renderFrame (line 59) | @Override

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/PhotoPlugin.java
  class PhotoPlugin (line 60) | @SuppressWarnings("unused")
    method PhotoPlugin (line 87) | public PhotoPlugin(@NonNull final Configuration configuration) {
    method setMetadata (line 95) | @Override
    method setFrameWriter (line 100) | @Override
    method setRenderingContext (line 106) | @Override
    method loadPhotos (line 112) | private Map<Long, List<Photo>> loadPhotos(@Nullable final File directo...
    method toPhoto (line 137) | @SuppressFBWarnings("DCN_NULLPOINTER_EXCEPTION")
    method getOrientation (line 149) | private static int getOrientation(@NonNull final com.drew.metadata.Met...
    method timeOfPhotoInMilliSeconds (line 158) | private static Long timeOfPhotoInMilliSeconds(@NonNull final com.drew....
    method validatePhotoTime (line 169) | private boolean validatePhotoTime(@NonNull final Photo photo) {
    method getOrder (line 182) | @Override
    method getAdditionalFrameCount (line 187) | @Override
    method renderFrame (line 197) | @Override
    method renderPhoto (line 213) | private void renderPhoto(@NonNull final Photo photo, @NonNull final Bu...
    method readPhoto (line 248) | private BufferedImage readPhoto(@NonNull final Photo photo, final int ...
    method renderFreezeFramesBefore (line 265) | private void renderFreezeFramesBefore(@NonNull final BufferedImage fra...
    method renderAnimationIn (line 274) | private void renderAnimationIn(@NonNull final BufferedImage frameImage...
    method renderAnimationOut (line 284) | private void renderAnimationOut(@NonNull final BufferedImage frameImag...
    method renderFreezeFramesAfter (line 294) | private void renderFreezeFramesAfter(@NonNull final BufferedImage fram...
    method renderAnimation (line 303) | private void renderAnimation(@NonNull final BufferedImage frameImage, ...
    method addBorder (line 325) | private static BufferedImage addBorder(@NonNull final BufferedImage ph...

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/PreviewPlugin.java
  class PreviewPlugin (line 34) | @SuppressWarnings("unused")
    method PreviewPlugin (line 48) | public PreviewPlugin(@NonNull final Configuration configuration) {
    method getOrder (line 52) | @Override
    method renderFrame (line 57) | @Override
    method renderingFinished (line 84) | @Override
    method renderingCanceled (line 91) | @Override
    method dialogClosed (line 96) | public void dialogClosed() {
    method calculateImageSize (line 100) | private void calculateImageSize(@NotNull final BufferedImage image) {

FILE: src/main/java/app/gpx_animator/core/renderer/plugins/RendererPlugin.java
  type RendererPlugin (line 44) | public interface RendererPlugin {
    method getOrder (line 55) | default int getOrder() {
    method getAdditionalFrameCount (line 69) | default int getAdditionalFrameCount() {
    method setMetadata (line 78) | default void setMetadata(final @NonNull Metadata metadata) { }
    method setFrameWriter (line 86) | default void setFrameWriter(final @NonNull FrameWriter frameWriter) { }
    method setRenderingContext (line 93) | default void setRenderingContext(final @NonNull RenderingContext rende...
    method renderBackground (line 105) | default void renderBackground(final @NonNull BufferedImage image) thro...
    method renderFrame (line 116) | @SuppressWarnings("RedundantThrows") // implementations throw this exc...
    method renderingFinished (line 124) | @SuppressWarnings("RedundantThrows") // implementations throw this exc...
    method renderingCanceled (line 132) | @SuppressWarnings("RedundantThrows") // implementations throw this exc...

FILE: src/main/java/app/gpx_animator/core/util/DateUtil.java
  class DateUtil (line 24) | public final class DateUtil {
    method DateUtil (line 35) | private DateUtil() throws InstantiationException {
    method parseZonedDateTime (line 39) | public static @NonNull ZonedDateTime parseZonedDateTime(@NonNull final...

FILE: src/main/java/app/gpx_animator/core/util/FormatUtil.java
  class FormatUtil (line 20) | public final class FormatUtil {
    method FormatUtil (line 22) | private FormatUtil() throws InstantiationException {
    method readableFileSize (line 27) | public static String readableFileSize(final long size) {

FILE: src/main/java/app/gpx_animator/core/util/MapUtil.java
  class MapUtil (line 47) | public final class MapUtil {
    method MapUtil (line 51) | private MapUtil() throws InstantiationException {
    method getMapPath (line 55) | private static Path getMapPath() {
    method hasNoMaps (line 59) | public static boolean hasNoMaps() {
    method updateMaps (line 63) | @SuppressWarnings("PMD.CloseResource") // false positive
    method touchMapFile (line 85) | public static void touchMapFile() {
    method readMaps (line 95) | public static List<MapTemplate> readMaps() {
    method getMapTemplate (line 185) | public static MapTemplate getMapTemplate(final String tmsUrlTemplate) {

FILE: src/main/java/app/gpx_animator/core/util/Notification.java
  type Notification (line 30) | public enum Notification {
    method Notification (line 45) | Notification(@NonNull final TrayIcon.MessageType type) {
    method show (line 49) | public void show(@NonNull final String title, @NonNull final String me...
    method init (line 53) | public static void init() {
    method isSupported (line 72) | public static boolean isSupported() {

FILE: src/main/java/app/gpx_animator/core/util/PluginUtil.java
  class PluginUtil (line 34) | public final class PluginUtil {
    method PluginUtil (line 39) | private PluginUtil() throws InstantiationException {
    method getAvailablePlugins (line 43) | @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") // checking parame...

FILE: src/main/java/app/gpx_animator/core/util/PointUtil.java
  class PointUtil (line 21) | public final class PointUtil {
    method PointUtil (line 23) | private PointUtil() throws InstantiationException {
    method calculateSpeed (line 26) | public static double calculateSpeed(@Nullable final GpxPoint lastPoint...
    method calculateDistance (line 44) | private static long calculateDistance(final GpxPoint point1, final Gpx...

FILE: src/main/java/app/gpx_animator/core/util/RenderUtil.java
  class RenderUtil (line 26) | public final class RenderUtil {
    method RenderUtil (line 28) | private RenderUtil() throws InstantiationException {
    method getGraphics (line 32) | public static Graphics2D getGraphics(@NonNull final BufferedImage imag...
    method getTime (line 43) | public static long getTime(final int frame, final long minTime, final ...
    method scaleImage (line 47) | public static BufferedImage scaleImage(@NonNull final BufferedImage ph...
    method rotateImage (line 65) | public static BufferedImage rotateImage(@NonNull final BufferedImage p...

FILE: src/main/java/app/gpx_animator/core/util/Sound.java
  type Sound (line 28) | public enum Sound {
    method play (line 38) | public void play() {

FILE: src/main/java/app/gpx_animator/core/util/Utils.java
  class Utils (line 24) | public final class Utils {
    method Utils (line 28) | private Utils() throws InstantiationException {
    method deepCopy (line 33) | public static BufferedImage deepCopy(final BufferedImage bi) {
    method isEqual (line 41) | @SuppressWarnings({"PMD.CompareObjectsWithEquals", "PMD.UseEqualsToCom...

FILE: src/main/java/app/gpx_animator/ui/UIMode.java
  type UIMode (line 20) | public enum UIMode {
    method setMode (line 27) | @SuppressWarnings("java:S3066")
    method getMode (line 32) | public static UIMode getMode() {

FILE: src/main/java/app/gpx_animator/ui/cli/CommandLineConfigurationFactory.java
  class CommandLineConfigurationFactory (line 53) | @SuppressWarnings("PMD.BeanMembersShouldSerialize") // This class is not...
    method CommandLineConfigurationFactory (line 75) | @SuppressWarnings({
    method exit (line 267) | @SuppressWarnings({"PMD.DoNotTerminateVM", "DuplicateStringLiteralInsp...
    method normalizeColors (line 272) | private void normalizeColors() {
    method normalizePreDrawTrackColors (line 286) | private void normalizePreDrawTrackColors() {
    method normalizeLineWidths (line 300) | private void normalizeLineWidths() {
    method normalizePreDrawLineWidths (line 304) | private void normalizePreDrawLineWidths() {
    method normalizeLineWidths (line 308) | private static void normalizeLineWidths(@NotNull final List<String> in...
    method normalizeTrackIcons (line 323) | private void normalizeTrackIcons() {
    method normalizeInputIcons (line 337) | private void normalizeInputIcons() {
    method normalizeMirrorTrackIcons (line 351) | private void normalizeMirrorTrackIcons() {
    method normalizeTrimGpxStart (line 365) | private void normalizeTrimGpxStart() {
    method normalizeTrimGpxEnd (line 369) | private void normalizeTrimGpxEnd() {
    method normalizeTrimGpx (line 373) | private static void normalizeTrimGpx(@NotNull final List<String> input...
    method checkVersion (line 388) | private static String checkVersion(@NotNull final ResourceBundle resou...
    method getConfiguration (line 416) | public Configuration getConfiguration() {
    method isGui (line 421) | public boolean isGui() {

FILE: src/main/java/app/gpx_animator/ui/swing/ColorSelector.java
  class ColorSelector (line 33) | public final class ColorSelector extends JPanel {
    method ColorSelector (line 50) | public ColorSelector() {
    method getColor (line 78) | public Color getColor() {
    method setColor (line 82) | public void setColor(final Color color) {
    method getToolTipText (line 91) | @Override
    method setToolTipText (line 96) | @Override
    method setEnabled (line 102) | @Override

FILE: src/main/java/app/gpx_animator/ui/swing/DurationEditor.java
  class DurationEditor (line 28) | public class DurationEditor extends DefaultEditor {
    method DurationEditor (line 33) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")

FILE: src/main/java/app/gpx_animator/ui/swing/DurationFormatter.java
  class DurationFormatter (line 23) | class DurationFormatter extends JFormattedTextField.AbstractFormatter {
    method valueToString (line 28) | @Override
    method stringToValue (line 38) | @Override
    method isValid (line 74) | private boolean isValid(final Object value) {
    method getDurationAsText (line 78) | private String getDurationAsText(final long duration) {

FILE: src/main/java/app/gpx_animator/ui/swing/DurationSpinnerModel.java
  class DurationSpinnerModel (line 24) | public final class DurationSpinnerModel extends AbstractSpinnerModel {
    method getValue (line 32) | @Override
    method setValue (line 37) | @Override
    method getNextValue (line 45) | @Override
    method getPreviousValue (line 50) | @Override
    method getField (line 55) | public Field getField() {
    method setField (line 59) | public void setField(final Field field) {
    method getDiffMs (line 63) | @SuppressWarnings({ "PMD.ImplicitSwitchFallThrough", "PMD.MissingBreak...
    type Field (line 84) | public enum Field {
      method Field (line 93) | Field(final String unit) {
      method fromUnit (line 97) | public static Field fromUnit(@NonNls final String unit) {
      method getUnit (line 106) | public String getUnit() {

FILE: src/main/java/app/gpx_animator/ui/swing/EmptyNullSpinnerModel.java
  class EmptyNullSpinnerModel (line 24) | public final class EmptyNullSpinnerModel extends AbstractSpinnerModel {
    method EmptyNullSpinnerModel (line 39) | public EmptyNullSpinnerModel(final Number value, final Number minimum,...
    method EmptyNullSpinnerModel (line 43) | public EmptyNullSpinnerModel(final Number value, final Number minimum,...
    method getNextValue (line 69) | @Override
    method getPreviousValue (line 74) | @Override
    method incrValue (line 79) | private Number incrValue(final int dir) {
    method round (line 112) | private double round(final double doubleValue) {
    method getValue (line 116) | @Override
    method setValue (line 121) | @Override
    method compareTo (line 151) | public int compareTo(final Number n1, final Number n2) {
    method setMaximum (line 157) | public void setMaximum(@Nullable final Number maximum) {

FILE: src/main/java/app/gpx_animator/ui/swing/EmptyZeroNumberEditor.java
  class EmptyZeroNumberEditor (line 27) | public class EmptyZeroNumberEditor extends DefaultEditor {
    method EmptyZeroNumberEditor (line 32) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")

FILE: src/main/java/app/gpx_animator/ui/swing/ErrorDialog.java
  class ErrorDialog (line 45) | public class ErrorDialog extends JDialog {
    method ErrorDialog (line 55) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
    method buildContent (line 69) | private JComponent buildContent() {
    method getStackTrace (line 104) | private String getStackTrace(@Nullable final Exception exception) {
    method copyMessage (line 115) | private void copyMessage() {
    method closeDialog (line 121) | private void closeDialog() {

FILE: src/main/java/app/gpx_animator/ui/swing/EscapeDialog.java
  class EscapeDialog (line 36) | abstract class EscapeDialog extends JDialog {
    method EscapeDialog (line 42) | EscapeDialog(@NonNull final JFrame owner) {
    method setContentPane (line 46) | @Override
    method createRootPane (line 51) | @Override

FILE: src/main/java/app/gpx_animator/ui/swing/FileSelector.java
  class FileSelector (line 33) | public abstract class FileSelector extends JPanel {
    method FileSelector (line 50) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
    method configure (line 118) | protected abstract Type configure(JFileChooser gpxFileChooser);
    method transformFilename (line 127) | protected String transformFilename(final String filename) {
    method getFilename (line 131) | public final String getFilename() {
    method setFilename (line 135) | public final void setFilename(final String filename) {
    method getToolTipText (line 139) | @Override
    method setToolTipText (line 144) | @Override
    type Type (line 150) | public enum Type {
    method getFile (line 154) | public final File getFile() {

FILE: src/main/java/app/gpx_animator/ui/swing/FontChooser.java
  class FontChooser (line 70) | public final class FontChooser extends JComponent {
    method FontChooser (line 129) | public FontChooser() {
    method FontChooser (line 138) | public FontChooser(final String... fontSizeStrings) {
    method getFontFamilyTextField (line 158) | private JTextField getFontFamilyTextField() {
    method getFontStyleTextField (line 172) | private JTextField getFontStyleTextField() {
    method getFontSizeTextField (line 185) | private JTextField getFontSizeTextField() {
    method getFontFamilyList (line 198) | private JList<String> getFontFamilyList() {
    method getFontStyleList (line 210) | private JList<String> getFontStyleList() {
    method getFontSizeList (line 222) | private JList<String> getFontSizeList() {
    method getSelectedFontFamily (line 240) | public String getSelectedFontFamily() {
    method getSelectedFontStyle (line 255) | public int getSelectedFontStyle() {
    method getSelectedFontSize (line 266) | public int getSelectedFontSize() {
    method getSelectedFont (line 289) | public Font getSelectedFont() {
    method setSelectedFontFamily (line 301) | public void setSelectedFontFamily(@NonNull final String name) {
    method setSelectedFontStyle (line 324) | public void setSelectedFontStyle(final int style) {
    method setSelectedFontSize (line 340) | public void setSelectedFontSize(final int size) {
    method setSelectedFont (line 359) | public void setSelectedFont(final Font font) {
    method showDialog (line 374) | public int showDialog(final Component parent) {
    class ListSelectionHandler (line 391) | class ListSelectionHandler implements ListSelectionListener {
      method ListSelectionHandler (line 395) | ListSelectionHandler(final JTextComponent textComponent) {
      method valueChanged (line 399) | @Override
    class TextFieldFocusHandlerForTextSelection (line 417) | class TextFieldFocusHandlerForTextSelection extends FocusAdapter {
      method TextFieldFocusHandlerForTextSelection (line 421) | TextFieldFocusHandlerForTextSelection(final JTextComponent textCompo...
      method focusGained (line 425) | @Override
      method focusLost (line 430) | @Override
    class TextFieldKeyHandlerForListSelectionUpDown (line 437) | static class TextFieldKeyHandlerForListSelectionUpDown extends KeyAdap...
      method TextFieldKeyHandlerForListSelectionUpDown (line 441) | TextFieldKeyHandlerForListSelectionUpDown(final JList<String> list) {
      method keyPressed (line 445) | @Override
    class ListSearchTextFieldDocumentHandler (line 469) | @SuppressWarnings("ClassCanBeRecord") // in my opinion this should not...
      method ListSearchTextFieldDocumentHandler (line 474) | ListSearchTextFieldDocumentHandler(final JList<String> targetList) {
      method insertUpdate (line 478) | @Override
      method removeUpdate (line 483) | @Override
      method changedUpdate (line 488) | @Override
      method update (line 493) | private void update(final DocumentEvent event) {
      class ListSelector (line 516) | public class ListSelector implements Runnable {
        method ListSelector (line 520) | ListSelector(final int index) {
        method run (line 524) | @Override
    class DialogOKAction (line 531) | class DialogOKAction extends AbstractAction {
      method DialogOKAction (line 538) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
      method actionPerformed (line 546) | @Override
    class DialogCancelAction (line 553) | class DialogCancelAction extends AbstractAction {
      method DialogCancelAction (line 560) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
      method actionPerformed (line 568) | @Override
    method createDialog (line 575) | private JDialog createDialog(final Component parent) {
    method updateSampleFont (line 610) | private void updateSampleFont() {
    method getFontFamilyPanel (line 615) | private JPanel getFontFamilyPanel() {
    method getFontStylePanel (line 644) | private JPanel getFontStylePanel() {
    method getFontSizePanel (line 672) | private JPanel getFontSizePanel() {
    method getSamplePanel (line 700) | private JPanel getSamplePanel() {
    method getSampleTextField (line 716) | private JTextField getSampleTextField() {
    method getFontFamilies (line 727) | private String[] getFontFamilies() {
    method getFontStyleNames (line 735) | @SuppressWarnings("PMD.AssignmentInOperand") // assignment in operand ...

FILE: src/main/java/app/gpx_animator/ui/swing/FontSelector.java
  class FontSelector (line 33) | public final class FontSelector extends JPanel {
    method FontSelector (line 47) | public FontSelector() {
    method getSelectedFont (line 76) | public Font getSelectedFont() {
    method setSelectedFont (line 80) | public void setSelectedFont(@Nullable final Font selectedFont) {
    method getStyleText (line 93) | private static String getStyleText(@NonNull final Font font, @NonNull ...

FILE: src/main/java/app/gpx_animator/ui/swing/GeneralSettingsPanel.java
  class GeneralSettingsPanel (line 76) | abstract class GeneralSettingsPanel extends JPanel {
    method GeneralSettingsPanel (line 151) | @SuppressWarnings({
    method checkAttributionMandatory (line 1460) | private void checkAttributionMandatory(@Nullable final Object position...
    method updateMaps (line 1483) | public void updateMaps(@NotNull final List<MapTemplate> newMapTemplate...
    method createImageFileSelector (line 1489) | private FileSelector createImageFileSelector() {
    method createInputMusicSelector (line 1512) | private FileSelector createInputMusicSelector() {
    method setVideoSize (line 1528) | private void setVideoSize(final Integer width, final Integer height) {
    method setViewportSize (line 1533) | private void setViewportSize(final Integer width, final Integer height) {
    method setConfiguration (line 1538) | public void setConfiguration(final Configuration c) {
    method buildConfiguration (line 1621) | public void buildConfiguration(final Configuration.Builder builder, fi...
    method generateAttributionText (line 1684) | private String generateAttributionText(final boolean replacePlaceholde...
    method configurationChanged (line 1697) | protected abstract void configurationChanged();

FILE: src/main/java/app/gpx_animator/ui/swing/JPlaceholderTextField.java
  class JPlaceholderTextField (line 25) | public final class JPlaceholderTextField extends JTextField {
    method JPlaceholderTextField (line 34) | public JPlaceholderTextField() {
    method paintComponent (line 38) | @Override
    method setPlaceholder (line 56) | public void setPlaceholder(final String s) {

FILE: src/main/java/app/gpx_animator/ui/swing/MainFrame.java
  class MainFrame (line 91) | public final class MainFrame extends JFrame {
    class InstanceHolder (line 118) | private static final class InstanceHolder {
    method getInstance (line 122) | public static MainFrame getInstance() {
    method MainFrame (line 126) | @SuppressWarnings("checkstyle:MethodLength") // TODO Refactor when doi...
    method render (line 452) | private void render(@NonNull final JProgressBar progressBar, final boo...
    method exitApplication (line 574) | @SuppressWarnings({"PMD.DoNotTerminateVM", "DuplicateStringLiteralInsp...
    method createConfiguration (line 582) | public Configuration createConfiguration(final boolean includeTracks, ...
    method setConfiguration (line 598) | public void setConfiguration(final Configuration c) {
    method pupulateOpenRecentMenu (line 614) | @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") // maximum of 10 i...
    method openFile (line 629) | private void openFile(final File fileToOpen) {
    method addRecentFile (line 647) | private void addRecentFile(final File recentFile) {
    method setChanged (line 653) | private synchronized void setChanged(final boolean changed) {
    method updateTitle (line 658) | private void updateTitle() {
    method addTrackSettingsTab (line 663) | void addTrackSettingsTab(final TrackConfiguration tc) {
    method afterRemove (line 698) | private void afterRemove() {
    method saveAs (line 706) | private void saveAs() {
    method save (line 721) | private void save(final File fileToSave) {
    method saveAsDefault (line 742) | private void saveAsDefault() {
    method loadDefaults (line 760) | private void loadDefaults() {
    method resetDefaults (line 782) | private void resetDefaults() {
    method showChangelog (line 794) | private void showChangelog() {
    method showChangelogOnce (line 800) | private void showChangelogOnce() {
    method checkMapData (line 807) | private void checkMapData() {
    class TrackActionListener (line 818) | @SuppressFBWarnings(value = "DMI_RANDOM_USED_ONLY_ONCE", justification...
      method TrackActionListener (line 824) | TrackActionListener(@NotNull final MainFrame mainFrame, @NotNull fin...
      method actionPerformed (line 831) | @Override
    class MapLoader (line 864) | static class MapLoader extends SwingWorker<List<MapTemplate>, Void> {
      method MapLoader (line 870) | MapLoader(@NotNull final MainFrame mainFrame,
      method doInBackground (line 879) | @Override
      method done (line 884) | @Override

FILE: src/main/java/app/gpx_animator/ui/swing/MarkdownDialog.java
  class MarkdownDialog (line 48) | public class MarkdownDialog extends EscapeDialog {
    method MarkdownDialog (line 96) | public MarkdownDialog(final JFrame owner, final String title,
    method MarkdownDialog (line 102) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
    method buildContent (line 118) | private JComponent buildContent() {
    method handleLinkClicked (line 143) | private void handleLinkClicked(@NotNull final HyperlinkEvent event) {
    method copyContent (line 154) | private void copyContent() {
    method closeDialog (line 158) | private void closeDialog() {
    method parseVariables (line 163) | private String parseVariables() {
    method readFileAsHTML (line 172) | private String readFileAsHTML() {
    method convertMarkdownToHTML (line 177) | private String convertMarkdownToHTML(final String md) {

FILE: src/main/java/app/gpx_animator/ui/swing/MarkdownFileDialog.java
  class MarkdownFileDialog (line 31) | public class MarkdownFileDialog extends MarkdownDialog {
    method MarkdownFileDialog (line 36) | public MarkdownFileDialog(final JFrame owner, final String title,
    method MarkdownFileDialog (line 42) | public MarkdownFileDialog(final JFrame owner, final String title,
    method readFileAsMarkdown (line 49) | private static String readFileAsMarkdown(@NonNull final String filenam...

FILE: src/main/java/app/gpx_animator/ui/swing/PreferencesDialog.java
  class PreferencesDialog (line 39) | public class PreferencesDialog extends EscapeDialog {
    method PreferencesDialog (line 44) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")

FILE: src/main/java/app/gpx_animator/ui/swing/PreviewDialog.java
  class PreviewDialog (line 34) | public final class PreviewDialog extends JDialog {
    method PreviewDialog (line 42) | public PreviewDialog(@NonNull final PreviewPlugin plugin, @NonNull fin...
    method updatePreview (line 64) | public void updatePreview(@NonNull final BufferedImage image) {
    method closeDialog (line 71) | public void closeDialog() {

FILE: src/main/java/app/gpx_animator/ui/swing/ProtocolDialog.java
  class ProtocolDialog (line 18) | public class ProtocolDialog extends MarkdownDialog {
    method ProtocolDialog (line 25) | public ProtocolDialog(final JFrame owner, final int width, final int h...
    method getMarkdown (line 29) | private static String getMarkdown() {
    method readFile (line 34) | private static Stream<String> readFile() {

FILE: src/main/java/app/gpx_animator/ui/swing/TrackSettingsPanel.java
  class TrackSettingsPanel (line 51) | abstract class TrackSettingsPanel extends JPanel {
    method TrackSettingsPanel (line 76) | @SuppressWarnings({
    method configureGpxFileChooser (line 482) | public static void configureGpxFileChooser(final ResourceBundle resour...
    method configureIconFileChooser (line 513) | public static void configureIconFileChooser(final ResourceBundle resou...
    method labelChanged (line 532) | protected abstract void labelChanged(String label);
    method createConfiguration (line 535) | public TrackConfiguration createConfiguration() {
    method setConfiguration (line 558) | public void setConfiguration(final TrackConfiguration c) {
    method remove (line 579) | protected abstract void remove();
    method configurationChanged (line 581) | protected abstract void configurationChanged();

FILE: src/main/java/app/gpx_animator/ui/swing/UsageDialog.java
  class UsageDialog (line 35) | public class UsageDialog extends EscapeDialog {
    method UsageDialog (line 43) | @SuppressWarnings("PMD.ConstructorCallsOverridableMethod")

FILE: src/test/java/app/gpx_animator/MemoryAppender.java
  class MemoryAppender (line 10) | public final class MemoryAppender extends ListAppender<ILoggingEvent> {
    method reset (line 12) | public void reset() {
    method search (line 16) | public List<ILoggingEvent> search(final String string, final Level lev...
    method searchFormattedMessages (line 23) | public List<ILoggingEvent> searchFormattedMessages(final String string...

FILE: src/test/java/app/gpx_animator/MissingTranslationsTest.java
  class MissingTranslationsTest (line 16) | public final class MissingTranslationsTest {
    method beforeAllTests (line 22) | @BeforeAll
    method checkBundle (line 33) | private void checkBundle(final Properties bundle, final String code) {
    method english (line 40) | @Test
    method german (line 45) | @Test

FILE: src/test/java/app/gpx_animator/core/configuration/adapter/FontXmlAdapterTest.java
  class FontXmlAdapterTest (line 12) | class FontXmlAdapterTest {
    method testMarshal (line 14) | @Test
    method testUnmarshal (line 21) | @Test

FILE: src/test/java/app/gpx_animator/core/data/SpeedUnitTest.java
  class SpeedUnitTest (line 7) | class SpeedUnitTest {
    method testKilometersPerHour (line 9) | @Test
    method testMilesPerHour (line 17) | @Test
    method testMinutesPerKilometer (line 25) | @Test
    method testMinutesPer500Meter (line 34) | @Test
    method testMinutesPerMile (line 43) | @Test
    method testKnots (line 52) | @Test

FILE: src/test/java/app/gpx_animator/core/data/gpx/GpxContentHandlerTest.java
  class GpxContentHandlerTest (line 13) | class GpxContentHandlerTest {
    method testCommentParsing (line 15) | @Test

FILE: src/test/java/app/gpx_animator/core/renderer/plugins/PhotoPluginTest.java
  class PhotoPluginTest (line 10) | class PhotoPluginTest {
    method toPhotoWithUpsideDownImage (line 12) | @Test

FILE: src/test/java/app/gpx_animator/core/util/DateUtilTest.java
  class DateUtilTest (line 12) | class DateUtilTest {
    method parseZonedDateTime (line 14) | @Test
    method parseZonedDateTimeException (line 26) | @Test

FILE: src/test/java/app/gpx_animator/core/util/PointUtilTest.java
  class PointUtilTest (line 24) | class PointUtilTest {
    method calculateSpeedWhenFirstPointIsNull (line 26) | @Test
    method calculateSpeedWhenTimeIsEquals (line 33) | @Test
    method calculateSpeedWhenPointsIsNotEquals (line 42) | @Test

FILE: src/test/java/app/gpx_animator/core/util/RenderUtilTest.java
  class RenderUtilTest (line 20) | class RenderUtilTest {
    method testRotateImageWith180Degrees (line 22) | @Test
    method testRotateImage (line 36) | @ParameterizedTest(name = "orientation {0} should rotate by {1} degree...
    method testRotateImage (line 57) | private static Stream<Arguments> testRotateImage() {
    method rotateImage (line 70) | private BufferedImage rotateImage(final BufferedImage originalImage, f...
    method flipImage (line 99) | private BufferedImage flipImage(final BufferedImage originalImage, fin...
    type FlipDirection (line 117) | private enum FlipDirection {
    type RotateByDegrees (line 122) | private enum RotateByDegrees {
      method RotateByDegrees (line 129) | RotateByDegrees(final double degrees) {
      method getDegrees (line 133) | public double getDegrees() {

FILE: src/test/java/app/gpx_animator/core/util/UtilsTest.java
  class UtilsTest (line 8) | class UtilsTest {
    method isEqual (line 10) | @Test

FILE: src/test/java/app/gpx_animator/ui/cli/CommandLineConfigurationFactoryTest.java
  class CommandLineConfigurationFactoryTest (line 30) | class CommandLineConfigurationFactoryTest {
    method checkInputParamsByOptionParams (line 35) | @ParameterizedTest
    method testOutputWhenInputIsSet (line 56) | @Test
    method testMultipleInputParams (line 68) | @Test

FILE: src/test/java/app/gpx_animator/ui/cli/CommandLineIT.java
  class CommandLineIT (line 25) | final class CommandLineIT {
    method checkFileSeparator (line 30) | private String checkFileSeparator(@SuppressWarnings("SameParameterValu...
    method getTemporaryOutputFile (line 36) | private String getTemporaryOutputFile() throws IOException {
    method assertDone (line 42) | private void assertDone() {
    method beforeEachTest (line 47) | @BeforeEach
    method testBasicCommandLine (line 60) | @Test
    method testPhotoPluginThroughCommandLine (line 76) | @Test
    method afterEachTest (line 112) | @AfterEach

FILE: src/test/java/app/gpx_animator/ui/cli/OptionParam.java
  type OptionParam (line 35) | @Getter
    method OptionParam (line 338) | OptionParam(final Option option,
    method ofOption (line 348) | public static OptionParam ofOption(final Option option) {
    method getFirstTrackConfiguration (line 357) | private static TrackConfiguration getFirstTrackConfiguration(final Com...

FILE: src/test/java/app/gpx_animator/ui/swing/DurationFormatterTest.java
  class DurationFormatterTest (line 13) | class DurationFormatterTest {
    method generateTestData (line 19) | private static Stream<Arguments> generateTestData() {
    method stringToValue (line 30) | @ParameterizedTest
    method valueToString (line 41) | @ParameterizedTest

FILE: src/test/java/app/gpx_animator/ui/swing/DurationSpinnerModelTest.java
  class DurationSpinnerModelTest (line 13) | final class DurationSpinnerModelTest {
    method generateGetterSetterTestData (line 15) | private static Stream<Arguments> generateGetterSetterTestData() {
    method testValue (line 26) | @ParameterizedTest
    method testField (line 34) | @ParameterizedTest
    method testFromUnit (line 42) | @Test
Condensed preview — 140 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,340K chars).
[
  {
    "path": ".all-contributorsrc",
    "chars": 9942,
    "preview": "{\n  \"projectName\": \"gpx-animator\",\n  \"projectOwner\": \"gpx-animator\",\n  \"repoType\": \"github\",\n  \"repoHost\": \"https://gith"
  },
  {
    "path": ".editorconfig",
    "chars": 27976,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\nmax_l"
  },
  {
    "path": ".fleet/run.json",
    "chars": 138,
    "preview": "{\n  \"configurations\": [\n    {\n      \"name\": \"run gpx-animator\",\n      \"type\": \"gradle\",\n      \"tasks\": [\n        \"run\"\n "
  },
  {
    "path": ".fleet/settings.json",
    "chars": 37,
    "preview": "{\n    \"backend.maxHeapSizeMb\": 2048\n}"
  },
  {
    "path": ".gitattributes",
    "chars": 35,
    "preview": "*.bat text eol=crlf\ngradlew eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "chars": 962,
    "preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "chars": 604,
    "preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees: ''\n\n---\n\n**Is"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 169,
    "preview": "version: 2\nupdates:\n  - package-ecosystem: \"Gradle\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n      time:"
  },
  {
    "path": ".github/workflows/add-to-project.yml",
    "chars": 464,
    "preview": "name: Adds all issues to project board\n\non:\n  issues:\n    types:\n      - opened\n  pull_request_target:\n    types:\n      "
  },
  {
    "path": ".github/workflows/gradle.yml",
    "chars": 631,
    "preview": "name: Java CI with Gradle\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:"
  },
  {
    "path": ".gitignore",
    "chars": 568,
    "preview": "# Gradle build system\n/.gradle\n\n# Build artefacts\n/bin\n/build\n/out\n/target\n\n# Yarn/Node/NPM\n/node_modules\n\n# Eclipse pro"
  },
  {
    "path": ".gitpod.Dockerfile",
    "chars": 440,
    "preview": "FROM gitpod/workspace-full-vnc\nUSER root\nRUN apt-get update \\\n    && bash -c \". /home/gitpod/.sdkman/bin/sdkman-init.sh "
  },
  {
    "path": ".gitpod.yml",
    "chars": 963,
    "preview": "image:\n  file: .gitpod.Dockerfile\n\ntasks:\n  - init: ./gradlew assemble\n\nports:\n  - port: 6080\n    onOpen: open-preview\n "
  },
  {
    "path": ".run/GPX Animator (de) HiDPI.run.xml",
    "chars": 1029,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"run (de_CH) HiDPI\" type=\"Gradle"
  },
  {
    "path": ".run/GPX Animator (de).run.xml",
    "chars": 905,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"run (de_CH)\" type=\"GradleRunCon"
  },
  {
    "path": ".run/GPX Animator (en) HiDPI.run.xml",
    "chars": 1029,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"run (en_US) HiDPI\" type=\"Gradle"
  },
  {
    "path": ".run/GPX Animator (en).run.xml",
    "chars": 905,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"run (en_US)\" type=\"GradleRunCon"
  },
  {
    "path": ".run/check test.run.xml",
    "chars": 939,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"check test\" type=\"GradleRunConf"
  },
  {
    "path": ".run/check.run.xml",
    "chars": 909,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"check\" type=\"GradleRunConfigura"
  },
  {
    "path": ".run/test.run.xml",
    "chars": 907,
    "preview": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"test\" type=\"GradleRunConfigurat"
  },
  {
    "path": ".sdkmanrc",
    "chars": 112,
    "preview": "# Enable auto-env through the sdkman_auto_env config\n# Add key=value pairs of SDKs to use below\njava=25.0.1-tem\n"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 11940,
    "preview": "# Changelog\n\nPlease report any bugs and feature requests via our\n[GitHub Issue Tracker](https://github.com/gpx-animator/"
  },
  {
    "path": "LICENSE.md",
    "chars": 10479,
    "preview": "Apache License\n==============\n\n_Version 2.0, January 2004_  \n_&lt;<http://www.apache.org/licenses/>&gt;_\n\n### Terms and "
  },
  {
    "path": "README.md",
    "chars": 21658,
    "preview": "# GPX Animator\n<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->\n[![All Contributors](https:/"
  },
  {
    "path": "build.gradle",
    "chars": 5212,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "config/checkstyle/checkstyle.xml",
    "chars": 8096,
    "preview": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n        \"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN\"\n        \"htt"
  },
  {
    "path": "config/pmd/pmd-rules.xml",
    "chars": 2610,
    "preview": "<?xml version=\"1.0\"?>\n<ruleset name=\"Custom Rules\"\n         xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n         xm"
  },
  {
    "path": "config/spotbugs/exclude.xml",
    "chars": 263,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FindBugsFilter>\n  <Match>\n    <!-- Check is broken and does not clearly report w"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 281,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 36,
    "preview": "org.gradle.configuration-cache=true\n"
  },
  {
    "path": "gradlew",
    "chars": 8631,
    "preview": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\")"
  },
  {
    "path": "gradlew.bat",
    "chars": 2846,
    "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": "install/gpx-animator.install4j",
    "chars": 46005,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<install4j version=\"12.0\" transformSequenceNumber=\"12\">\n  <directoryPresets confi"
  },
  {
    "path": "jitpack.yml",
    "chars": 18,
    "preview": "jdk:\n  - openjdk17"
  },
  {
    "path": "package.json",
    "chars": 69,
    "preview": "{\n  \"devDependencies\": {\n    \"all-contributors-cli\": \"^6.24.0\"\n  }\n}\n"
  },
  {
    "path": "renovate.json",
    "chars": 591,
    "preview": "{\n  \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n  \"extends\": [\n    \"config:base\",\n    \":disableDepen"
  },
  {
    "path": "settings.gradle",
    "chars": 34,
    "preview": "rootProject.name = 'gpx-animator'\n"
  },
  {
    "path": "src/main/java/app/gpx_animator/Main.java",
    "chars": 3179,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/Constants.java",
    "chars": 2437,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/Help.java",
    "chars": 9639,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/Option.java",
    "chars": 3951,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/UserException.java",
    "chars": 1011,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/Configuration.java",
    "chars": 28739,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/TrackConfiguration.java",
    "chars": 8576,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/adapter/ColorXmlAdapter.java",
    "chars": 1165,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/adapter/FileXmlAdapter.java",
    "chars": 1915,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/adapter/FontXmlAdapter.java",
    "chars": 1827,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/configuration/adapter/TrackIconXmlAdapter.java",
    "chars": 1089,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/MapTemplate.java",
    "chars": 1186,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/MusicCodec.java",
    "chars": 1842,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/Photo.java",
    "chars": 761,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/Position.java",
    "chars": 1560,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/SpeedUnit.java",
    "chars": 2851,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/TrackIcon.java",
    "chars": 3358,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/VideoCodec.java",
    "chars": 1937,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/MyPoint.java",
    "chars": 147,
    "preview": "package app.gpx_animator.core.data.entity;\n\npublic interface MyPoint {\n\n    Double getLatitude();\n    Double getLongitud"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/Track.java",
    "chars": 630,
    "preview": "package app.gpx_animator.core.data.entity;\n\nimport edu.umd.cs.findbugs.annotations.SuppressFBWarnings;\nimport lombok.All"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/TrackPoint.java",
    "chars": 1295,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/TrackSegment.java",
    "chars": 971,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/TrackType.java",
    "chars": 610,
    "preview": "package app.gpx_animator.core.data.entity;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.slf4j.Logger;\nimport or"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/entity/WayPoint.java",
    "chars": 1286,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/gpx/GPX.java",
    "chars": 903,
    "preview": "package app.gpx_animator.core.data.gpx;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.Arrays;\n\npublic enu"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/gpx/GpxContentHandler.java",
    "chars": 9416,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/gpx/GpxParser.java",
    "chars": 3694,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/data/gpx/GpxPoint.java",
    "chars": 2411,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/preferences/Preferences.java",
    "chars": 5614,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/ImageRenderer.java",
    "chars": 3023,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/Metadata.java",
    "chars": 898,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/Renderer.java",
    "chars": 41268,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/RenderingContext.java",
    "chars": 789,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/TextRenderer.java",
    "chars": 5533,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/cache/TileCache.java",
    "chars": 9644,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/framewriter/FileFrameWriter.java",
    "chars": 2672,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/framewriter/FrameWriter.java",
    "chars": 879,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/framewriter/NullFrameWriter.java",
    "chars": 950,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/framewriter/VideoFrameWriter.java",
    "chars": 5240,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/AttributionPlugin.java",
    "chars": 2448,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundColorPlugin.java",
    "chars": 1586,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundImagePlugin.java",
    "chars": 2532,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/BackgroundMapPlugin.java",
    "chars": 7069,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/CommentPlugin.java",
    "chars": 2952,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/InformationPlugin.java",
    "chars": 7332,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/LogoPlugin.java",
    "chars": 2336,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/PhotoPlugin.java",
    "chars": 16446,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/PreviewPlugin.java",
    "chars": 3589,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/renderer/plugins/RendererPlugin.java",
    "chars": 5142,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/DateUtil.java",
    "chars": 2093,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/FormatUtil.java",
    "chars": 1397,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/MapUtil.java",
    "chars": 8159,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/Notification.java",
    "chars": 2672,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/PluginUtil.java",
    "chars": 3786,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/PointUtil.java",
    "chars": 2649,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/RenderUtil.java",
    "chars": 3934,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/Sound.java",
    "chars": 1989,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/core/util/Utils.java",
    "chars": 1922,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/UIMode.java",
    "chars": 995,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/cli/CommandLineConfigurationFactory.java",
    "chars": 20948,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/ColorSelector.java",
    "chars": 3699,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/DurationEditor.java",
    "chars": 3042,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/DurationFormatter.java",
    "chars": 3059,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/DurationSpinnerModel.java",
    "chars": 2900,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/EmptyNullSpinnerModel.java",
    "chars": 5269,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/EmptyZeroNumberEditor.java",
    "chars": 2869,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/ErrorDialog.java",
    "chars": 4728,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/EscapeDialog.java",
    "chars": 2141,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/FileSelector.java",
    "chars": 5195,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/FontChooser.java",
    "chars": 26930,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/FontSelector.java",
    "chars": 3849,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/GeneralSettingsPanel.java",
    "chars": 91706,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/JPlaceholderTextField.java",
    "chars": 1928,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/MainFrame.java",
    "chars": 40124,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/MarkdownDialog.java",
    "chars": 6989,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/MarkdownFileDialog.java",
    "chars": 2427,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/PreferencesDialog.java",
    "chars": 7048,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/PreviewDialog.java",
    "chars": 2608,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/ProtocolDialog.java",
    "chars": 1744,
    "preview": "package app.gpx_animator.ui.swing;\n\nimport app.gpx_animator.core.preferences.Preferences;\nimport ch.qos.logback.classic."
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/TrackSettingsPanel.java",
    "chars": 28938,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/java/app/gpx_animator/ui/swing/UsageDialog.java",
    "chars": 3954,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/main/resources/ABOUT.md",
    "chars": 83,
    "preview": "# {{APPNAME}}\n\n## Version {{VERSION}}\n\n_{{COPYRIGHT}}_\n\n{{DESCRIPTION}}  \n{{LINK}}\n"
  },
  {
    "path": "src/main/resources/i18n/Messages.properties",
    "chars": 20373,
    "preview": "cli.error.graphics=graphics is not supported in this environment\ncli.error.number=invalid number for option '%s'\ncli.err"
  },
  {
    "path": "src/main/resources/i18n/Messages_de.properties",
    "chars": 21984,
    "preview": "cli.error.graphics=Grafische Ausgabe wird in dieser Umgebung nicht unterstützt\ncli.error.number=Ungültige Wert für Param"
  },
  {
    "path": "src/main/resources/logback.xml",
    "chars": 827,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<configuration>\n    <appender name=\"CONSOLE\" class=\"ch.qos.logback.core.ConsoleAp"
  },
  {
    "path": "src/test/java/app/gpx_animator/MemoryAppender.java",
    "chars": 925,
    "preview": "package app.gpx_animator;\n\nimport ch.qos.logback.classic.Level;\nimport ch.qos.logback.classic.spi.ILoggingEvent;\nimport "
  },
  {
    "path": "src/test/java/app/gpx_animator/MissingTranslationsTest.java",
    "chars": 1543,
    "preview": "package app.gpx_animator;\n\nimport org.junit.jupiter.api.BeforeAll;\nimport org.junit.jupiter.api.Test;\n\nimport java.io.IO"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/configuration/adapter/FontXmlAdapterTest.java",
    "chars": 916,
    "preview": "package app.gpx_animator.core.configuration.adapter;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.awt.Font;\n\nimport "
  },
  {
    "path": "src/test/java/app/gpx_animator/core/data/SpeedUnitTest.java",
    "chars": 2327,
    "preview": "package app.gpx_animator.core.data;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions."
  },
  {
    "path": "src/test/java/app/gpx_animator/core/data/gpx/GpxContentHandlerTest.java",
    "chars": 1839,
    "preview": "package app.gpx_animator.core.data.gpx;\n\nimport app.gpx_animator.core.UserException;\nimport org.junit.jupiter.api.Test;\n"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/renderer/plugins/PhotoPluginTest.java",
    "chars": 670,
    "preview": "package app.gpx_animator.core.renderer.plugins;\n\nimport app.gpx_animator.core.data.Photo;\nimport org.junit.jupiter.api.T"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/util/DateUtilTest.java",
    "chars": 1189,
    "preview": "package app.gpx_animator.core.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.time.ZoneId;\nimport java.time.Zoned"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/util/PointUtilTest.java",
    "chars": 1936,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/util/RenderUtilTest.java",
    "chars": 6156,
    "preview": "package app.gpx_animator.core.util;\n\nimport com.github.romankh3.image.comparison.ImageComparison;\nimport com.github.roma"
  },
  {
    "path": "src/test/java/app/gpx_animator/core/util/UtilsTest.java",
    "chars": 1056,
    "preview": "package app.gpx_animator.core.util;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Assertions."
  },
  {
    "path": "src/test/java/app/gpx_animator/ui/cli/CommandLineConfigurationFactoryTest.java",
    "chars": 3548,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/test/java/app/gpx_animator/ui/cli/CommandLineIT.java",
    "chars": 4797,
    "preview": "package app.gpx_animator.ui.cli;\n\nimport app.gpx_animator.Main;\nimport app.gpx_animator.MemoryAppender;\nimport app.gpx_a"
  },
  {
    "path": "src/test/java/app/gpx_animator/ui/cli/OptionParam.java",
    "chars": 17524,
    "preview": "/*\n *  Copyright Contributors to the GPX Animator project.\n *\n *  Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "src/test/java/app/gpx_animator/ui/swing/DurationFormatterTest.java",
    "chars": 1710,
    "preview": "package app.gpx_animator.ui.swing;\n\nimport org.jetbrains.annotations.NonNls;\nimport org.junit.jupiter.params.Parameteriz"
  },
  {
    "path": "src/test/java/app/gpx_animator/ui/swing/DurationSpinnerModelTest.java",
    "chars": 1469,
    "preview": "package app.gpx_animator.ui.swing;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.params.ParameterizedTest"
  },
  {
    "path": "src/test/resources/gpx/bikeride.gpx",
    "chars": 3390855,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx creator=\"Garmin Connect\" version=\"1.1\"\n  xsi:schemaLocation=\"http://www.topo"
  },
  {
    "path": "src/test/resources/gpx/comment.gpx",
    "chars": 1819,
    "preview": "<?xml version='1.0' encoding='UTF-8'?>\n<gpx version=\"1.1\"\n     creator=\"https://www.komoot.de\"\n     xmlns=\"http://www.to"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the gpx-animator/gpx-animator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 140 files (4.0 MB), approximately 1.1M tokens, and a symbol index with 784 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!