aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpacien2020-09-25 16:01:49 +0200
committerpacien2020-09-25 16:01:49 +0200
commite93f7b1eb84c083d67567115284c0002a3a7d5fc (patch)
tree8d373e8f7f571485e1330928f43b090ed004c525
parent8e3ac8fe44bebb38e1882ca7f06b8100078ad88d (diff)
parentfd542f75a1d94ee5f804d0925823276b97f38581 (diff)
downloadldgallery-master.tar.gz
Merge branch 'develop' for release v2.0HEADv2.0master
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md45
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.travis.yml2
-rw-r--r--changelog.md24
-rw-r--r--compiler/app/Main.hs17
-rw-r--r--compiler/ldgallery.1.md48
-rw-r--r--compiler/package.yaml2
-rw-r--r--compiler/src/Caching.hs76
-rw-r--r--compiler/src/Compiler.hs74
-rw-r--r--compiler/src/Config.hs6
-rw-r--r--compiler/src/FileProcessors.hs128
-rw-r--r--compiler/src/Files.hs36
-rw-r--r--compiler/src/Input.hs65
-rw-r--r--compiler/src/ItemProcessors.hs115
-rw-r--r--compiler/src/Processors.hs203
-rw-r--r--compiler/src/Resource.hs90
-rw-r--r--example/config.json5
-rw-r--r--example/src/Misc Media/A Trip to the Moon.mp4bin0 -> 916818 bytes
-rw-r--r--example/src/Misc Media/Beethoven - Fifth Symphony intro.oggbin0 -> 131121 bytes
-rw-r--r--example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg_thumbnail.jpgbin0 -> 29688 bytes
-rw-r--r--example/src/Misc Media/European Social Charter (Revised).pdfbin0 -> 183134 bytes
-rw-r--r--example/src/Misc Media/Universal Declaration of Human Rights.txt157
-rw-r--r--example/src/Ormont-Dessus/_thumbnail.jpg (renamed from example/src/Ormont-Dessus/_directory.jpg)bin457873 -> 457873 bytes
-rw-r--r--example/src/gallery.yaml4
-rw-r--r--ldgallery-quickstart.7.md79
-rw-r--r--readme.md4
-rw-r--r--viewer/.eslintrc.js9
-rw-r--r--viewer/.vscode/tasks.json86
-rw-r--r--viewer/babel.config.js3
-rw-r--r--viewer/ldgallery-viewer.7.md51
-rw-r--r--viewer/package-lock.json3316
-rw-r--r--viewer/package.json82
-rw-r--r--viewer/src/@types/ItemType.ts11
-rw-r--r--viewer/src/@types/Operation.ts2
-rw-r--r--viewer/src/@types/gallery.d.ts92
-rw-r--r--viewer/src/@types/scrollposition.d.ts2
-rw-r--r--viewer/src/@types/tag.d.ts4
-rw-r--r--viewer/src/assets/scss/global.scss40
-rw-r--r--viewer/src/assets/scss/scrollbar.scss39
-rw-r--r--viewer/src/assets/scss/theme.scss6
-rw-r--r--viewer/src/assets/scss/transition.scss32
-rw-r--r--viewer/src/components/LdBreadcrumb.vue4
-rw-r--r--viewer/src/components/LdCommand.vue17
-rw-r--r--viewer/src/components/LdCommandSearch.vue4
-rw-r--r--viewer/src/components/LdCommandSort.vue55
-rw-r--r--viewer/src/components/LdError.vue58
-rw-r--r--viewer/src/components/LdGallery.vue16
-rw-r--r--viewer/src/components/LdInformation.vue84
-rw-r--r--viewer/src/components/LdProposition.vue52
-rw-r--r--viewer/src/components/LdTagInput.vue4
-rw-r--r--viewer/src/components/LdThumbnail.vue18
-rw-r--r--viewer/src/components/index.ts17
-rw-r--r--viewer/src/components/item_handlers/LdAudioViewer.vue55
-rw-r--r--viewer/src/components/item_handlers/LdDirectory.vue (renamed from viewer/src/views/GalleryDirectory.vue)13
-rw-r--r--viewer/src/components/item_handlers/LdDownload.vue57
-rw-r--r--viewer/src/components/item_handlers/LdPdfViewer.vue45
-rw-r--r--viewer/src/components/item_handlers/LdPicture.vue (renamed from viewer/src/components/LdPicture.vue)20
-rw-r--r--viewer/src/components/item_handlers/LdPlainTextViewer.vue55
-rw-r--r--viewer/src/components/item_handlers/LdVideoViewer.vue47
-rw-r--r--viewer/src/locales/en.json31
-rw-r--r--viewer/src/main.ts14
-rw-r--r--viewer/src/plugins/buefy.ts6
-rw-r--r--viewer/src/plugins/fontawesome-icons.ts45
-rw-r--r--viewer/src/plugins/fontawesome.ts30
-rw-r--r--viewer/src/plugins/router.ts2
-rw-r--r--viewer/src/services/dragscrollclickfix.ts3
-rw-r--r--viewer/src/services/indexfactory.ts26
-rw-r--r--viewer/src/services/indexsearch.ts7
-rw-r--r--viewer/src/services/itemComparators.ts73
-rw-r--r--viewer/src/services/ldzoom.ts6
-rw-r--r--viewer/src/services/navigation.ts41
-rw-r--r--viewer/src/shims-tsx.d.ts4
-rw-r--r--viewer/src/store/galleryStore.ts36
-rw-r--r--viewer/src/store/index.ts16
-rw-r--r--viewer/src/store/uiStore.ts19
-rw-r--r--viewer/src/views/GalleryNavigation.vue38
-rw-r--r--viewer/src/views/GallerySearch.vue15
-rw-r--r--viewer/src/views/MainLayout.vue30
-rw-r--r--viewer/src/views/PanelLeft.vue34
-rw-r--r--viewer/src/views/PanelTop.vue8
-rw-r--r--viewer/visualstudio.code-workspace22
-rw-r--r--viewer/vue.config.js46
82 files changed, 4144 insertions, 2004 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..8653388
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,45 @@
1---
2name: Bug report
3about: Create a report to help us improve
4title: ''
5labels: ''
6assignees: ''
7---
8
9**Describe the bug**
10
11A clear and concise description of what the bug is.
12
13
14**To reproduce**
15
16Steps to reproduce the behaviour:
17
181. Go to '...'
192. Click on '....'
203. Scroll down to '....'
214. See error
22
23
24**Expected behaviour**
25
26A clear and concise description of what you expected to happen.
27
28
29**Screenshots**
30
31If applicable, add screenshots to help explain your problem.
32
33
34**Environment (please complete the folloming information):**
35
36 - LdGallery version: [e.g. 1.0]
37 - Platform: [e.g. desktop/smartphone/tablet/...]
38 - OS: [e.g. iOS/MacOS/Android/Windows/Debian/...]
39 - Browser: [e.g. Firefox/Chrome/Safari/...]
40 - Browser version: [e.g. 81]
41
42
43**Additional context**
44
45Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..bbcbbe7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
1---
2name: Feature request
3about: Suggest an idea for this project
4title: ''
5labels: ''
6assignees: ''
7
8---
9
10**Is your feature request related to a problem? Please describe.**
11A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
13**Describe the solution you'd like**
14A clear and concise description of what you want to happen.
15
16**Describe alternatives you've considered**
17A clear and concise description of any alternative solutions or features you've considered.
18
19**Additional context**
20Add any other context or screenshots about the feature request here.
diff --git a/.travis.yml b/.travis.yml
index 826dd65..23be533 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -116,7 +116,7 @@ jobs:
116 - cp viewer/ldgallery-viewer.7.md dist/ldgallery-viewer.7.md 116 - cp viewer/ldgallery-viewer.7.md dist/ldgallery-viewer.7.md
117 - cp compiler/ldgallery.1.md dist/ldgallery.1.md 117 - cp compiler/ldgallery.1.md dist/ldgallery.1.md
118 - cp changelog.md license.md dist/ 118 - cp changelog.md license.md dist/
119 - curl --output magick.zip -L https://imagemagick.org/download/binaries/ImageMagick-7.0.10-10-portable-Q16-x64.zip 119 - curl --fail --output magick.zip -L https://imagemagick.org/download/binaries/ImageMagick-7.0.10-30-portable-Q16-x64.zip
120 - 7z e magick.zip -odist/ magick.exe 120 - 7z e magick.zip -odist/ magick.exe
121 - 7z e magick.zip -so LICENSE.txt > dist/magick.license.txt 121 - 7z e magick.zip -so LICENSE.txt > dist/magick.license.txt
122 - 7z e magick.zip -so NOTICE.txt > dist/magick.notice.txt 122 - 7z e magick.zip -so NOTICE.txt > dist/magick.notice.txt
diff --git a/changelog.md b/changelog.md
index d1d81c1..cf4b230 100644
--- a/changelog.md
+++ b/changelog.md
@@ -3,5 +3,27 @@
3This file lists notable changes that have been made to the application on each release. 3This file lists notable changes that have been made to the application on each release.
4Releases are tracked and referred to using git tags. 4Releases are tracked and referred to using git tags.
5 5
6## v2.0 - 2020-09-25
7- Thumbnails are now allowed for all files in addition to directories.
8 __Breaking change__: directory thumbnails are now named "\_thumbnail.ext" instead of "\_directory.ext".
9- Plain text, PDF, audio and video items are now displayed within the web application in browsers which support those formats.
10- Items can now have a timestamp.
11 Date and time can be given through the "datetime" key in sidecar metadata files.
12 By default, this is set to the last modification date and time of the file itself.
13- Items can now have an optional description, given through the option of the same name in sidecar metadata files.
14 Rich text formatting is possible through the use of the GitHub-Flavoured Markdown (GFM) syntax.
15- An information panel has been added to the viewer.
16 It displays the title, date and time, as well as the description associated to the viewed item.
17- Items can now be sorted by name and date through a newly introduced sorting menu in the viewer.
18 A default order can be configured in the viewer's configuration file with the "initialItemSort" option.
19 The default behaviour is to sort items in chronological order.
20- Tag suggestions are now limited to the first 10 most used tags for each category.
21 The hidden suggestions now have to be expanded by the user.
22 This limit can be modified or disabled with the newly introduced "initialTagDisplayLimit" option.
23- The viewer can now load alternative configuration files through an optional query parameter.
24- The index file to load can now be specified in the viewer configuration file with the "galleryIndex" option.
25- Gallery build time has been reduced through more extensive caching (now reusing item metadata from previous compilations).
26
27
6## v1.0 - 2020-05-02 28## v1.0 - 2020-05-02
7- first release 29- First release.
diff --git a/compiler/app/Main.hs b/compiler/app/Main.hs
index 48e5644..e71e0db 100644
--- a/compiler/app/Main.hs
+++ b/compiler/app/Main.hs
@@ -21,6 +21,7 @@ module Main where
21import GHC.Generics (Generic) 21import GHC.Generics (Generic)
22import Paths_ldgallery_compiler (version, getDataFileName) 22import Paths_ldgallery_compiler (version, getDataFileName)
23import Control.Monad (when) 23import Control.Monad (when)
24import Data.Functor ((<&>))
24import Data.Maybe (isJust) 25import Data.Maybe (isJust)
25import Data.Version (showVersion) 26import Data.Version (showVersion)
26import Data.Aeson (ToJSON) 27import Data.Aeson (ToJSON)
@@ -32,7 +33,7 @@ import Compiler
32import Files (readDirectory, copyTo, remove) 33import Files (readDirectory, copyTo, remove)
33 34
34 35
35data ViewerConfig = ViewerConfig 36newtype ViewerConfig = ViewerConfig
36 { galleryRoot :: String 37 { galleryRoot :: String
37 } deriving (Generic, Show, ToJSON) 38 } deriving (Generic, Show, ToJSON)
38 39
@@ -42,7 +43,7 @@ data Options = Options
42 , outputDir :: FilePath 43 , outputDir :: FilePath
43 , outputIndex :: FilePath 44 , outputIndex :: FilePath
44 , galleryConfig :: FilePath 45 , galleryConfig :: FilePath
45 , rebuilAll :: Bool 46 , rebuildAll :: Bool
46 , cleanOutput :: Bool 47 , cleanOutput :: Bool
47 , withViewer :: Maybe FilePath 48 , withViewer :: Maybe FilePath
48 } deriving (Show, Data, Typeable) 49 } deriving (Show, Data, Typeable)
@@ -73,7 +74,7 @@ options = Options
73 &= name "gallery-config" 74 &= name "gallery-config"
74 &= explicit 75 &= explicit
75 &= help "Gallery configuration file (default=<input-dir>/gallery.yaml)" 76 &= help "Gallery configuration file (default=<input-dir>/gallery.yaml)"
76 , rebuilAll = False 77 , rebuildAll = False
77 &= name "r" 78 &= name "r"
78 &= name "rebuild-all" 79 &= name "rebuild-all"
79 &= explicit 80 &= explicit
@@ -92,7 +93,7 @@ options = Options
92 &= help "Deploy either the bundled or the given static web viewer to the output directory" 93 &= help "Deploy either the bundled or the given static web viewer to the output directory"
93 } 94 }
94 95
95 &= summary ("ldgallery v" ++ (showVersion version) ++ " - a static web gallery generator with tags") 96 &= summary ("ldgallery v" ++ showVersion version ++ " - a static web gallery generator with tags")
96 &= program "ldgallery" 97 &= program "ldgallery"
97 &= help "Compile a gallery" 98 &= help "Compile a gallery"
98 &= helpArg [explicit, name "h", name "help"] 99 &= helpArg [explicit, name "h", name "help"]
@@ -130,7 +131,7 @@ main =
130 (galleryOutputDir opts) 131 (galleryOutputDir opts)
131 (outputIndex opts) 132 (outputIndex opts)
132 [outputDir opts] 133 [outputDir opts]
133 (rebuilAll opts) 134 (rebuildAll opts)
134 (cleanOutput opts) 135 (cleanOutput opts)
135 where 136 where
136 checkDistinctPaths :: FilePath -> FilePath -> IO () 137 checkDistinctPaths :: FilePath -> FilePath -> IO ()
@@ -146,7 +147,7 @@ main =
146 147
147 deployViewer :: FilePath -> Options -> IO () 148 deployViewer :: FilePath -> Options -> IO ()
148 deployViewer distPath Options{outputDir, cleanOutput} = 149 deployViewer distPath Options{outputDir, cleanOutput} =
149 (when cleanOutput $ cleanViewerDir outputDir) 150 when cleanOutput (cleanViewerDir outputDir)
150 >> copyViewer distPath outputDir 151 >> copyViewer distPath outputDir
151 >> writeJSON (outputDir </> "config.json") viewerConfig 152 >> writeJSON (outputDir </> "config.json") viewerConfig
152 153
@@ -154,8 +155,8 @@ main =
154 cleanViewerDir :: FilePath -> IO () 155 cleanViewerDir :: FilePath -> IO ()
155 cleanViewerDir target = 156 cleanViewerDir target =
156 listDirectory target 157 listDirectory target
157 >>= return . filter (/= gallerySubdir) 158 <&> filter (/= gallerySubdir)
158 >>= mapM_ remove . map (target </>) 159 >>= mapM_ (remove . (target </>))
159 160
160 copyViewer :: FilePath -> FilePath -> IO () 161 copyViewer :: FilePath -> FilePath -> IO ()
161 copyViewer dist target = 162 copyViewer dist target =
diff --git a/compiler/ldgallery.1.md b/compiler/ldgallery.1.md
index a60a3b1..eda6cc2 100644
--- a/compiler/ldgallery.1.md
+++ b/compiler/ldgallery.1.md
@@ -2,7 +2,7 @@
2pagetitle: Compiler user manual - ldgallery 2pagetitle: Compiler user manual - ldgallery
3title: LDGALLERY(1) ldgallery 3title: LDGALLERY(1) ldgallery
4author: Pacien TRAN-GIRARD, Guillaume FOUET 4author: Pacien TRAN-GIRARD, Guillaume FOUET
5date: 2020-04-30 (v1.0) 5date: 2020-09-19 (v2.0)
6--- 6---
7 7
8 8
@@ -13,7 +13,7 @@ ldgallery - a static web gallery generator with tags
13 13
14# DESCRIPTION 14# DESCRIPTION
15 15
16ldgallery is a static gallery generator which turns a collection of tagged pictures into a searchable web gallery. 16ldgallery is a static gallery generator which turns a collection of tagged media files into a searchable web gallery.
17 17
18The ldgallery compiler program processes pictures and aggregates metadata from plain text sidecar files to generate an indexed version of the gallery. 18The ldgallery compiler program processes pictures and aggregates metadata from plain text sidecar files to generate an indexed version of the gallery.
19It can optionally output a static web viewer along, which allows the content to be presented and searched through from a JavaScript-enabled web browser. 19It can optionally output a static web viewer along, which allows the content to be presented and searched through from a JavaScript-enabled web browser.
@@ -45,6 +45,7 @@ Available options are:
45 45
46-r, \--rebuild-all 46-r, \--rebuild-all
47: Invalidate cache and recompile everything. 47: Invalidate cache and recompile everything.
48 By default, the compiler skips items which haven't changed based on their modification time.
48 49
49-c, \--clean-output 50-c, \--clean-output
50: Remove unnecessary files from the output directory. 51: Remove unnecessary files from the output directory.
@@ -67,22 +68,24 @@ Available options are:
67 68
68A gallery source directory contains the gallery items and their sidecar metadata files, optionally grouped inside sub-directories. 69A gallery source directory contains the gallery items and their sidecar metadata files, optionally grouped inside sub-directories.
69 70
70Directory thumbnails can be set by placing a picture file named "_directory", with any image file extension, inside of directories. 71Thumbnails can be associated to items by suffixing their name with "\_thumbnail", followed by an image file extension.
72Directory thumbnails can be placed within their respective directories themselves, without any prefix.
71 73
72An example input gallery directory structure could be as follows: 74An example input gallery directory structure could be as follows:
73 75
74``` 76```
75./example-gallery 77./example-gallery
76├── DSC0001.jpg --------- a picture 78├── DSC0001.jpg ----------------- a picture
77├── DSC0001.jpg.yaml ---- its associated sidecar metadata file 79├── DSC0001.jpg.yaml ------------ its associated sidecar metadata file
78├── Some directory ------ a directory grouping gallery items 80├── Some directory -------------- a directory grouping gallery items
79│ ├── _directory.jpg -- a thumbnail for its parent directory 81│ ├── _directory.yaml --------- directory sidecar metadata file
80│ ├── _directory.yaml - directory sidecar metadata file 82│ ├── _thumbnail.jpg ---------- a thumbnail for its parent directory
81│ ├── DSC0002.jpg 83│ ├── DSC0002.jpg
82│ ├── DSC0002.jpg.yaml 84│ ├── DSC0002.jpg.yaml
83│ ├── DSC0003.jpg 85│ ├── song.ogg
84│ └── DSC0003.jpg.yaml 86│ ├── song.ogg.yaml
85└── gallery.yaml -------- gallery settings file 87│ └── song.ogg_thumbnail.jpg -- a thumbnail for song.ogg
88└── gallery.yaml ---------------- gallery settings file
86``` 89```
87 90
88 91
@@ -91,7 +94,7 @@ An example input gallery directory structure could be as follows:
91File metadata are read from sidecar files of the same name, with the ".yaml" extension appended. 94File metadata are read from sidecar files of the same name, with the ".yaml" extension appended.
92Metadata contained within item files themselves (e.g. Exif fields for pictures) are ignored. 95Metadata contained within item files themselves (e.g. Exif fields for pictures) are ignored.
93 96
94Directory metadata are read from sidecar files named "_directory.yaml" located within the directory. 97Directory metadata are read from sidecar files named "\_directory.yaml" located within the directory.
95 98
96When a sidecar file is absent or a particular key omitted, values are set as empty or to their fallback value specified below. 99When a sidecar file is absent or a particular key omitted, values are set as empty or to their fallback value specified below.
97 100
@@ -99,17 +102,16 @@ title
99: Title of the item. 102: Title of the item.
100 Defaults to the name of the file or directory. 103 Defaults to the name of the file or directory.
101 104
102<!-- not used in the viewer yet --
103datetime 105datetime
104: ISO 8601 zoned date and time. 106: ISO 8601 zoned date and time.
105 Defaults to the last modification time of the file itself, 107 Defaults to the last modification time of the file itself,
106 or the most recent modification date of a directory's items. 108 or the most recent modification date of a directory's items.
107-->
108 109
109<!-- not used in the viewer yet --
110description 110description
111: Description for the item. 111: Optional description for the item.
112--> 112 Rich text formatting is possible through the use of the [GitHub Flavoured Markdown syntax][GFM].
113
114 [GFM]: https://github.github.com/gfm/
113 115
114tags 116tags
115: List of tags for the item. 117: List of tags for the item.
@@ -119,7 +121,9 @@ tags
119 121
120# GALLERY CONFIGURATION 122# GALLERY CONFIGURATION
121 123
122The gallery settings reside in a file named "gallery.yaml" located at the root of the gallery's source directory. 124The gallery settings reside in a file named __gallery.yaml__ located at the root of the gallery's source directory.
125
126Gallery configurations options are:
123 127
124galleryTitle 128galleryTitle
125: Title of the gallery. 129: Title of the gallery.
@@ -127,7 +131,7 @@ galleryTitle
127 131
128includedDirectories[] 132includedDirectories[]
129: Glob patterns of directory names to include in the gallery. 133: Glob patterns of directory names to include in the gallery.
130 Defaults to ["*"] (matches all directory names). 134 Defaults to ["\*"] (matches all directory names).
131 135
132excludedDirectories[] 136excludedDirectories[]
133: Glob patterns of directory names to exclude from the gallery. 137: Glob patterns of directory names to exclude from the gallery.
@@ -135,7 +139,7 @@ excludedDirectories[]
135 139
136includedFiles[] 140includedFiles[]
137: Glob patterns of file names to include in the gallery. 141: Glob patterns of file names to include in the gallery.
138 Defaults to ["*"] (matches all file names). 142 Defaults to ["\*"] (matches all file names).
139 143
140excludedFiles[] 144excludedFiles[]
141: Glob patterns of file names to exclude from the gallery. 145: Glob patterns of file names to exclude from the gallery.
@@ -144,7 +148,7 @@ excludedFiles[]
144includedTags[] 148includedTags[]
145: Glob patterns of tags to include in the gallery. 149: Glob patterns of tags to include in the gallery.
146 Items with no tags can be matched with the empty pattern. 150 Items with no tags can be matched with the empty pattern.
147 Defaults to ["*"] (matches all tags, includes untagged items). 151 Defaults to ["\*"] (matches all tags, includes untagged items).
148 152
149excludedTags[] 153excludedTags[]
150: Glob patterns of tags to exclude from the gallery. 154: Glob patterns of tags to exclude from the gallery.
@@ -176,7 +180,7 @@ pictureMaxResolution.height
176 180
177# SEE ALSO 181# SEE ALSO
178 182
179Related manual pages: __ldgallery-quickstart__(7), __ldgallery-viewer__(7) 183Related manual pages: __ldgallery-quickstart__(7), __ldgallery-viewer__(7).
180 184
181The ldgallery source code is available on <https://ldgallery.pacien.org>. 185The ldgallery source code is available on <https://ldgallery.pacien.org>.
182 186
diff --git a/compiler/package.yaml b/compiler/package.yaml
index c44675b..faa2174 100644
--- a/compiler/package.yaml
+++ b/compiler/package.yaml
@@ -1,5 +1,5 @@
1name: ldgallery-compiler 1name: ldgallery-compiler
2version: 1.0 2version: 2.0
3homepage: https://ldgallery.pacien.org 3homepage: https://ldgallery.pacien.org
4github: "pacien/ldgallery" 4github: "pacien/ldgallery"
5license: AGPL-3 5license: AGPL-3
diff --git a/compiler/src/Caching.hs b/compiler/src/Caching.hs
new file mode 100644
index 0000000..c2b5a43
--- /dev/null
+++ b/compiler/src/Caching.hs
@@ -0,0 +1,76 @@
1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19module Caching
20 ( Cache
21 , noCache
22 , ItemCache
23 , buildItemCache
24 , useCached
25 ) where
26
27
28import Control.Monad (when)
29import qualified Data.Map.Strict as Map
30import System.Directory (removePathForcibly, doesDirectoryExist, doesFileExist)
31
32import FileProcessors (FileProcessor)
33import Resource (GalleryItem(..), flattenGalleryTree)
34import Files
35
36
37type Cache a = FileProcessor a -> FileProcessor a
38
39
40noCache :: Cache a
41noCache processor itemPath resPath inputFsPath outputFsPath =
42 removePathForcibly outputFsPath
43 >> processor itemPath resPath inputFsPath outputFsPath
44
45
46type ItemCache = Path -> Maybe GalleryItem
47
48buildItemCache :: Maybe GalleryItem -> ItemCache
49buildItemCache cachedItems = lookupCache
50 where
51 withKey item = (webPath $ Resource.path item, item)
52 cachedItemList = maybe [] flattenGalleryTree cachedItems
53 cachedMap = Map.fromList (map withKey cachedItemList)
54 lookupCache path = Map.lookup (webPath path) cachedMap
55
56useCached :: ItemCache -> (GalleryItem -> a) -> Cache a
57useCached cache propGetter processor itemPath resPath inputFsPath outputFsPath =
58 do
59 isDir <- doesDirectoryExist outputFsPath
60 when isDir $ removePathForcibly outputFsPath
61
62 fileExists <- doesFileExist outputFsPath
63 if fileExists then
64 do
65 needUpdate <- isOutdated True inputFsPath outputFsPath
66 case (needUpdate, cache itemPath) of
67 (False, Just props) -> fromCache props
68 _ -> update
69 else
70 update
71
72 where
73 update = processor itemPath resPath inputFsPath outputFsPath
74 fromCache props =
75 putStrLn ("From cache:\t" ++ outputFsPath)
76 >> return (propGetter props)
diff --git a/compiler/src/Compiler.hs b/compiler/src/Compiler.hs
index 749872d..1ec55c5 100644
--- a/compiler/src/Compiler.hs
+++ b/compiler/src/Compiler.hs
@@ -24,17 +24,25 @@ module Compiler
24 24
25import GHC.Generics (Generic) 25import GHC.Generics (Generic)
26import Control.Monad (liftM2, when) 26import Control.Monad (liftM2, when)
27import Data.Bool (bool)
27import Data.Maybe (fromMaybe) 28import Data.Maybe (fromMaybe)
28import System.FilePath ((</>)) 29import System.FilePath ((</>))
29import qualified System.FilePath.Glob as Glob 30import qualified System.FilePath.Glob as Glob
30import System.Directory (canonicalizePath) 31import System.Directory (canonicalizePath, doesFileExist)
31 32
32import Data.Aeson (ToJSON) 33import Data.Aeson (ToJSON, FromJSON)
33import qualified Data.Aeson as JSON 34import qualified Data.Aeson as JSON
34 35
35import Config 36import Config
36import Input (InputTree, readInputTree, filterInputTree, sidecar, tags) 37import Input (InputTree, readInputTree, filterInputTree, sidecar, tags)
37import Resource (GalleryItem, buildGalleryTree, galleryCleanupResourceDir) 38import Resource
39 ( GalleryItem
40 , GalleryItemProps
41 , Thumbnail
42 , buildGalleryTree
43 , galleryCleanupResourceDir
44 , properties
45 , thumbnail)
38import Files 46import Files
39 ( FileName 47 ( FileName
40 , FSNode(..) 48 , FSNode(..)
@@ -43,9 +51,8 @@ import Files
43 , nodeName 51 , nodeName
44 , filterDir 52 , filterDir
45 , ensureParentDir ) 53 , ensureParentDir )
46import Processors 54import ItemProcessors (ItemProcessor, itemFileProcessor, thumbnailFileProcessor)
47 ( itemFileProcessor, thumbnailFileProcessor 55import Caching (Cache, noCache, buildItemCache, useCached)
48 , skipCached, withCached )
49 56
50 57
51defaultGalleryConf :: String 58defaultGalleryConf :: String
@@ -64,7 +71,7 @@ thumbnailsDir = "thumbnails"
64data GalleryIndex = GalleryIndex 71data GalleryIndex = GalleryIndex
65 { properties :: ViewerConfig 72 { properties :: ViewerConfig
66 , tree :: GalleryItem 73 , tree :: GalleryItem
67 } deriving (Generic, Show, ToJSON) 74 } deriving (Generic, Show, ToJSON, FromJSON)
68 75
69 76
70writeJSON :: ToJSON a => FileName -> a -> IO () 77writeJSON :: ToJSON a => FileName -> a -> IO ()
@@ -73,6 +80,15 @@ writeJSON outputPath object =
73 putStrLn $ "Generating:\t" ++ outputPath 80 putStrLn $ "Generating:\t" ++ outputPath
74 ensureParentDir JSON.encodeFile outputPath object 81 ensureParentDir JSON.encodeFile outputPath object
75 82
83loadGalleryIndex :: FilePath -> IO (Maybe GalleryIndex)
84loadGalleryIndex path =
85 doesFileExist path >>= bool (return Nothing) decodeIndex
86 where
87 decodeIndex =
88 JSON.eitherDecodeFileStrict path
89 >>= either (\err -> warn err >> return Nothing) (return . Just)
90 warn = putStrLn . ("Warning:\tUnable to reuse existing index as cache: " ++)
91
76 92
77(&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool 93(&&&) :: (a -> Bool) -> (a -> Bool) -> a -> Bool
78(&&&) = liftM2 (&&) 94(&&&) = liftM2 (&&)
@@ -81,16 +97,16 @@ writeJSON outputPath object =
81(|||) = liftM2 (||) 97(|||) = liftM2 (||)
82 98
83anyPattern :: [String] -> String -> Bool 99anyPattern :: [String] -> String -> Bool
84anyPattern patterns string = any (flip Glob.match string) (map Glob.compile patterns) 100anyPattern patterns string = any (flip Glob.match string . Glob.compile) patterns
85 101
86galleryDirFilter :: GalleryConfig -> [FilePath] -> FSNode -> Bool 102galleryDirFilter :: GalleryConfig -> [FilePath] -> FSNode -> Bool
87galleryDirFilter config excludedCanonicalDirs = 103galleryDirFilter config excludedCanonicalDirs =
88 (not . isHidden) 104 (not . isHidden)
89 &&& (not . isExcludedDir) 105 &&& (not . isExcludedDir)
90 &&& ((matchesDir $ anyPattern $ includedDirectories config) ||| 106 &&& (matchesDir (anyPattern $ includedDirectories config) |||
91 (matchesFile $ anyPattern $ includedFiles config)) 107 matchesFile (anyPattern $ includedFiles config))
92 &&& (not . ((matchesDir $ anyPattern $ excludedDirectories config) ||| 108 &&& (not . (matchesDir (anyPattern $ excludedDirectories config) |||
93 (matchesFile $ anyPattern $ excludedFiles config))) 109 matchesFile (anyPattern $ excludedFiles config)))
94 110
95 where 111 where
96 matchesDir :: (FileName -> Bool) -> FSNode -> Bool 112 matchesDir :: (FileName -> Bool) -> FSNode -> Bool
@@ -102,17 +118,17 @@ galleryDirFilter config excludedCanonicalDirs =
102 matchesFile _ Dir{} = False 118 matchesFile _ Dir{} = False
103 119
104 isExcludedDir :: FSNode -> Bool 120 isExcludedDir :: FSNode -> Bool
105 isExcludedDir Dir{canonicalPath} = any (canonicalPath ==) excludedCanonicalDirs 121 isExcludedDir Dir{canonicalPath} = canonicalPath `elem` excludedCanonicalDirs
106 isExcludedDir File{} = False 122 isExcludedDir File{} = False
107 123
108inputTreeFilter :: GalleryConfig -> InputTree -> Bool 124inputTreeFilter :: GalleryConfig -> InputTree -> Bool
109inputTreeFilter GalleryConfig{includedTags, excludedTags} = 125inputTreeFilter GalleryConfig{includedTags, excludedTags} =
110 (hasTagMatching $ anyPattern includedTags) 126 hasTagMatching (anyPattern includedTags)
111 &&& (not . (hasTagMatching $ anyPattern excludedTags)) 127 &&& (not . hasTagMatching (anyPattern excludedTags))
112 128
113 where 129 where
114 hasTagMatching :: (String -> Bool) -> InputTree -> Bool 130 hasTagMatching :: (String -> Bool) -> InputTree -> Bool
115 hasTagMatching cond = (any cond) . (fromMaybe [""] . tags) . sidecar 131 hasTagMatching cond = any cond . (fromMaybe [""] . tags) . sidecar
116 132
117 133
118compileGallery :: FilePath -> FilePath -> FilePath -> FilePath -> [FilePath] -> Bool -> Bool -> IO () 134compileGallery :: FilePath -> FilePath -> FilePath -> FilePath -> [FilePath] -> Bool -> Bool -> IO ()
@@ -127,14 +143,17 @@ compileGallery configPath inputDirPath outputDirPath outputIndexPath excludedDir
127 inputTree <- readInputTree sourceTree 143 inputTree <- readInputTree sourceTree
128 let curatedInputTree = filterInputTree (inputTreeFilter config) inputTree 144 let curatedInputTree = filterInputTree (inputTreeFilter config) inputTree
129 145
130 let cache = if rebuildAll then skipCached else withCached 146 let galleryIndexPath = outputGalleryIndex outputIndexPath
131 let itemProc = itemProcessor config cache 147 cachedIndex <- loadCachedIndex galleryIndexPath
132 let thumbnailProc = thumbnailProcessor config cache 148 let cache = mkCache cachedIndex
149
150 let itemProc = itemProcessor config (cache Resource.properties)
151 let thumbnailProc = thumbnailProcessor config (cache Resource.thumbnail)
133 let galleryBuilder = buildGalleryTree itemProc thumbnailProc (tagsFromDirectories config) 152 let galleryBuilder = buildGalleryTree itemProc thumbnailProc (tagsFromDirectories config)
134 resources <- galleryBuilder curatedInputTree 153 resources <- galleryBuilder curatedInputTree
135 154
136 when cleanOutput $ galleryCleanupResourceDir resources outputDirPath 155 when cleanOutput $ galleryCleanupResourceDir resources outputDirPath
137 writeJSON (outputGalleryIndex outputIndexPath) $ GalleryIndex (viewerConfig config) resources 156 writeJSON galleryIndexPath $ GalleryIndex (viewerConfig config) resources
138 157
139 where 158 where
140 inputGalleryConf :: FilePath -> FilePath 159 inputGalleryConf :: FilePath -> FilePath
@@ -145,10 +164,25 @@ compileGallery configPath inputDirPath outputDirPath outputIndexPath excludedDir
145 outputGalleryIndex "" = outputDirPath </> defaultIndexFile 164 outputGalleryIndex "" = outputDirPath </> defaultIndexFile
146 outputGalleryIndex file = file 165 outputGalleryIndex file = file
147 166
167 loadCachedIndex :: FilePath -> IO (Maybe GalleryIndex)
168 loadCachedIndex galleryIndexPath =
169 if rebuildAll
170 then return Nothing
171 else loadGalleryIndex galleryIndexPath
172
173 mkCache :: Maybe GalleryIndex -> (GalleryItem -> a) -> Cache a
174 mkCache refGalleryIndex =
175 if rebuildAll
176 then const noCache
177 else useCached (buildItemCache $ fmap tree refGalleryIndex)
178
179 itemProcessor :: GalleryConfig -> Cache GalleryItemProps -> ItemProcessor GalleryItemProps
148 itemProcessor config cache = 180 itemProcessor config cache =
149 itemFileProcessor 181 itemFileProcessor
150 (pictureMaxResolution config) cache 182 (pictureMaxResolution config) cache
151 inputDirPath outputDirPath itemsDir 183 inputDirPath outputDirPath itemsDir
184
185 thumbnailProcessor :: GalleryConfig -> Cache (Maybe Thumbnail) -> ItemProcessor (Maybe Thumbnail)
152 thumbnailProcessor config cache = 186 thumbnailProcessor config cache =
153 thumbnailFileProcessor 187 thumbnailFileProcessor
154 (thumbnailMaxResolution config) cache 188 (thumbnailMaxResolution config) cache
diff --git a/compiler/src/Config.hs b/compiler/src/Config.hs
index 0ae0fa1..afcfb36 100644
--- a/compiler/src/Config.hs
+++ b/compiler/src/Config.hs
@@ -73,8 +73,8 @@ instance FromJSON GalleryConfig where
73 <*> v .:? "includedTags" .!= ["*"] 73 <*> v .:? "includedTags" .!= ["*"]
74 <*> v .:? "excludedTags" .!= [] 74 <*> v .:? "excludedTags" .!= []
75 <*> v .:? "tagCategories" .!= [] 75 <*> v .:? "tagCategories" .!= []
76 <*> v .:? "tagsFromDirectories" .!= (TagsFromDirectoriesConfig 0 "") 76 <*> v .:? "tagsFromDirectories" .!= TagsFromDirectoriesConfig 0 ""
77 <*> v .:? "thumbnailMaxResolution" .!= (Resolution 400 300) 77 <*> v .:? "thumbnailMaxResolution" .!= Resolution 400 300
78 <*> v .:? "pictureMaxResolution" 78 <*> v .:? "pictureMaxResolution"
79 79
80readConfig :: FileName -> IO GalleryConfig 80readConfig :: FileName -> IO GalleryConfig
@@ -84,7 +84,7 @@ readConfig = decodeYamlFile
84data ViewerConfig = ViewerConfig 84data ViewerConfig = ViewerConfig
85 { galleryTitle :: String 85 { galleryTitle :: String
86 , tagCategories :: [String] 86 , tagCategories :: [String]
87 } deriving (Generic, ToJSON, Show) 87 } deriving (Generic, ToJSON, FromJSON, Show)
88 88
89viewerConfig :: GalleryConfig -> ViewerConfig 89viewerConfig :: GalleryConfig -> ViewerConfig
90viewerConfig GalleryConfig{galleryTitle, tagCategories} = ViewerConfig galleryTitle tagCategories 90viewerConfig GalleryConfig{galleryTitle, tagCategories} = ViewerConfig galleryTitle tagCategories
diff --git a/compiler/src/FileProcessors.hs b/compiler/src/FileProcessors.hs
new file mode 100644
index 0000000..5c4e1c8
--- /dev/null
+++ b/compiler/src/FileProcessors.hs
@@ -0,0 +1,128 @@
1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19module FileProcessors
20 ( FileProcessor
21 , transformThenDescribe
22 , copyResource
23 , noopProcessor
24 , FileTransformer
25 , copyFileProcessor
26 , resizePictureUpTo
27 , resourceAt
28 , getImageResolution
29 , FileDescriber
30 , getResProps
31 , getPictureProps
32 , getThumbnailProps
33 ) where
34
35
36import Control.Exception (Exception, throwIO)
37import System.Process (readProcess, callProcess)
38import Text.Read (readMaybe)
39
40import System.Directory (getModificationTime)
41import qualified System.Directory
42
43import Config (Resolution(..))
44import Resource (Resource(..), GalleryItemProps(..), Thumbnail(..))
45import Files
46
47
48data ProcessingException = ProcessingException FilePath String deriving Show
49instance Exception ProcessingException
50
51type FileProcessor a =
52 Path -- ^ Item path
53 -> Path -- ^ Target resource path
54 -> FilePath -- ^ Filesystem input path
55 -> FilePath -- ^ Filesystem output path
56 -> IO a
57
58transformThenDescribe :: FileTransformer -> FileDescriber a -> FileProcessor a
59transformThenDescribe transformer describer _itemPath resPath fsInPath fsOutPath =
60 transformer fsInPath fsOutPath >> describer resPath fsOutPath
61
62copyResource :: (Resource -> a) -> FileProcessor a
63copyResource resPropConstructor =
64 transformThenDescribe copyFileProcessor (getResProps resPropConstructor)
65
66noopProcessor :: FileProcessor (Maybe a)
67noopProcessor _ _ _ _ = return Nothing
68
69
70type FileTransformer =
71 FileName -- ^ Input path
72 -> FileName -- ^ Output path
73 -> IO ()
74
75copyFileProcessor :: FileTransformer
76copyFileProcessor inputPath outputPath =
77 putStrLn ("Copying:\t" ++ outputPath)
78 >> ensureParentDir (flip System.Directory.copyFile) outputPath inputPath
79
80resizePictureUpTo :: Resolution -> FileTransformer
81resizePictureUpTo maxResolution inputPath outputPath =
82 putStrLn ("Generating:\t" ++ outputPath)
83 >> ensureParentDir (flip resize) outputPath inputPath
84 where
85 maxSize :: Resolution -> String
86 maxSize Resolution{width, height} = show width ++ "x" ++ show height ++ ">"
87
88 resize :: FileName -> FileName -> IO ()
89 resize input output = callProcess "magick"
90 [ input
91 , "-auto-orient"
92 , "-resize", maxSize maxResolution
93 , output ]
94
95
96type FileDescriber a =
97 Path -- ^ Target resource path
98 -> FilePath -- ^ Filesystem path
99 -> IO a
100
101getImageResolution :: FilePath -> IO Resolution
102getImageResolution fsPath =
103 readProcess "magick" ["identify", "-format", "%w %h", firstFrame] []
104 >>= parseResolution . break (== ' ')
105 where
106 firstFrame :: FilePath
107 firstFrame = fsPath ++ "[0]"
108
109 parseResolution :: (String, String) -> IO Resolution
110 parseResolution (widthString, heightString) =
111 case (readMaybe widthString, readMaybe heightString) of
112 (Just w, Just h) -> return $ Resolution w h
113 _ -> throwIO $ ProcessingException fsPath "Unable to read image resolution."
114
115resourceAt :: FileDescriber Resource
116resourceAt resPath fsPath = Resource resPath <$> getModificationTime fsPath
117
118getResProps :: (Resource -> a) -> FileDescriber a
119getResProps resPropsConstructor resPath fsPath =
120 resPropsConstructor <$> resourceAt resPath fsPath
121
122getPictureProps :: FileDescriber GalleryItemProps
123getPictureProps resPath fsPath =
124 Picture <$> resourceAt resPath fsPath <*> getImageResolution fsPath
125
126getThumbnailProps :: FileDescriber (Maybe Thumbnail)
127getThumbnailProps resPath fsPath =
128 Just <$> (Thumbnail <$> resourceAt resPath fsPath <*> getImageResolution fsPath)
diff --git a/compiler/src/Files.hs b/compiler/src/Files.hs
index c769815..023546b 100644
--- a/compiler/src/Files.hs
+++ b/compiler/src/Files.hs
@@ -20,7 +20,7 @@ module Files
20 ( FileName, LocalPath, WebPath, Path(..) 20 ( FileName, LocalPath, WebPath, Path(..)
21 , (</>), (</), (/>), (<.>) 21 , (</>), (</), (/>), (<.>)
22 , fileName, subPaths, pathLength 22 , fileName, subPaths, pathLength
23 , localPath, webPath 23 , localPath, webPath, fromWebPath
24 , FSNode(..), AnchoredFSNode(..) 24 , FSNode(..), AnchoredFSNode(..)
25 , nodeName, isHidden, flattenDir, filterDir 25 , nodeName, isHidden, flattenDir, filterDir
26 , readDirectory, copyTo 26 , readDirectory, copyTo
@@ -28,10 +28,11 @@ module Files
28 ) where 28 ) where
29 29
30 30
31import Data.List (isPrefixOf, length, subsequences, sortOn) 31import Data.List (isPrefixOf, length, sortOn)
32import Data.Function ((&)) 32import Data.Function ((&))
33import Data.Text (pack) 33import Data.Functor ((<&>))
34import Data.Aeson (ToJSON) 34import Data.Text (pack, unpack)
35import Data.Aeson (ToJSON, FromJSON)
35import qualified Data.Aeson as JSON 36import qualified Data.Aeson as JSON
36 37
37import System.Directory 38import System.Directory
@@ -53,13 +54,16 @@ type LocalPath = String
53type WebPath = String 54type WebPath = String
54 55
55-- | Reversed path component list 56-- | Reversed path component list
56data Path = Path [FileName] deriving Show 57newtype Path = Path [FileName] deriving Show
57 58
58instance ToJSON Path where 59instance ToJSON Path where
59 toJSON = JSON.String . pack . webPath 60 toJSON = JSON.String . pack . webPath
60 61
62instance FromJSON Path where
63 parseJSON = JSON.withText "Path" (return . fromWebPath . unpack)
64
61instance Eq Path where 65instance Eq Path where
62 (Path left) == (Path right) = left == right 66 left == right = webPath left == webPath right
63 67
64(</>) :: Path -> Path -> Path 68(</>) :: Path -> Path -> Path
65(Path l) </> (Path r) = Path (r ++ l) 69(Path l) </> (Path r) = Path (r ++ l)
@@ -80,7 +84,10 @@ fileName (Path (name:_)) = Just name
80fileName _ = Nothing 84fileName _ = Nothing
81 85
82subPaths :: Path -> [Path] 86subPaths :: Path -> [Path]
83subPaths (Path path) = map Path $ subsequences path 87subPaths (Path path) = map Path $ subpaths path
88 where
89 subpaths [] = []
90 subpaths full@(_:r) = full : subpaths r
84 91
85pathLength :: Path -> Int 92pathLength :: Path -> Int
86pathLength (Path path) = Data.List.length path 93pathLength (Path path) = Data.List.length path
@@ -91,6 +98,9 @@ localPath (Path path) = System.FilePath.joinPath $ reverse path
91webPath :: Path -> WebPath 98webPath :: Path -> WebPath
92webPath (Path path) = System.FilePath.Posix.joinPath $ reverse path 99webPath (Path path) = System.FilePath.Posix.joinPath $ reverse path
93 100
101fromWebPath :: WebPath -> Path
102fromWebPath = Path . reverse . System.FilePath.Posix.splitDirectories
103
94 104
95data FSNode = 105data FSNode =
96 File 106 File
@@ -120,7 +130,7 @@ isHidden = hiddenName . nodeName
120-- | DFS with intermediate dirs first. 130-- | DFS with intermediate dirs first.
121flattenDir :: FSNode -> [FSNode] 131flattenDir :: FSNode -> [FSNode]
122flattenDir file@File{} = [file] 132flattenDir file@File{} = [file]
123flattenDir dir@Dir{items} = dir:(concatMap flattenDir items) 133flattenDir dir@Dir{items} = dir:concatMap flattenDir items
124 134
125-- | Filters a dir tree. The root is always returned. 135-- | Filters a dir tree. The root is always returned.
126filterDir :: (FSNode -> Bool) -> AnchoredFSNode -> AnchoredFSNode 136filterDir :: (FSNode -> Bool) -> AnchoredFSNode -> AnchoredFSNode
@@ -133,7 +143,7 @@ filterDir cond (AnchoredFSNode anchor root) =
133 filter cond items & map filterNode & Dir path canonicalPath 143 filter cond items & map filterNode & Dir path canonicalPath
134 144
135readDirectory :: LocalPath -> IO AnchoredFSNode 145readDirectory :: LocalPath -> IO AnchoredFSNode
136readDirectory root = mkNode (Path []) >>= return . AnchoredFSNode root 146readDirectory root = AnchoredFSNode root <$> mkNode (Path [])
137 where 147 where
138 mkNode :: Path -> IO FSNode 148 mkNode :: Path -> IO FSNode
139 mkNode path = 149 mkNode path =
@@ -151,10 +161,10 @@ readDirectory root = mkNode (Path []) >>= return . AnchoredFSNode root
151 161
152 mkDirNode :: Path -> FilePath -> IO FSNode 162 mkDirNode :: Path -> FilePath -> IO FSNode
153 mkDirNode path canonicalPath = 163 mkDirNode path canonicalPath =
154 (listDirectory $ localPath (root /> path)) 164 listDirectory (localPath (root /> path))
155 >>= mapM (mkNode . ((</) path)) 165 >>= mapM (mkNode . (path </))
156 >>= return . sortOn nodeName 166 <&> sortOn nodeName
157 >>= return . Dir path canonicalPath 167 <&> Dir path canonicalPath
158 168
159copyTo :: FilePath -> AnchoredFSNode -> IO () 169copyTo :: FilePath -> AnchoredFSNode -> IO ()
160copyTo target AnchoredFSNode{anchor, root} = copyNode root 170copyTo target AnchoredFSNode{anchor, root} = copyNode root
diff --git a/compiler/src/Input.hs b/compiler/src/Input.hs
index 6ed7471..48931ec 100644
--- a/compiler/src/Input.hs
+++ b/compiler/src/Input.hs
@@ -27,13 +27,15 @@ import GHC.Generics (Generic)
27import Control.Exception (Exception, AssertionFailed(..), throw, throwIO) 27import Control.Exception (Exception, AssertionFailed(..), throw, throwIO)
28import Control.Monad.IO.Class (MonadIO, liftIO) 28import Control.Monad.IO.Class (MonadIO, liftIO)
29import Data.Function ((&)) 29import Data.Function ((&))
30import Data.Maybe (catMaybes) 30import Data.Functor ((<&>))
31import Data.Maybe (catMaybes, fromMaybe)
31import Data.Bool (bool) 32import Data.Bool (bool)
32import Data.List (find) 33import Data.List (find, isSuffixOf)
33import Data.Time.Clock (UTCTime) 34import Data.Time.Clock (UTCTime)
34import Data.Time.LocalTime (ZonedTime) 35import Data.Time.LocalTime (ZonedTime)
35import Data.Yaml (ParseException, decodeFileEither) 36import Data.Yaml (ParseException, decodeFileEither)
36import Data.Aeson (FromJSON) 37import Data.Aeson (FromJSON)
38import qualified Data.Map.Strict as Map
37import System.FilePath (isExtensionOf, dropExtension) 39import System.FilePath (isExtensionOf, dropExtension)
38import System.Directory (doesFileExist, getModificationTime) 40import System.Directory (doesFileExist, getModificationTime)
39 41
@@ -54,12 +56,13 @@ data InputTree =
54 InputFile 56 InputFile
55 { path :: Path 57 { path :: Path
56 , modTime :: UTCTime 58 , modTime :: UTCTime
57 , sidecar :: Sidecar } 59 , sidecar :: Sidecar
60 , thumbnailPath :: Maybe Path }
58 | InputDir 61 | InputDir
59 { path :: Path 62 { path :: Path
60 , modTime :: UTCTime 63 , modTime :: UTCTime
61 , sidecar :: Sidecar 64 , sidecar :: Sidecar
62 , dirThumbnailPath :: Maybe Path 65 , thumbnailPath :: Maybe Path
63 , items :: [InputTree] } 66 , items :: [InputTree] }
64 deriving Show 67 deriving Show
65 68
@@ -80,6 +83,9 @@ emptySidecar = Sidecar
80sidecarExt :: String 83sidecarExt :: String
81sidecarExt = "yaml" 84sidecarExt = "yaml"
82 85
86thumbnailSuffix :: String
87thumbnailSuffix = "_thumbnail"
88
83dirPropFile :: String 89dirPropFile :: String
84dirPropFile = "_directory" 90dirPropFile = "_directory"
85 91
@@ -90,7 +96,7 @@ readSidecarFile :: FilePath -> IO Sidecar
90readSidecarFile filepath = 96readSidecarFile filepath =
91 doesFileExist filepath 97 doesFileExist filepath
92 >>= bool (return Nothing) (decodeYamlFile filepath) 98 >>= bool (return Nothing) (decodeYamlFile filepath)
93 >>= return . maybe emptySidecar id 99 <&> fromMaybe emptySidecar
94 100
95 101
96readInputTree :: AnchoredFSNode -> IO InputTree 102readInputTree :: AnchoredFSNode -> IO InputTree
@@ -98,40 +104,49 @@ readInputTree (AnchoredFSNode _ File{}) =
98 throw $ AssertionFailed "Input directory is a file" 104 throw $ AssertionFailed "Input directory is a file"
99readInputTree (AnchoredFSNode anchor root@Dir{}) = mkDirNode root 105readInputTree (AnchoredFSNode anchor root@Dir{}) = mkDirNode root
100 where 106 where
101 mkInputNode :: FSNode -> IO (Maybe InputTree) 107 mkInputNode :: Map.Map FileName FSNode -> FSNode -> IO (Maybe InputTree)
102 mkInputNode file@File{path} 108 mkInputNode dir file@File{path} | not (isSidecar file) && not (isThumbnail file) =
103 | (not $ isSidecar file) && (not $ isThumbnail file) = 109 do
104 do 110 sidecar <- readSidecarFile $ localPath (anchor /> path <.> sidecarExt)
105 sidecar <- readSidecarFile $ localPath (anchor /> path <.> sidecarExt) 111 modTime <- getModificationTime $ localPath (anchor /> path)
106 modTime <- getModificationTime $ localPath (anchor /> path) 112 let thumbnail = findFileThumbnail (fromMaybe "" $ fileName path) dir
107 return $ Just $ InputFile path modTime sidecar 113 return $ Just $ InputFile path modTime sidecar thumbnail
108 mkInputNode File{} = return Nothing 114 mkInputNode _ File{} = return Nothing
109 mkInputNode dir@Dir{} = mkDirNode dir >>= return . Just 115 mkInputNode _ dir@Dir{} = Just <$> mkDirNode dir
110 116
111 mkDirNode :: FSNode -> IO InputTree 117 mkDirNode :: FSNode -> IO InputTree
112 mkDirNode File{} = throw $ AssertionFailed "Input directory is a file" 118 mkDirNode File{} = throw $ AssertionFailed "Input directory is a file"
113 mkDirNode Dir{path, items} = 119 mkDirNode Dir{path, items} =
114 do 120 do
115 dirItems <- mapM mkInputNode items 121 dirItems <- mapM (mkInputNode $ Map.fromList (map withBaseName items)) items
116 modTime <- getModificationTime $ localPath (anchor /> path) 122 modTime <- getModificationTime $ localPath (anchor /> path)
117 sidecar <- readSidecarFile $ localPath (anchor /> path </> dirSidecar) 123 sidecar <- readSidecarFile $ localPath (anchor /> path </> dirSidecar)
118 return $ InputDir path modTime sidecar (findThumbnail items) (catMaybes dirItems) 124 return $ InputDir path modTime sidecar (findDirThumbnail items) (catMaybes dirItems)
125
126 withBaseName :: FSNode -> (FileName, FSNode)
127 withBaseName node = (fromMaybe "" $ baseName $ Files.path node, node)
128
129 findFileThumbnail :: FileName -> Map.Map FileName FSNode -> Maybe Path
130 findFileThumbnail name dict = Files.path <$> Map.lookup (name ++ thumbnailSuffix) dict
119 131
120 isSidecar :: FSNode -> Bool 132 isSidecar :: FSNode -> Bool
121 isSidecar Dir{} = False 133 isSidecar Dir{} = False
122 isSidecar File{path} = 134 isSidecar File{path} = fileName path & maybe False (isExtensionOf sidecarExt)
123 fileName path 135
124 & (maybe False $ isExtensionOf sidecarExt) 136 baseName :: Path -> Maybe FileName
137 baseName = fmap dropExtension . fileName
125 138
126 isThumbnail :: FSNode -> Bool 139 isThumbnail :: FSNode -> Bool
127 isThumbnail Dir{} = False 140 isThumbnail Dir{} = False
128 isThumbnail File{path} = 141 isThumbnail File{path} = baseName path & maybe False (thumbnailSuffix `isSuffixOf`)
129 fileName path 142
130 & fmap dropExtension 143 isDirThumbnail :: FSNode -> Bool
131 & (maybe False (dirPropFile ==)) 144 isDirThumbnail Dir{} = False
145 isDirThumbnail File{path} = baseName path & (== Just thumbnailSuffix)
146
147 findDirThumbnail :: [FSNode] -> Maybe Path
148 findDirThumbnail = fmap Files.path . find isDirThumbnail
132 149
133 findThumbnail :: [FSNode] -> Maybe Path
134 findThumbnail = (fmap Files.path) . (find isThumbnail)
135 150
136-- | Filters an InputTree. The root is always returned. 151-- | Filters an InputTree. The root is always returned.
137filterInputTree :: (InputTree -> Bool) -> InputTree -> InputTree 152filterInputTree :: (InputTree -> Bool) -> InputTree -> InputTree
diff --git a/compiler/src/ItemProcessors.hs b/compiler/src/ItemProcessors.hs
new file mode 100644
index 0000000..f967954
--- /dev/null
+++ b/compiler/src/ItemProcessors.hs
@@ -0,0 +1,115 @@
1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19module ItemProcessors
20 ( ItemProcessor
21 , itemFileProcessor
22 , thumbnailFileProcessor
23 ) where
24
25
26import Data.Char (toLower)
27import System.FilePath (takeExtension)
28
29import Config (Resolution(..))
30import Resource (ItemProcessor, Thumbnail(..), GalleryItemProps(..))
31import Caching (Cache)
32import FileProcessors
33import Files
34
35
36data Format =
37 PictureFormat
38 | PlainTextFormat
39 | PortableDocumentFormat
40 | VideoFormat
41 | AudioFormat
42 | Unknown
43
44formatFromPath :: Path -> Format
45formatFromPath =
46 maybe Unknown ((fromExt . map toLower) . takeExtension) . fileName
47 where
48 fromExt :: String -> Format
49 fromExt ext = case ext of
50 ".bmp" -> PictureFormat
51 ".jpg" -> PictureFormat
52 ".jpeg" -> PictureFormat
53 ".png" -> PictureFormat
54 ".tiff" -> PictureFormat
55 ".hdr" -> PictureFormat
56 ".gif" -> PictureFormat
57 ".txt" -> PlainTextFormat
58 ".md" -> PlainTextFormat -- TODO: handle markdown separately
59 ".pdf" -> PortableDocumentFormat
60 ".wav" -> AudioFormat
61 ".oga" -> AudioFormat
62 ".ogg" -> AudioFormat
63 ".spx" -> AudioFormat
64 ".opus" -> AudioFormat
65 ".flac" -> AudioFormat
66 ".m4a" -> AudioFormat
67 ".mp3" -> AudioFormat
68 ".ogv" -> VideoFormat
69 ".ogx" -> VideoFormat
70 ".webm" -> VideoFormat
71 ".mkv" -> VideoFormat
72 ".mp4" -> VideoFormat
73 _ -> Unknown
74
75
76type ItemFileProcessor a =
77 FilePath -- ^ Filesystem input base path
78 -> FilePath -- ^ Filesystem output base path
79 -> FileName -- ^ Output class (subdir)
80 -> ItemProcessor a
81
82
83callFileProcessor :: (Path -> FileProcessor a) -> Cache a -> ItemFileProcessor a
84callFileProcessor processorProvider withCache inputBase outputBase resClass itemPath resPath =
85 withCache (processorProvider resPath)
86 itemPath
87 (resClass /> resPath)
88 (localPath $ inputBase /> resPath)
89 (localPath $ outputBase /> (resClass /> resPath))
90
91
92itemFileProcessor :: Maybe Resolution -> Cache GalleryItemProps -> ItemFileProcessor GalleryItemProps
93itemFileProcessor maxResolution =
94 callFileProcessor (flip processorFor maxResolution . formatFromPath)
95 where
96 processorFor :: Format -> Maybe Resolution -> FileProcessor GalleryItemProps
97 processorFor PictureFormat (Just maxRes) =
98 transformThenDescribe (resizePictureUpTo maxRes) getPictureProps
99 processorFor PictureFormat Nothing =
100 transformThenDescribe copyFileProcessor getPictureProps
101 processorFor PlainTextFormat _ = copyResource PlainText
102 processorFor PortableDocumentFormat _ = copyResource PDF
103 processorFor VideoFormat _ = copyResource Video
104 processorFor AudioFormat _ = copyResource Audio
105 processorFor Unknown _ = copyResource Other
106 -- TODO: handle video reencoding and others?
107
108
109thumbnailFileProcessor :: Resolution -> Cache (Maybe Thumbnail) -> ItemFileProcessor (Maybe Thumbnail)
110thumbnailFileProcessor maxRes =
111 callFileProcessor (processorFor . formatFromPath)
112 where
113 processorFor :: Format -> FileProcessor (Maybe Thumbnail)
114 processorFor PictureFormat = transformThenDescribe (resizePictureUpTo maxRes) getThumbnailProps
115 processorFor _ = noopProcessor
diff --git a/compiler/src/Processors.hs b/compiler/src/Processors.hs
deleted file mode 100644
index 02db325..0000000
--- a/compiler/src/Processors.hs
+++ /dev/null
@@ -1,203 +0,0 @@
1-- ldgallery - A static generator which turns a collection of tagged
2-- pictures into a searchable web gallery.
3--
4-- Copyright (C) 2019-2020 Pacien TRAN-GIRARD
5--
6-- This program is free software: you can redistribute it and/or modify
7-- it under the terms of the GNU Affero General Public License as
8-- published by the Free Software Foundation, either version 3 of the
9-- License, or (at your option) any later version.
10--
11-- This program is distributed in the hope that it will be useful,
12-- but WITHOUT ANY WARRANTY; without even the implied warranty of
13-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14-- GNU Affero General Public License for more details.
15--
16-- You should have received a copy of the GNU Affero General Public License
17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19module Processors
20 ( Resolution(..)
21 , ItemFileProcessor, itemFileProcessor
22 , ThumbnailFileProcessor, thumbnailFileProcessor
23 , skipCached, withCached
24 ) where
25
26
27import Control.Exception (Exception, throwIO)
28import Control.Monad (when)
29import Data.Function ((&))
30import Data.Char (toLower)
31import Text.Read (readMaybe)
32
33import System.Directory hiding (copyFile)
34import qualified System.Directory
35import System.FilePath
36
37import System.Process (callProcess, readProcess)
38
39import Resource
40 ( ItemProcessor, ThumbnailProcessor
41 , GalleryItemProps(..), Resolution(..), Resource(..), Thumbnail(..) )
42
43import Files
44
45
46data ProcessingException = ProcessingException FilePath String deriving Show
47instance Exception ProcessingException
48
49
50-- TODO: handle video, music, text...
51data Format = PictureFormat | Unknown
52
53formatFromPath :: Path -> Format
54formatFromPath =
55 maybe Unknown fromExt
56 . fmap (map toLower)
57 . fmap takeExtension
58 . fileName
59 where
60 fromExt :: String -> Format
61 fromExt ext = case ext of
62 ".bmp" -> PictureFormat
63 ".jpg" -> PictureFormat
64 ".jpeg" -> PictureFormat
65 ".png" -> PictureFormat
66 ".tiff" -> PictureFormat
67 ".hdr" -> PictureFormat
68 ".gif" -> PictureFormat
69 _ -> Unknown
70
71
72type FileProcessor =
73 FileName -- ^ Input path
74 -> FileName -- ^ Output path
75 -> IO ()
76
77copyFileProcessor :: FileProcessor
78copyFileProcessor inputPath outputPath =
79 (putStrLn $ "Copying:\t" ++ outputPath)
80 >> ensureParentDir (flip System.Directory.copyFile) outputPath inputPath
81
82resizePictureUpTo :: Resolution -> FileProcessor
83resizePictureUpTo maxResolution inputPath outputPath =
84 (putStrLn $ "Generating:\t" ++ outputPath)
85 >> ensureParentDir (flip resize) outputPath inputPath
86 where
87 maxSize :: Resolution -> String
88 maxSize Resolution{width, height} = show width ++ "x" ++ show height ++ ">"
89
90 resize :: FileName -> FileName -> IO ()
91 resize input output = callProcess "magick"
92 [ input
93 , "-auto-orient"
94 , "-resize", maxSize maxResolution
95 , output ]
96
97
98type Cache = FileProcessor -> FileProcessor
99
100skipCached :: Cache
101skipCached processor inputPath outputPath =
102 removePathForcibly outputPath
103 >> processor inputPath outputPath
104
105withCached :: Cache
106withCached processor inputPath outputPath =
107 do
108 isDir <- doesDirectoryExist outputPath
109 when isDir $ removePathForcibly outputPath
110
111 fileExists <- doesFileExist outputPath
112 if fileExists then
113 do
114 needUpdate <- isOutdated True inputPath outputPath
115 if needUpdate then update else skip
116 else
117 update
118
119 where
120 update = processor inputPath outputPath
121 skip = putStrLn $ "Skipping:\t" ++ outputPath
122
123
124resourceAt :: FilePath -> Path -> IO Resource
125resourceAt fsPath resPath = getModificationTime fsPath >>= return . Resource resPath
126
127getImageResolution :: FilePath -> IO Resolution
128getImageResolution fsPath =
129 readProcess "magick" ["identify", "-format", "%w %h", firstFrame] []
130 >>= parseResolution . break (== ' ')
131 where
132 firstFrame :: FilePath
133 firstFrame = fsPath ++ "[0]"
134
135 parseResolution :: (String, String) -> IO Resolution
136 parseResolution (widthString, heightString) =
137 case (readMaybe widthString, readMaybe heightString) of
138 (Just w, Just h) -> return $ Resolution w h
139 _ -> throwIO $ ProcessingException fsPath "Unable to read image resolution."
140
141getPictureProps :: ItemDescriber
142getPictureProps fsPath resource =
143 getImageResolution fsPath
144 >>= return . Picture resource
145
146
147type ItemDescriber =
148 FilePath
149 -> Resource
150 -> IO GalleryItemProps
151
152
153type ItemFileProcessor =
154 FileName -- ^ Input base path
155 -> FileName -- ^ Output base path
156 -> FileName -- ^ Output class (subdir)
157 -> ItemProcessor
158
159itemFileProcessor :: Maybe Resolution -> Cache -> ItemFileProcessor
160itemFileProcessor maxResolution cached inputBase outputBase resClass inputRes =
161 cached processor inPath outPath
162 >> resourceAt outPath relOutPath
163 >>= descriptor outPath
164 where
165 relOutPath = resClass /> inputRes
166 inPath = localPath $ inputBase /> inputRes
167 outPath = localPath $ outputBase /> relOutPath
168 (processor, descriptor) = processorFor (formatFromPath inputRes) maxResolution
169
170 processorFor :: Format -> Maybe Resolution -> (FileProcessor, ItemDescriber)
171 processorFor PictureFormat (Just maxRes) = (resizePictureUpTo maxRes, getPictureProps)
172 processorFor PictureFormat Nothing = (copyFileProcessor, getPictureProps)
173 -- TODO: handle video reencoding and others?
174 processorFor Unknown _ = (copyFileProcessor, const $ return . Other)
175
176
177type ThumbnailFileProcessor =
178 FileName -- ^ Input base path
179 -> FileName -- ^ Output base path
180 -> FileName -- ^ Output class (subdir)
181 -> ThumbnailProcessor
182
183thumbnailFileProcessor :: Resolution -> Cache -> ThumbnailFileProcessor
184thumbnailFileProcessor maxRes cached inputBase outputBase resClass inputRes =
185 cached <$> processorFor (formatFromPath inputRes)
186 & process
187 where
188 relOutPath = resClass /> inputRes
189 inPath = localPath $ inputBase /> inputRes
190 outPath = localPath $ outputBase /> relOutPath
191
192 process :: Maybe FileProcessor -> IO (Maybe Thumbnail)
193 process Nothing = return Nothing
194 process (Just proc) =
195 do
196 proc inPath outPath
197 resource <- resourceAt outPath relOutPath
198 resolution <- getImageResolution outPath
199 return $ Just $ Thumbnail resource resolution
200
201 processorFor :: Format -> Maybe FileProcessor
202 processorFor PictureFormat = Just $ resizePictureUpTo maxRes
203 processorFor _ = Nothing
diff --git a/compiler/src/Resource.hs b/compiler/src/Resource.hs
index e134468..f59eed6 100644
--- a/compiler/src/Resource.hs
+++ b/compiler/src/Resource.hs
@@ -17,9 +17,15 @@
17-- along with this program. If not, see <https://www.gnu.org/licenses/>. 17-- along with this program. If not, see <https://www.gnu.org/licenses/>.
18 18
19module Resource 19module Resource
20 ( ItemProcessor, ThumbnailProcessor 20 ( ItemProcessor
21 , GalleryItem(..), GalleryItemProps(..), Resolution(..), Resource(..), Thumbnail(..) 21 , GalleryItem(..)
22 , buildGalleryTree, galleryCleanupResourceDir 22 , GalleryItemProps(..)
23 , Resolution(..)
24 , Resource(..)
25 , Thumbnail(..)
26 , buildGalleryTree
27 , galleryCleanupResourceDir
28 , flattenGalleryTree
23 ) where 29 ) where
24 30
25 31
@@ -29,15 +35,16 @@ import Data.List.Ordered (minusBy)
29import Data.Char (toLower) 35import Data.Char (toLower)
30import Data.Maybe (mapMaybe, fromMaybe) 36import Data.Maybe (mapMaybe, fromMaybe)
31import Data.Function ((&)) 37import Data.Function ((&))
38import Data.Functor ((<&>))
32import qualified Data.Set as Set 39import qualified Data.Set as Set
33import Data.Text (pack) 40import Data.Text (pack, unpack, breakOn)
34import Data.Time.Clock (UTCTime) 41import Data.Time.Clock (UTCTime)
35import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC) 42import Data.Time.LocalTime (ZonedTime, utc, utcToZonedTime, zonedTimeToUTC)
36import Data.Time.Format (formatTime, defaultTimeLocale) 43import Data.Time.Format (formatTime, parseTimeM, defaultTimeLocale)
37import Safe.Foldable (maximumByMay) 44import Safe.Foldable (maximumByMay)
38 45
39import GHC.Generics (Generic) 46import GHC.Generics (Generic)
40import Data.Aeson (ToJSON, genericToJSON, genericToEncoding) 47import Data.Aeson (ToJSON, FromJSON, genericToJSON, genericToEncoding, genericParseJSON)
41import qualified Data.Aeson as JSON 48import qualified Data.Aeson as JSON
42 49
43import Files 50import Files
@@ -69,12 +76,23 @@ instance ToJSON Resource where
69 where 76 where
70 timestamp = formatTime defaultTimeLocale "%s" modTime 77 timestamp = formatTime defaultTimeLocale "%s" modTime
71 78
79instance FromJSON Resource where
80 parseJSON = JSON.withText "Resource" (unpackRes . breakOn "?")
81 where
82 unpackRes (resPathStr, modTimeStr) =
83 Resource (fromWebPath $ unpack resPathStr)
84 <$> parseTimeM True defaultTimeLocale "?%s" (unpack modTimeStr)
85
72 86
73data GalleryItemProps = 87data GalleryItemProps =
74 Directory { items :: [GalleryItem] } 88 Directory { items :: [GalleryItem] }
75 | Picture 89 | Picture
76 { resource :: Resource 90 { resource :: Resource
77 , resolution :: Resolution } 91 , resolution :: Resolution }
92 | PlainText { resource :: Resource }
93 | PDF { resource :: Resource }
94 | Video { resource :: Resource }
95 | Audio { resource :: Resource }
78 | Other { resource :: Resource } 96 | Other { resource :: Resource }
79 deriving (Generic, Show) 97 deriving (Generic, Show)
80 98
@@ -82,15 +100,14 @@ instance ToJSON GalleryItemProps where
82 toJSON = genericToJSON encodingOptions 100 toJSON = genericToJSON encodingOptions
83 toEncoding = genericToEncoding encodingOptions 101 toEncoding = genericToEncoding encodingOptions
84 102
103instance FromJSON GalleryItemProps where
104 parseJSON = genericParseJSON encodingOptions
105
85 106
86data Thumbnail = Thumbnail 107data Thumbnail = Thumbnail
87 { resource :: Resource 108 { resource :: Resource
88 , resolution :: Resolution 109 , resolution :: Resolution
89 } deriving (Generic, Show) 110 } deriving (Generic, Show, ToJSON, FromJSON)
90
91instance ToJSON Thumbnail where
92 toJSON = genericToJSON encodingOptions
93 toEncoding = genericToEncoding encodingOptions
94 111
95 112
96data GalleryItem = GalleryItem 113data GalleryItem = GalleryItem
@@ -101,49 +118,49 @@ data GalleryItem = GalleryItem
101 , path :: Path 118 , path :: Path
102 , thumbnail :: Maybe Thumbnail 119 , thumbnail :: Maybe Thumbnail
103 , properties :: GalleryItemProps 120 , properties :: GalleryItemProps
104 } deriving (Generic, Show) 121 } deriving (Generic, Show, ToJSON, FromJSON)
105
106instance ToJSON GalleryItem where
107 toJSON = genericToJSON encodingOptions
108 toEncoding = genericToEncoding encodingOptions
109 122
110 123
111type ItemProcessor = Path -> IO GalleryItemProps 124type ItemProcessor a =
112type ThumbnailProcessor = Path -> IO (Maybe Thumbnail) 125 Path -- Item path
126 -> Path -- Resource Path
127 -> IO a
113 128
114 129
115buildGalleryTree :: 130buildGalleryTree ::
116 ItemProcessor -> ThumbnailProcessor -> TagsFromDirectoriesConfig 131 ItemProcessor GalleryItemProps -> ItemProcessor (Maybe Thumbnail) -> TagsFromDirectoriesConfig
117 -> InputTree -> IO GalleryItem 132 -> InputTree -> IO GalleryItem
118buildGalleryTree processItem processThumbnail tagsFromDirsConfig inputTree = 133buildGalleryTree processItem processThumbnail tagsFromDirsConfig =
119 mkGalleryItem [] inputTree 134 mkGalleryItem []
120 where 135 where
121 mkGalleryItem :: [Tag] -> InputTree -> IO GalleryItem 136 mkGalleryItem :: [Tag] -> InputTree -> IO GalleryItem
122 mkGalleryItem inheritedTags InputFile{path, modTime, sidecar} = 137 mkGalleryItem inheritedTags InputFile{path, modTime, sidecar, thumbnailPath} =
123 do 138 do
124 properties <- processItem path 139 let itemPath = "/" /> path
125 processedThumbnail <- processThumbnail path 140 properties <- processItem itemPath path
141 processedThumbnail <- processThumbnail itemPath (thumbnailPath ?? path)
126 return GalleryItem 142 return GalleryItem
127 { title = Input.title sidecar ?? fileName path ?? "" 143 { title = Input.title sidecar ?? fileName path ?? ""
128 , datetime = Input.datetime sidecar ?? toZonedTime modTime 144 , datetime = Input.datetime sidecar ?? toZonedTime modTime
129 , description = Input.description sidecar ?? "" 145 , description = Input.description sidecar ?? ""
130 , tags = unique ((Input.tags sidecar ?? []) ++ inheritedTags ++ parentDirTags path) 146 , tags = unique ((Input.tags sidecar ?? []) ++ inheritedTags ++ parentDirTags path)
131 , path = "/" /> path 147 , path = itemPath
132 , thumbnail = processedThumbnail 148 , thumbnail = processedThumbnail
133 , properties = properties } 149 , properties = properties }
134 150
135 mkGalleryItem inheritedTags InputDir{path, modTime, sidecar, dirThumbnailPath, items} = 151 mkGalleryItem inheritedTags InputDir{path, modTime, sidecar, thumbnailPath, items} =
136 do 152 do
153 let itemPath = "/" /> path
137 let dirTags = (Input.tags sidecar ?? []) ++ inheritedTags 154 let dirTags = (Input.tags sidecar ?? []) ++ inheritedTags
138 processedItems <- parallel $ map (mkGalleryItem dirTags) items 155 processedItems <- parallel $ map (mkGalleryItem dirTags) items
139 processedThumbnail <- maybeThumbnail dirThumbnailPath 156 processedThumbnail <- maybeThumbnail itemPath thumbnailPath
140 return GalleryItem 157 return GalleryItem
141 { title = Input.title sidecar ?? fileName path ?? "" 158 { title = Input.title sidecar ?? fileName path ?? ""
142 , datetime = Input.datetime sidecar ?? mostRecentModTime processedItems 159 , datetime = Input.datetime sidecar ?? mostRecentModTime processedItems
143 ?? toZonedTime modTime 160 ?? toZonedTime modTime
144 , description = Input.description sidecar ?? "" 161 , description = Input.description sidecar ?? ""
145 , tags = unique (aggregateTags processedItems ++ parentDirTags path) 162 , tags = unique (aggregateTags processedItems ++ parentDirTags path)
146 , path = "/" /> path 163 , path = itemPath
147 , thumbnail = processedThumbnail 164 , thumbnail = processedThumbnail
148 , properties = Directory processedItems } 165 , properties = Directory processedItems }
149 166
@@ -163,9 +180,9 @@ buildGalleryTree processItem processThumbnail tagsFromDirsConfig inputTree =
163 aggregateTags :: [GalleryItem] -> [Tag] 180 aggregateTags :: [GalleryItem] -> [Tag]
164 aggregateTags = concatMap (\item -> tags (item::GalleryItem)) 181 aggregateTags = concatMap (\item -> tags (item::GalleryItem))
165 182
166 maybeThumbnail :: Maybe Path -> IO (Maybe Thumbnail) 183 maybeThumbnail :: Path -> Maybe Path -> IO (Maybe Thumbnail)
167 maybeThumbnail Nothing = return Nothing 184 maybeThumbnail _ Nothing = return Nothing
168 maybeThumbnail (Just thumbnailPath) = processThumbnail thumbnailPath 185 maybeThumbnail itemPath (Just thumbnailPath) = processThumbnail itemPath thumbnailPath
169 186
170 mostRecentModTime :: [GalleryItem] -> Maybe ZonedTime 187 mostRecentModTime :: [GalleryItem] -> Maybe ZonedTime
171 mostRecentModTime = 188 mostRecentModTime =
@@ -186,7 +203,7 @@ flattenGalleryTree simple = [simple]
186 203
187galleryOutputDiff :: GalleryItem -> FSNode -> [Path] 204galleryOutputDiff :: GalleryItem -> FSNode -> [Path]
188galleryOutputDiff resources ref = 205galleryOutputDiff resources ref =
189 (filesystemPaths ref) \\ (compiledPaths $ flattenGalleryTree resources) 206 filesystemPaths ref \\ compiledPaths (flattenGalleryTree resources)
190 where 207 where
191 filesystemPaths :: FSNode -> [Path] 208 filesystemPaths :: FSNode -> [Path]
192 filesystemPaths = map Files.path . tail . flattenDir 209 filesystemPaths = map Files.path . tail . flattenDir
@@ -208,8 +225,7 @@ galleryOutputDiff resources ref =
208 225
209 thumbnailPaths :: [GalleryItem] -> [Path] 226 thumbnailPaths :: [GalleryItem] -> [Path]
210 thumbnailPaths = 227 thumbnailPaths =
211 map resourcePath 228 map (resourcePath . (resource :: (Thumbnail -> Resource)))
212 . map (resource :: (Thumbnail -> Resource))
213 . mapMaybe thumbnail 229 . mapMaybe thumbnail
214 230
215 (\\) :: [Path] -> [Path] -> [Path] 231 (\\) :: [Path] -> [Path] -> [Path]
@@ -231,7 +247,7 @@ galleryOutputDiff resources ref =
231galleryCleanupResourceDir :: GalleryItem -> FileName -> IO () 247galleryCleanupResourceDir :: GalleryItem -> FileName -> IO ()
232galleryCleanupResourceDir resourceTree outputDir = 248galleryCleanupResourceDir resourceTree outputDir =
233 readDirectory outputDir 249 readDirectory outputDir
234 >>= return . galleryOutputDiff resourceTree . root 250 <&> galleryOutputDiff resourceTree . root
235 >>= return . sortOn ((0 -) . pathLength) -- nested files before their parent dirs 251 <&> sortOn ((0 -) . pathLength) -- nested files before their parent dirs
236 >>= return . map (localPath . (/>) outputDir) 252 <&> map (localPath . (/>) outputDir)
237 >>= mapM_ remove 253 >>= mapM_ remove
diff --git a/example/config.json b/example/config.json
index 6483257..2454113 100644
--- a/example/config.json
+++ b/example/config.json
@@ -1,3 +1,6 @@
1{ 1{
2 "galleryRoot": "out/" 2 "galleryRoot": "out/",
3 "galleryIndex": "index.json",
4 "initialItemSort": "date_asc",
5 "initialTagDisplayLimit": 10
3} 6}
diff --git a/example/src/Misc Media/A Trip to the Moon.mp4 b/example/src/Misc Media/A Trip to the Moon.mp4
new file mode 100644
index 0000000..b268c10
--- /dev/null
+++ b/example/src/Misc Media/A Trip to the Moon.mp4
Binary files differ
diff --git a/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg b/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg
new file mode 100644
index 0000000..e5f9653
--- /dev/null
+++ b/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg
Binary files differ
diff --git a/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg_thumbnail.jpg b/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg_thumbnail.jpg
new file mode 100644
index 0000000..7795eb9
--- /dev/null
+++ b/example/src/Misc Media/Beethoven - Fifth Symphony intro.ogg_thumbnail.jpg
Binary files differ
diff --git a/example/src/Misc Media/European Social Charter (Revised).pdf b/example/src/Misc Media/European Social Charter (Revised).pdf
new file mode 100644
index 0000000..422a17e
--- /dev/null
+++ b/example/src/Misc Media/European Social Charter (Revised).pdf
Binary files differ
diff --git a/example/src/Misc Media/Universal Declaration of Human Rights.txt b/example/src/Misc Media/Universal Declaration of Human Rights.txt
new file mode 100644
index 0000000..1d7e539
--- /dev/null
+++ b/example/src/Misc Media/Universal Declaration of Human Rights.txt
@@ -0,0 +1,157 @@
1Universal Declaration of Human Rights
2
3Preamble
4Whereas recognition of the inherent dignity and of the equal and inalienable rights of all members of the human family is the foundation of freedom, justice and peace in the world,
5
6Whereas disregard and contempt for human rights have resulted in barbarous acts which have outraged the conscience of mankind, and the advent of a world in which human beings shall enjoy freedom of speech and belief and freedom from fear and want has been proclaimed as the highest aspiration of the common people,
7
8Whereas it is essential, if man is not to be compelled to have recourse, as a last resort, to rebellion against tyranny and oppression, that human rights should be protected by the rule of law,
9
10Whereas it is essential to promote the development of friendly relations between nations,
11
12Whereas the peoples of the United Nations have in the Charter reaffirmed their faith in fundamental human rights, in the dignity and worth of the human person and in the equal rights of men and women and have determined to promote social progress and better standards of life in larger freedom,
13
14Whereas Member States have pledged themselves to achieve, in co-operation with the United Nations, the promotion of universal respect for and observance of human rights and fundamental freedoms,
15
16Whereas a common understanding of these rights and freedoms is of the greatest importance for the full realization of this pledge,
17
18Now, Therefore THE GENERAL ASSEMBLY proclaims THIS UNIVERSAL DECLARATION OF HUMAN RIGHTS as a common standard of achievement for all peoples and all nations, to the end that every individual and every organ of society, keeping this Declaration constantly in mind, shall strive by teaching and education to promote respect for these rights and freedoms and by progressive measures, national and international, to secure their universal and effective recognition and observance, both among the peoples of Member States themselves and among the peoples of territories under their jurisdiction.
19
20Article 1.
21
22All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood.
23
24Article 2.
25
26Everyone is entitled to all the rights and freedoms set forth in this Declaration, without distinction of any kind, such as race, colour, sex, language, religion, political or other opinion, national or social origin, property, birth or other status. Furthermore, no distinction shall be made on the basis of the political, jurisdictional or international status of the country or territory to which a person belongs, whether it be independent, trust, non-self-governing or under any other limitation of sovereignty.
27
28Article 3.
29
30Everyone has the right to life, liberty and security of person.
31
32Article 4.
33
34No one shall be held in slavery or servitude; slavery and the slave trade shall be prohibited in all their forms.
35
36Article 5.
37
38No one shall be subjected to torture or to cruel, inhuman or degrading treatment or punishment.
39
40Article 6.
41
42Everyone has the right to recognition everywhere as a person before the law.
43
44Article 7.
45
46All are equal before the law and are entitled without any discrimination to equal protection of the law. All are entitled to equal protection against any discrimination in violation of this Declaration and against any incitement to such discrimination.
47
48Article 8.
49
50Everyone has the right to an effective remedy by the competent national tribunals for acts violating the fundamental rights granted him by the constitution or by law.
51
52Article 9.
53
54No one shall be subjected to arbitrary arrest, detention or exile.
55
56Article 10.
57
58Everyone is entitled in full equality to a fair and public hearing by an independent and impartial tribunal, in the determination of his rights and obligations and of any criminal charge against him.
59
60Article 11.
61
62(1) Everyone charged with a penal offence has the right to be presumed innocent until proved guilty according to law in a public trial at which he has had all the guarantees necessary for his defence.
63(2) No one shall be held guilty of any penal offence on account of any act or omission which did not constitute a penal offence, under national or international law, at the time when it was committed. Nor shall a heavier penalty be imposed than the one that was applicable at the time the penal offence was committed.
64
65Article 12.
66
67No one shall be subjected to arbitrary interference with his privacy, family, home or correspondence, nor to attacks upon his honour and reputation. Everyone has the right to the protection of the law against such interference or attacks.
68
69Article 13.
70
71(1) Everyone has the right to freedom of movement and residence within the borders of each state.
72(2) Everyone has the right to leave any country, including his own, and to return to his country.
73
74Article 14.
75
76(1) Everyone has the right to seek and to enjoy in other countries asylum from persecution.
77(2) This right may not be invoked in the case of prosecutions genuinely arising from non-political crimes or from acts contrary to the purposes and principles of the United Nations.
78
79Article 15.
80
81(1) Everyone has the right to a nationality.
82(2) No one shall be arbitrarily deprived of his nationality nor denied the right to change his nationality.
83
84Article 16.
85
86(1) Men and women of full age, without any limitation due to race, nationality or religion, have the right to marry and to found a family. They are entitled to equal rights as to marriage, during marriage and at its dissolution.
87(2) Marriage shall be entered into only with the free and full consent of the intending spouses.
88(3) The family is the natural and fundamental group unit of society and is entitled to protection by society and the State.
89
90Article 17.
91
92(1) Everyone has the right to own property alone as well as in association with others.
93(2) No one shall be arbitrarily deprived of his property.
94
95Article 18.
96
97Everyone has the right to freedom of thought, conscience and religion; this right includes freedom to change his religion or belief, and freedom, either alone or in community with others and in public or private, to manifest his religion or belief in teaching, practice, worship and observance.
98
99Article 19.
100
101Everyone has the right to freedom of opinion and expression; this right includes freedom to hold opinions without interference and to seek, receive and impart information and ideas through any media and regardless of frontiers.
102
103Article 20.
104
105(1) Everyone has the right to freedom of peaceful assembly and association.
106(2) No one may be compelled to belong to an association.
107
108Article 21.
109
110(1) Everyone has the right to take part in the government of his country, directly or through freely chosen representatives.
111(2) Everyone has the right of equal access to public service in his country.
112(3) The will of the people shall be the basis of the authority of government; this will shall be expressed in periodic and genuine elections which shall be by universal and equal suffrage and shall be held by secret vote or by equivalent free voting procedures.
113
114Article 22.
115
116Everyone, as a member of society, has the right to social security and is entitled to realization, through national effort and international co-operation and in accordance with the organization and resources of each State, of the economic, social and cultural rights indispensable for his dignity and the free development of his personality.
117
118Article 23.
119
120(1) Everyone has the right to work, to free choice of employment, to just and favourable conditions of work and to protection against unemployment.
121(2) Everyone, without any discrimination, has the right to equal pay for equal work.
122(3) Everyone who works has the right to just and favourable remuneration ensuring for himself and his family an existence worthy of human dignity, and supplemented, if necessary, by other means of social protection.
123(4) Everyone has the right to form and to join trade unions for the protection of his interests.
124
125Article 24.
126
127Everyone has the right to rest and leisure, including reasonable limitation of working hours and periodic holidays with pay.
128
129Article 25.
130
131(1) Everyone has the right to a standard of living adequate for the health and well-being of himself and of his family, including food, clothing, housing and medical care and necessary social services, and the right to security in the event of unemployment, sickness, disability, widowhood, old age or other lack of livelihood in circumstances beyond his control.
132(2) Motherhood and childhood are entitled to special care and assistance. All children, whether born in or out of wedlock, shall enjoy the same social protection.
133
134Article 26.
135
136(1) Everyone has the right to education. Education shall be free, at least in the elementary and fundamental stages. Elementary education shall be compulsory. Technical and professional education shall be made generally available and higher education shall be equally accessible to all on the basis of merit.
137(2) Education shall be directed to the full development of the human personality and to the strengthening of respect for human rights and fundamental freedoms. It shall promote understanding, tolerance and friendship among all nations, racial or religious groups, and shall further the activities of the United Nations for the maintenance of peace.
138(3) Parents have a prior right to choose the kind of education that shall be given to their children.
139
140Article 27.
141
142(1) Everyone has the right freely to participate in the cultural life of the community, to enjoy the arts and to share in scientific advancement and its benefits.
143(2) Everyone has the right to the protection of the moral and material interests resulting from any scientific, literary or artistic production of which he is the author.
144
145Article 28.
146
147Everyone is entitled to a social and international order in which the rights and freedoms set forth in this Declaration can be fully realized.
148
149Article 29.
150
151(1) Everyone has duties to the community in which alone the free and full development of his personality is possible.
152(2) In the exercise of his rights and freedoms, everyone shall be subject only to such limitations as are determined by law solely for the purpose of securing due recognition and respect for the rights and freedoms of others and of meeting the just requirements of morality, public order and the general welfare in a democratic society.
153(3) These rights and freedoms may in no case be exercised contrary to the purposes and principles of the United Nations.
154
155Article 30.
156
157Nothing in this Declaration may be interpreted as implying for any State, group or person any right to engage in any activity or to perform any act aimed at the destruction of any of the rights and freedoms set forth herein.
diff --git a/example/src/Ormont-Dessus/_directory.jpg b/example/src/Ormont-Dessus/_thumbnail.jpg
index 19a716e..19a716e 100644
--- a/example/src/Ormont-Dessus/_directory.jpg
+++ b/example/src/Ormont-Dessus/_thumbnail.jpg
Binary files differ
diff --git a/example/src/gallery.yaml b/example/src/gallery.yaml
index b569910..fc91313 100644
--- a/example/src/gallery.yaml
+++ b/example/src/gallery.yaml
@@ -7,6 +7,10 @@
7 7
8includedFiles: 8includedFiles:
9 - '*.jpg' 9 - '*.jpg'
10 - '*.txt'
11 - '*.pdf'
12 - '*.ogg'
13 - '*.mp4'
10 14
11#excludedFiles: 15#excludedFiles:
12# - "*.md" 16# - "*.md"
diff --git a/ldgallery-quickstart.7.md b/ldgallery-quickstart.7.md
index 2154d20..4c93f51 100644
--- a/ldgallery-quickstart.7.md
+++ b/ldgallery-quickstart.7.md
@@ -2,27 +2,41 @@
2pagetitle: Quickstart guide - ldgallery 2pagetitle: Quickstart guide - ldgallery
3title: LDGALLERY-QUICKSTART(7) ldgallery 3title: LDGALLERY-QUICKSTART(7) ldgallery
4author: Pacien TRAN-GIRARD, Guillaume FOUET 4author: Pacien TRAN-GIRARD, Guillaume FOUET
5date: 2020-05-01 (v1.0) 5date: 2020-09-19 (v2.0)
6--- 6---
7 7
8# ABOUT 8# ABOUT
9 9
10This document is a step-by-step guide showing how to create, compile and deploy a new gallery with _ldgallery_. 10This document is a step-by-step guide showing how to create and compile a simple gallery and get familiar with _ldgallery_.
11 11
12It mainly describes how to structure the source gallery directory accepted by the _ldgallery_ compiler.
12 13
13# QUICKSTART GUIDE 14```
15[source gallery directory with items and their tags]
16 |
17 | ldgallery compiler
18 v
19[generated web gallery with embedded web viewer]
20 |
21 | copy
22 v
23[web server]
24```
14 25
15## Step 1: setting up the compiler
16 26
17The _ldgallery_ compiler's job is to transform a directory containing pictures and other types of items, alongside additional metadata to associate to those, into a gallery that can be viewed in a web browser. 27# QUICKSTART GUIDE
18 28
19This compiler program is typically installed and runs on the computer of the gallery's owner. 29## Step 1: initialising the gallery source directory
20 30
21It can be installed through a package manager (package name "ldgallery") or manually by extracting a prebuilt archive available on the project's website <https://ldgallery.pacien.org>. 31A new gallery can be initialised by creating a directory containing a gallery configuration file named __gallery.yaml__.
22 32
23## Step 2: initialising the gallery 33```
34./monument-gallery-source
35└── gallery.yaml ----------- gallery settings file
36```
24 37
25A minimal gallery can be initialised by creating a directory containing a gallery configuration file named "gallery.yaml" with the following content: 38__gallery.yaml__ holds the settings of the gallery.
39Its content can be as follows:
26 40
27```yaml 41```yaml
28# gallery.yaml: ldgallery example gallery configuration file. 42# gallery.yaml: ldgallery example gallery configuration file.
@@ -34,11 +48,20 @@ tagCategories:
34 - city 48 - city
35``` 49```
36 50
37## Step 3: adding items 51## Step 2: adding items
38 52
39A new item, say a picture file named "DSC0001.jpg", can now be added to the directory created at the previous step. 53A new item, say a picture file named "DSC0001.jpg", can now be added to the directory created at the previous step.
40 54
41Optionally, some metadata such as a title and some tags can be associated by creating a file named "DSC0001.jpg.yaml" at the same location, with the following content: 55Optionally, some metadata such as a title and some tags can be associated by creating a file named "DSC0001.jpg.yaml" at the same location.
56
57```
58./monument-gallery-source
59├── gallery.yaml ----------- gallery settings file
60├── DSC0001.jpg ------------ a picture
61└── DSC0001.jpg.yaml ------- its associated optional sidecar metadata file
62```
63
64The sidecar metadata file "DSC0001.jpg.yaml" can have the following content:
42 65
43```yaml 66```yaml
44# DSC0001.jpg.yaml: ldgallery metadata sidecar file for DSC0001.jpg. 67# DSC0001.jpg.yaml: ldgallery metadata sidecar file for DSC0001.jpg.
@@ -51,29 +74,29 @@ tags:
51 - tower 74 - tower
52``` 75```
53 76
54## Step 4: compiling the gallery 77## Step 3: compiling the gallery
55 78
56The gallery can now be compiled by running the following command in a terminal with the right path to the gallery directory created during the previous steps: 79The gallery can now be compiled by running the following command in a terminal with the right path to the gallery directory created during the previous steps:
57 80
58```sh 81```sh
59ldgallery --with-viewer --input-dir <source gallery path> 82ldgallery \
83 --with-viewer \
84 --input-dir ./monument-gallery-source \
85 --output-dir ./monument-gallery-output
60``` 86```
61 87
62If the compiler was installed manually through the extraction of a pre-built archive, it might be necessary to specify the full path of the installation: 88If the compiler was installed manually through the extraction of a pre-built archive,
89it might be necessary to specify the full path of the installation:
63 90
64```sh 91```sh
65<installation path>/ldgallery --with-viewer=<installation path>/viewer --input-dir <source gallery path> 92<installation path>/ldgallery \
93 --with-viewer=<installation path>/viewer \
94 --input-dir ./monument-gallery-source \
95 --output-dir ./monument-gallery-output
66``` 96```
67 97
68Running the command above produces a directory named "out" within the input gallery directory, which contains the compiled gallery and a web viewer, ready to be deployed on some web server. 98Running the command above produces a directory named "monument-gallery-output" in the current directory,
69 99which contains the compiled gallery and a web viewer ready to be copied to some web server.
70## Step 5: deploying the gallery
71
72The content of the "out" directory generated at the previous step can now simply be uploaded to some web host, for example with an FTP client like FileZilla or through rsync/SSH with the following command:
73
74```sh
75rsync -Prz <source gallery path>/out/* user@webhost:publication_path/
76```
77 100
78The target web host doesn't need to run any additional software besides a web server correctly configured to serve flat static files. 101The target web host doesn't need to run any additional software besides a web server correctly configured to serve flat static files.
79 102
@@ -82,18 +105,20 @@ The target web host doesn't need to run any additional software besides a web se
82 105
83## Version control 106## Version control
84 107
85Some standard version-control software such as Git or Mercurial can easily be used to keep track of the evolutions of the gallery directory, thanks to the text-based format used for the sidecar metadata files. 108Some standard version-control software such as Git or Mercurial can easily be used to keep track of the evolutions of the gallery directory,
109thanks to the text-based format used for the sidecar metadata files.
86 110
87## Automated compilation and deployment 111## Automated compilation and deployment
88 112
89The compilation and upload commands can be combined in a Makefile or made part of a script for faster and more convenient deployments. 113The gallery can quickly be deployed by using a command such as `rsync`.
90 114
115The compilation and upload commands can be combined in a Makefile or made part of a script for faster and more convenient deployments.
91Such scripted procedure can then further be automated through Continuous Integration hooks. 116Such scripted procedure can then further be automated through Continuous Integration hooks.
92 117
93 118
94# SEE ALSO 119# SEE ALSO
95 120
96Related manual pages: __ldgallery__(1), __ldgallery-viewer__(7) 121Related manual pages: __ldgallery__(1), __ldgallery-viewer__(7).
97 122
98The ldgallery source code is available on <https://ldgallery.pacien.org>. 123The ldgallery source code is available on <https://ldgallery.pacien.org>.
99 124
diff --git a/readme.md b/readme.md
index 2b648ae..6a438ca 100644
--- a/readme.md
+++ b/readme.md
@@ -52,11 +52,13 @@ Builds of this software embed and make use of the following libraries:
52* Viewer (npm packages) 52* Viewer (npm packages)
53 * fortawesome/fontawesome-svg-core, licensed under the MIT License 53 * fortawesome/fontawesome-svg-core, licensed under the MIT License
54 * fortawesome/free-solid-svg-icons, licensed under the CC-BY-4.0 and MIT Licenses 54 * fortawesome/free-solid-svg-icons, licensed under the CC-BY-4.0 and MIT Licenses
55 * fortawesome/free-regular-svg-icons, licensed under the CC-BY-4.0 and MIT Licenses
55 * fortawesome/vue-fontawesome, licensed under the MIT License 56 * fortawesome/vue-fontawesome, licensed under the MIT License
56 * buefy, licensed under the MIT License 57 * buefy, licensed under the MIT License
57 * core-js, licensed under the MIT License 58 * core-js, licensed under the MIT License
58 * resize-observer-polyfill, licensed under the MIT License
59 * hammerjs, licensed under the MIT License 59 * hammerjs, licensed under the MIT License
60 * marked, licensed under the MIT License
61 * resize-observer-polyfill, licensed under the MIT License
60 * v-lazy-image, licensed under the MIT License 62 * v-lazy-image, licensed under the MIT License
61 * vue, licensed under the MIT License 63 * vue, licensed under the MIT License
62 * vue-class-component, licensed under the MIT License 64 * vue-class-component, licensed under the MIT License
diff --git a/viewer/.eslintrc.js b/viewer/.eslintrc.js
index a67de5e..9d3fbbc 100644
--- a/viewer/.eslintrc.js
+++ b/viewer/.eslintrc.js
@@ -5,14 +5,14 @@ module.exports = {
5 node: true, 5 node: true,
6 }, 6 },
7 7
8 extends: [ 8 plugins: ["prettier"],
9 "plugin:vue/essential", 9
10 "@vue/typescript" 10 extends: ["plugin:vue/essential", "plugin:prettier/recommended", "@vue/typescript"],
11 ],
12 11
13 rules: { 12 rules: {
14 "no-console": "off", 13 "no-console": "off",
15 "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", 14 "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
15 "prettier/prettier": "warn",
16 "eol-last": ["warn", "always"], 16 "eol-last": ["warn", "always"],
17 "object-curly-spacing": ["warn", "always"], 17 "object-curly-spacing": ["warn", "always"],
18 "quote-props": ["warn", "as-needed"], 18 "quote-props": ["warn", "as-needed"],
@@ -36,5 +36,4 @@ module.exports = {
36 sourceType: "module", 36 sourceType: "module",
37 parser: "@typescript-eslint/parser", 37 parser: "@typescript-eslint/parser",
38 }, 38 },
39
40}; 39};
diff --git a/viewer/.vscode/tasks.json b/viewer/.vscode/tasks.json
index 102002d..cb1cdb2 100644
--- a/viewer/.vscode/tasks.json
+++ b/viewer/.vscode/tasks.json
@@ -1,39 +1,49 @@
1{ 1{
2 // See https://go.microsoft.com/fwlink/?LinkId=733558 2 // See https://go.microsoft.com/fwlink/?LinkId=733558
3 // for the documentation about the tasks.json format 3 // for the documentation about the tasks.json format
4 "version": "2.0.0", 4 "version": "2.0.0",
5 "tasks": [ 5 "tasks": [
6 { 6 {
7 "type": "npm", 7 "type": "npm",
8 "script": "build", 8 "script": "build",
9 "group": { 9 "group": {
10 "kind": "build", 10 "kind": "build",
11 "isDefault": true 11 "isDefault": true
12 }, 12 },
13 "problemMatcher": [ 13 "problemMatcher": [
14 "$tsc" 14 "$tsc"
15 ] 15 ]
16 }, 16 },
17 { 17 {
18 "type": "npm", 18 "type": "npm",
19 "script": "serve", 19 "script": "serve",
20 "problemMatcher": [ 20 "problemMatcher": [
21 "$tsc" 21 "$tsc"
22 ] 22 ]
23 }, 23 },
24 { 24 {
25 "type": "npm", 25 "type": "npm",
26 "script": "lint-autoformat", 26 "script": "lint-autoformat",
27 "problemMatcher": [ 27 "problemMatcher": [
28 "$tsc" 28 "$tsc"
29 ] 29 ]
30 }, 30 },
31 { 31 {
32 "type": "npm", 32 "type": "npm",
33 "script": "lint", 33 "script": "lint",
34 "problemMatcher": [ 34 "problemMatcher": [
35 "$tsc" 35 "$tsc"
36 ] 36 ]
37 } 37 },
38 ] 38 {
39} \ No newline at end of file 39 "type": "npm",
40 "script": "build:report",
41 "problemMatcher": [
42 "$tsc"
43 ],
44 "group": "build",
45 "label": "npm: build:report",
46 "detail": "vue-cli-service build --report",
47 }
48 ]
49}
diff --git a/viewer/babel.config.js b/viewer/babel.config.js
index 1378522..ca2a3c1 100644
--- a/viewer/babel.config.js
+++ b/viewer/babel.config.js
@@ -1,5 +1,4 @@
1module.exports = { 1module.exports = {
2 presets: ["@vue/cli-plugin-babel/preset"], 2 presets: ["@vue/cli-plugin-babel/preset"],
3 plugins: [ 3 plugins: [],
4 ],
5}; 4};
diff --git a/viewer/ldgallery-viewer.7.md b/viewer/ldgallery-viewer.7.md
index 41f5003..96070dc 100644
--- a/viewer/ldgallery-viewer.7.md
+++ b/viewer/ldgallery-viewer.7.md
@@ -2,7 +2,7 @@
2pagetitle: Viewer user manual - ldgallery 2pagetitle: Viewer user manual - ldgallery
3title: LDGALLERY-VIEWER(7) ldgallery 3title: LDGALLERY-VIEWER(7) ldgallery
4author: Pacien TRAN-GIRARD, Guillaume FOUET 4author: Pacien TRAN-GIRARD, Guillaume FOUET
5date: 2020-04-30 (v1.0) 5date: 2020-09-24 (v2.0)
6--- 6---
7 7
8 8
@@ -24,12 +24,23 @@ Its responsiveness allows it to be used from either a desktop browser or some mo
24The viewer's user interface is split into a main item view and a side search panel, which can be opened by using the appropriate button in the toolbar at the top-left corner. 24The viewer's user interface is split into a main item view and a side search panel, which can be opened by using the appropriate button in the toolbar at the top-left corner.
25 25
26The main view displays the gallery's directories and items as a thumbnail grid. 26The main view displays the gallery's directories and items as a thumbnail grid.
27The order in which items are displayed can be chosen from the sort menu at the top-left corner.
27 28
28The side panel allows the user to interactively enter filtering queries to search through the gallery's content. 29The side panel allows the user to interactively enter filtering queries to search through the gallery's content.
29This panel features a list of relevant tags, grouped by categories, that can be used to build the search query. 30This panel features a list of relevant tags, grouped by categories, that can be used to build the search query.
30 31
31Picture items can be opened and visualised within the application. 32The information panel at the bottom of the sidebar displays various metadata about the currently viewed item.
32Other types of elements are either downloaded or displayed in the same window depending on the user's web browser supported media types. 33Those include the title, date and description of the file or directory.
34
35Items of the following formats can be opened and visualised within the web application:
36
37* Pictures (Bitmap, JPEG, PNG, TIFF, HDR, GIF)
38* Videos (OGV, WebM, Matroska, MPEG-4)
39* Audio files (WAV, Opus, FLAC, MP3, MPEG-4)
40* Plain text files (`.txt`)
41* PDFs
42
43Formats which are not listed above or which are not supported by the user's web browser are offered for download instead of being directly displayed in the same window.
33 44
34 45
35# SEARCH QUERIES 46# SEARCH QUERIES
@@ -46,17 +57,45 @@ The following modifiers can be used in queries as prefixes of tags:
46`-` 57`-`
47: Exclude all items having the associated tag, independently of simple tag restrictions and inclusions. 58: Exclude all items having the associated tag, independently of simple tag restrictions and inclusions.
48 59
49Autocompletion suggestions are shown as filters are being typed in the query field. 60Auto-completion suggestions are shown as filters are being typed in the query field.
50In the case of disambiguated tags, both the category and the tag components are allowed to be partially entered, allowing "loc:fra" to expand into "location:france" for example. 61In the case of disambiguated tags, both the category and the tag components are allowed to be partially entered, allowing "loc:fra" to expand into "location:france" for example.
51 62
52 63
53# VIEWER CONFIGURATION 64# VIEWER CONFIGURATION
54 65
55The viewer itself can be configured through a JSON file named "config.json" and placed in the web viewer's directory. 66The viewer itself can be configured through a JSON file named __config.json__ and placed in the web viewer's directory.
67
68Viewer configuration options are:
56 69
57galleryRoot 70galleryRoot
58: Absolute or relative path to the root of the gallery to display. 71: Absolute or relative path to the root of the gallery to display.
59 72
73galleryIndex
74: Optional index file to use under the value specified for "galleryRoot".
75 Defaults to "index.json".
76
77initialItemSort
78: Order in which gallery items are originally to be displayed.
79 Possible values are "title_asc", "date_asc", "date_desc".
80 Defaults to "date_asc".
81 Titles are sorted using a human-friendly _natural sort order_ which treats multi-digit numbers atomically.
82 The item path is used as a tie-breaker for all the defined orders.
83
84<!-- https://github.com/pacien/ldgallery/issues/27
85initialSearchQuery
86: Optional initial search query to set when opening the gallery.
87-->
88
89initialTagDisplayLimit
90: Limit on the number of tags to suggest in each tag category.
91 Causes only the specified amount of most used tags to be displayed until the user expands the list.
92 Set to -1 to disable the limit on suggestions.
93 Defaults to 10.
94
95An alternative viewer configuration file located in the viewer's directory can be loaded by specifying its name,
96without the ".json" extension, as a query parameter given before the page anchor;
97for example, some alternative configuration named "config_2.json" can be loaded with "http://gallery/?config_2#".
98
60 99
61# PROGRESSIVE WEB APPLICATION 100# PROGRESSIVE WEB APPLICATION
62 101
@@ -68,7 +107,7 @@ An example of such manifest and an associated icon are available in the example
68 107
69# SEE ALSO 108# SEE ALSO
70 109
71Related manual pages: __ldgallery__(1), __ldgallery-quickstart__(7) 110Related manual pages: __ldgallery__(1), __ldgallery-quickstart__(7).
72 111
73The ldgallery source code is available on <https://ldgallery.pacien.org>. 112The ldgallery source code is available on <https://ldgallery.pacien.org>.
74 113
diff --git a/viewer/package-lock.json b/viewer/package-lock.json
index d4a5fb0..4785b3e 100644
--- a/viewer/package-lock.json
+++ b/viewer/package-lock.json
@@ -1,6 +1,6 @@
1{ 1{
2 "name": "ldgallery-viewer", 2 "name": "ldgallery-viewer",
3 "version": "0.1.0", 3 "version": "2.0.0",
4 "lockfileVersion": 1, 4 "lockfileVersion": 1,
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
@@ -14,30 +14,62 @@
14 } 14 }
15 }, 15 },
16 "@babel/compat-data": { 16 "@babel/compat-data": {
17 "version": "7.9.0", 17 "version": "7.10.3",
18 "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.9.0.tgz", 18 "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.10.3.tgz",
19 "integrity": "sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g==", 19 "integrity": "sha512-BDIfJ9uNZuI0LajPfoYV28lX8kyCPMHY6uY4WH1lJdcicmAfxCK5ASzaeV0D/wsUaRH/cLk+amuxtC37sZ8TUg==",
20 "dev": true, 20 "dev": true,
21 "requires": { 21 "requires": {
22 "browserslist": "^4.9.1", 22 "browserslist": "^4.12.0",
23 "invariant": "^2.2.4", 23 "invariant": "^2.2.4",
24 "semver": "^5.5.0" 24 "semver": "^5.5.0"
25 },
26 "dependencies": {
27 "browserslist": {
28 "version": "4.12.2",
29 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.2.tgz",
30 "integrity": "sha512-MfZaeYqR8StRZdstAK9hCKDd2StvePCYp5rHzQCPicUjfFliDgmuaBNPHYUTpAywBN8+Wc/d7NYVFkO0aqaBUw==",
31 "dev": true,
32 "requires": {
33 "caniuse-lite": "^1.0.30001088",
34 "electron-to-chromium": "^1.3.483",
35 "escalade": "^3.0.1",
36 "node-releases": "^1.1.58"
37 }
38 },
39 "caniuse-lite": {
40 "version": "1.0.30001090",
41 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001090.tgz",
42 "integrity": "sha512-QzPRKDCyp7RhjczTPZaqK3CjPA5Ht2UnXhZhCI4f7QiB5JK6KEuZBxIzyWnB3wO4hgAj4GMRxAhuiacfw0Psjg==",
43 "dev": true
44 },
45 "electron-to-chromium": {
46 "version": "1.3.483",
47 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz",
48 "integrity": "sha512-+05RF8S9rk8S0G8eBCqBRBaRq7+UN3lDs2DAvnG8SBSgQO3hjy0+qt4CmRk5eiuGbTcaicgXfPmBi31a+BD3lg==",
49 "dev": true
50 },
51 "node-releases": {
52 "version": "1.1.58",
53 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.58.tgz",
54 "integrity": "sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==",
55 "dev": true
56 }
25 } 57 }
26 }, 58 },
27 "@babel/core": { 59 "@babel/core": {
28 "version": "7.9.0", 60 "version": "7.10.3",
29 "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz", 61 "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.10.3.tgz",
30 "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==", 62 "integrity": "sha512-5YqWxYE3pyhIi84L84YcwjeEgS+fa7ZjK6IBVGTjDVfm64njkR2lfDhVR5OudLk8x2GK59YoSyVv+L/03k1q9w==",
31 "dev": true, 63 "dev": true,
32 "requires": { 64 "requires": {
33 "@babel/code-frame": "^7.8.3", 65 "@babel/code-frame": "^7.10.3",
34 "@babel/generator": "^7.9.0", 66 "@babel/generator": "^7.10.3",
35 "@babel/helper-module-transforms": "^7.9.0", 67 "@babel/helper-module-transforms": "^7.10.1",
36 "@babel/helpers": "^7.9.0", 68 "@babel/helpers": "^7.10.1",
37 "@babel/parser": "^7.9.0", 69 "@babel/parser": "^7.10.3",
38 "@babel/template": "^7.8.6", 70 "@babel/template": "^7.10.3",
39 "@babel/traverse": "^7.9.0", 71 "@babel/traverse": "^7.10.3",
40 "@babel/types": "^7.9.0", 72 "@babel/types": "^7.10.3",
41 "convert-source-map": "^1.7.0", 73 "convert-source-map": "^1.7.0",
42 "debug": "^4.1.0", 74 "debug": "^4.1.0",
43 "gensync": "^1.0.0-beta.1", 75 "gensync": "^1.0.0-beta.1",
@@ -49,21 +81,21 @@
49 }, 81 },
50 "dependencies": { 82 "dependencies": {
51 "@babel/code-frame": { 83 "@babel/code-frame": {
52 "version": "7.8.3", 84 "version": "7.10.3",
53 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", 85 "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.3.tgz",
54 "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", 86 "integrity": "sha512-fDx9eNW0qz0WkUeqL6tXEXzVlPh6Y5aCDEZesl0xBGA8ndRukX91Uk44ZqnkECp01NAZUdCAl+aiQNGi0k88Eg==",
55 "dev": true, 87 "dev": true,
56 "requires": { 88 "requires": {
57 "@babel/highlight": "^7.8.3" 89 "@babel/highlight": "^7.10.3"
58 } 90 }
59 }, 91 },
60 "@babel/highlight": { 92 "@babel/highlight": {
61 "version": "7.9.0", 93 "version": "7.10.3",
62 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", 94 "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.3.tgz",
63 "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", 95 "integrity": "sha512-Ih9B/u7AtgEnySE2L2F0Xm0GaM729XqqLfHkalTsbjXGyqmf/6M0Cu0WpvqueUlW+xk88BHw9Nkpj49naU+vWw==",
64 "dev": true, 96 "dev": true,
65 "requires": { 97 "requires": {
66 "@babel/helper-validator-identifier": "^7.9.0", 98 "@babel/helper-validator-identifier": "^7.10.3",
67 "chalk": "^2.0.0", 99 "chalk": "^2.0.0",
68 "js-tokens": "^4.0.0" 100 "js-tokens": "^4.0.0"
69 } 101 }
@@ -77,12 +109,12 @@
77 } 109 }
78 }, 110 },
79 "@babel/generator": { 111 "@babel/generator": {
80 "version": "7.9.4", 112 "version": "7.10.3",
81 "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.4.tgz", 113 "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.10.3.tgz",
82 "integrity": "sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==", 114 "integrity": "sha512-drt8MUHbEqRzNR0xnF8nMehbY11b1SDkRw03PSNH/3Rb2Z35oxkddVSi3rcaak0YJQ86PCuE7Qx1jSFhbLNBMA==",
83 "dev": true, 115 "dev": true,
84 "requires": { 116 "requires": {
85 "@babel/types": "^7.9.0", 117 "@babel/types": "^7.10.3",
86 "jsesc": "^2.5.1", 118 "jsesc": "^2.5.1",
87 "lodash": "^4.17.13", 119 "lodash": "^4.17.13",
88 "source-map": "^0.5.0" 120 "source-map": "^0.5.0"
@@ -97,240 +129,272 @@
97 } 129 }
98 }, 130 },
99 "@babel/helper-annotate-as-pure": { 131 "@babel/helper-annotate-as-pure": {
100 "version": "7.8.3", 132 "version": "7.10.1",
101 "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz", 133 "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.1.tgz",
102 "integrity": "sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw==", 134 "integrity": "sha512-ewp3rvJEwLaHgyWGe4wQssC2vjks3E80WiUe2BpMb0KhreTjMROCbxXcEovTrbeGVdQct5VjQfrv9EgC+xMzCw==",
103 "dev": true, 135 "dev": true,
104 "requires": { 136 "requires": {
105 "@babel/types": "^7.8.3" 137 "@babel/types": "^7.10.1"
106 } 138 }
107 }, 139 },
108 "@babel/helper-builder-binary-assignment-operator-visitor": { 140 "@babel/helper-builder-binary-assignment-operator-visitor": {
109 "version": "7.8.3", 141 "version": "7.10.3",
110 "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz", 142 "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.3.tgz",
111 "integrity": "sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw==", 143 "integrity": "sha512-lo4XXRnBlU6eRM92FkiZxpo1xFLmv3VsPFk61zJKMm7XYJfwqXHsYJTY6agoc4a3L8QPw1HqWehO18coZgbT6A==",
112 "dev": true, 144 "dev": true,
113 "requires": { 145 "requires": {
114 "@babel/helper-explode-assignable-expression": "^7.8.3", 146 "@babel/helper-explode-assignable-expression": "^7.10.3",
115 "@babel/types": "^7.8.3" 147 "@babel/types": "^7.10.3"
116 } 148 }
117 }, 149 },
118 "@babel/helper-compilation-targets": { 150 "@babel/helper-compilation-targets": {
119 "version": "7.8.7", 151 "version": "7.10.2",
120 "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz", 152 "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.2.tgz",
121 "integrity": "sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw==", 153 "integrity": "sha512-hYgOhF4To2UTB4LTaZepN/4Pl9LD4gfbJx8A34mqoluT8TLbof1mhUlYuNWTEebONa8+UlCC4X0TEXu7AOUyGA==",
122 "dev": true, 154 "dev": true,
123 "requires": { 155 "requires": {
124 "@babel/compat-data": "^7.8.6", 156 "@babel/compat-data": "^7.10.1",
125 "browserslist": "^4.9.1", 157 "browserslist": "^4.12.0",
126 "invariant": "^2.2.4", 158 "invariant": "^2.2.4",
127 "levenary": "^1.1.1", 159 "levenary": "^1.1.1",
128 "semver": "^5.5.0" 160 "semver": "^5.5.0"
161 },
162 "dependencies": {
163 "browserslist": {
164 "version": "4.12.2",
165 "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.2.tgz",
166 "integrity": "sha512-MfZaeYqR8StRZdstAK9hCKDd2StvePCYp5rHzQCPicUjfFliDgmuaBNPHYUTpAywBN8+Wc/d7NYVFkO0aqaBUw==",
167 "dev": true,
168 "requires": {
169 "caniuse-lite": "^1.0.30001088",
170 "electron-to-chromium": "^1.3.483",
171 "escalade": "^3.0.1",
172 "node-releases": "^1.1.58"
173 }
174 },
175 "caniuse-lite": {
176 "version": "1.0.30001090",
177 "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001090.tgz",
178 "integrity": "sha512-QzPRKDCyp7RhjczTPZaqK3CjPA5Ht2UnXhZhCI4f7QiB5JK6KEuZBxIzyWnB3wO4hgAj4GMRxAhuiacfw0Psjg==",
179 "dev": true
180 },
181 "electron-to-chromium": {
182 "version": "1.3.483",
183 "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.483.tgz",
184 "integrity": "sha512-+05RF8S9rk8S0G8eBCqBRBaRq7+UN3lDs2DAvnG8SBSgQO3hjy0+qt4CmRk5eiuGbTcaicgXfPmBi31a+BD3lg==",
185 "dev": true
186 },
187 "node-releases": {
188 "version": "1.1.58",
189 "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.58.tgz",
190 "integrity": "sha512-NxBudgVKiRh/2aPWMgPR7bPTX0VPmGx5QBwCtdHitnqFE5/O8DeBXuIMH1nwNnw/aMo6AjOrpsHzfY3UbUJ7yg==",
191 "dev": true
192 }
129 } 193 }
130 }, 194 },
131 "@babel/helper-create-class-features-plugin": { 195 "@babel/helper-create-class-features-plugin": {
132 "version": "7.8.6", 196 "version": "7.10.3",
133 "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.6.tgz", 197 "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.3.tgz",
134 "integrity": "sha512-klTBDdsr+VFFqaDHm5rR69OpEQtO2Qv8ECxHS1mNhJJvaHArR6a1xTf5K/eZW7eZpJbhCx3NW1Yt/sKsLXLblg==", 198 "integrity": "sha512-iRT9VwqtdFmv7UheJWthGc/h2s7MqoweBF9RUj77NFZsg9VfISvBTum3k6coAhJ8RWv2tj3yUjA03HxPd0vfpQ==",
135 "dev": true, 199 "dev": true,
136 "requires": { 200 "requires": {
137 "@babel/helper-function-name": "^7.8.3", 201 "@babel/helper-function-name": "^7.10.3",
138 "@babel/helper-member-expression-to-functions": "^7.8.3", 202 "@babel/helper-member-expression-to-functions": "^7.10.3",
139 "@babel/helper-optimise-call-expression": "^7.8.3", 203 "@babel/helper-optimise-call-expression": "^7.10.3",
140 "@babel/helper-plugin-utils": "^7.8.3", 204 "@babel/helper-plugin-utils": "^7.10.3",
141 "@babel/helper-replace-supers": "^7.8.6", 205 "@babel/helper-replace-supers": "^7.10.1",
142 "@babel/helper-split-export-declaration": "^7.8.3" 206 "@babel/helper-split-export-declaration": "^7.10.1"
143 } 207 }
144 }, 208 },
145 "@babel/helper-create-regexp-features-plugin": { 209 "@babel/helper-create-regexp-features-plugin": {
146 "version": "7.8.8", 210 "version": "7.10.1",
147 "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz", 211 "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.1.tgz",
148 "integrity": "sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg==", 212 "integrity": "sha512-Rx4rHS0pVuJn5pJOqaqcZR4XSgeF9G/pO/79t+4r7380tXFJdzImFnxMU19f83wjSrmKHq6myrM10pFHTGzkUA==",
149 "dev": true, 213 "dev": true,
150 "requires": { 214 "requires": {
151 "@babel/helper-annotate-as-pure": "^7.8.3", 215 "@babel/helper-annotate-as-pure": "^7.10.1",
152 "@babel/helper-regex": "^7.8.3", 216 "@babel/helper-regex": "^7.10.1",
153 "regexpu-core": "^4.7.0" 217 "regexpu-core": "^4.7.0"
154 } 218 }
155 }, 219 },
156 "@babel/helper-define-map": { 220 "@babel/helper-define-map": {
157 "version": "7.8.3", 221 "version": "7.10.3",
158 "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz", 222 "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.3.tgz",
159 "integrity": "sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g==", 223 "integrity": "sha512-bxRzDi4Sin/k0drWCczppOhov1sBSdBvXJObM1NLHQzjhXhwRtn7aRWGvLJWCYbuu2qUk3EKs6Ci9C9ps8XokQ==",
160 "dev": true, 224 "dev": true,
161 "requires": { 225 "requires": {
162 "@babel/helper-function-name": "^7.8.3", 226 "@babel/helper-function-name": "^7.10.3",
163 "@babel/types": "^7.8.3", 227 "@babel/types": "^7.10.3",
164 "lodash": "^4.17.13" 228 "lodash": "^4.17.13"
165 } 229 }
166 }, 230 },
167 "@babel/helper-explode-assignable-expression": { 231 "@babel/helper-explode-assignable-expression": {
168 "version": "7.8.3", 232 "version": "7.10.3",
169 "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz", 233 "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.10.3.tgz",
170 "integrity": "sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw==", 234 "integrity": "sha512-0nKcR64XrOC3lsl+uhD15cwxPvaB6QKUDlD84OT9C3myRbhJqTMYir69/RWItUvHpharv0eJ/wk7fl34ONSwZw==",
171 "dev": true, 235 "dev": true,
172 "requires": { 236 "requires": {
173 "@babel/traverse": "^7.8.3", 237 "@babel/traverse": "^7.10.3",
174 "@babel/types": "^7.8.3" 238 "@babel/types": "^7.10.3"
175 } 239 }
176 }, 240 },
177 "@babel/helper-function-name": { 241 "@babel/helper-function-name": {
178 "version": "7.8.3", 242 "version": "7.10.3",
179 "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz", 243 "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz",
180 "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==", 244 "integrity": "sha512-FvSj2aiOd8zbeqijjgqdMDSyxsGHaMt5Tr0XjQsGKHD3/1FP3wksjnLAWzxw7lvXiej8W1Jt47SKTZ6upQNiRw==",
181 "dev": true, 245 "dev": true,
182 "requires": { 246 "requires": {
183 "@babel/helper-get-function-arity": "^7.8.3", 247 "@babel/helper-get-function-arity": "^7.10.3",
184 "@babel/template": "^7.8.3", 248 "@babel/template": "^7.10.3",
185 "@babel/types": "^7.8.3" 249 "@babel/types": "^7.10.3"
186 } 250 }
187 }, 251 },
188 "@babel/helper-get-function-arity": { 252 "@babel/helper-get-function-arity": {
189 "version": "7.8.3", 253 "version": "7.10.3",
190 "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz", 254 "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz",
191 "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==", 255 "integrity": "sha512-iUD/gFsR+M6uiy69JA6fzM5seno8oE85IYZdbVVEuQaZlEzMO2MXblh+KSPJgsZAUx0EEbWXU0yJaW7C9CdAVg==",
192 "dev": true, 256 "dev": true,
193 "requires": { 257 "requires": {
194 "@babel/types": "^7.8.3" 258 "@babel/types": "^7.10.3"
195 } 259 }
196 }, 260 },
197 "@babel/helper-hoist-variables": { 261 "@babel/helper-hoist-variables": {
198 "version": "7.8.3", 262 "version": "7.10.3",
199 "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz", 263 "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.3.tgz",
200 "integrity": "sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg==", 264 "integrity": "sha512-9JyafKoBt5h20Yv1+BXQMdcXXavozI1vt401KBiRc2qzUepbVnd7ogVNymY1xkQN9fekGwfxtotH2Yf5xsGzgg==",
201 "dev": true, 265 "dev": true,
202 "requires": { 266 "requires": {
203 "@babel/types": "^7.8.3" 267 "@babel/types": "^7.10.3"
204 } 268 }
205 }, 269 },
206 "@babel/helper-member-expression-to-functions": { 270 "@babel/helper-member-expression-to-functions": {
207 "version": "7.8.3", 271 "version": "7.10.3",
208 "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz", 272 "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz",
209 "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==", 273 "integrity": "sha512-q7+37c4EPLSjNb2NmWOjNwj0+BOyYlssuQ58kHEWk1Z78K5i8vTUsteq78HMieRPQSl/NtpQyJfdjt3qZ5V2vw==",
210 "dev": true, 274 "dev": true,
211 "requires": { 275 "requires": {
212 "@babel/types": "^7.8.3" 276 "@babel/types": "^7.10.3"
213 } 277 }
214 }, 278 },
215 "@babel/helper-module-imports": { 279 "@babel/helper-module-imports": {
216 "version": "7.8.3", 280 "version": "7.10.3",
217 "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz", 281 "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz",
218 "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==", 282 "integrity": "sha512-Jtqw5M9pahLSUWA+76nhK9OG8nwYXzhQzVIGFoNaHnXF/r4l7kz4Fl0UAW7B6mqC5myoJiBP5/YQlXQTMfHI9w==",
219 "dev": true, 283 "dev": true,
220 "requires": { 284 "requires": {
221 "@babel/types": "^7.8.3" 285 "@babel/types": "^7.10.3"
222 } 286 }
223 }, 287 },
224 "@babel/helper-module-transforms": { 288 "@babel/helper-module-transforms": {
225 "version": "7.9.0", 289 "version": "7.10.1",
226 "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz", 290 "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz",
227 "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==", 291 "integrity": "sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg==",
228 "dev": true, 292 "dev": true,
229 "requires": { 293 "requires": {
230 "@babel/helper-module-imports": "^7.8.3", 294 "@babel/helper-module-imports": "^7.10.1",
231 "@babel/helper-replace-supers": "^7.8.6", 295 "@babel/helper-replace-supers": "^7.10.1",
232 "@babel/helper-simple-access": "^7.8.3", 296 "@babel/helper-simple-access": "^7.10.1",
233 "@babel/helper-split-export-declaration": "^7.8.3", 297 "@babel/helper-split-export-declaration": "^7.10.1",
234 "@babel/template": "^7.8.6", 298 "@babel/template": "^7.10.1",
235 "@babel/types": "^7.9.0", 299 "@babel/types": "^7.10.1",
236 "lodash": "^4.17.13" 300 "lodash": "^4.17.13"
237 } 301 }
238 }, 302 },
239 "@babel/helper-optimise-call-expression": { 303 "@babel/helper-optimise-call-expression": {
240 "version": "7.8.3", 304 "version": "7.10.3",
241 "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz", 305 "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz",
242 "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==", 306 "integrity": "sha512-kT2R3VBH/cnSz+yChKpaKRJQJWxdGoc6SjioRId2wkeV3bK0wLLioFpJROrX0U4xr/NmxSSAWT/9Ih5snwIIzg==",
243 "dev": true, 307 "dev": true,
244 "requires": { 308 "requires": {
245 "@babel/types": "^7.8.3" 309 "@babel/types": "^7.10.3"
246 } 310 }
247 }, 311 },
248 "@babel/helper-plugin-utils": { 312 "@babel/helper-plugin-utils": {
249 "version": "7.8.3", 313 "version": "7.10.3",
250 "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz", 314 "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz",
251 "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==", 315 "integrity": "sha512-j/+j8NAWUTxOtx4LKHybpSClxHoq6I91DQ/mKgAXn5oNUPIUiGppjPIX3TDtJWPrdfP9Kfl7e4fgVMiQR9VE/g==",
252 "dev": true 316 "dev": true
253 }, 317 },
254 "@babel/helper-regex": { 318 "@babel/helper-regex": {
255 "version": "7.8.3", 319 "version": "7.10.1",
256 "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.8.3.tgz", 320 "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.1.tgz",
257 "integrity": "sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ==", 321 "integrity": "sha512-7isHr19RsIJWWLLFn21ubFt223PjQyg1HY7CZEMRr820HttHPpVvrsIN3bUOo44DEfFV4kBXO7Abbn9KTUZV7g==",
258 "dev": true, 322 "dev": true,
259 "requires": { 323 "requires": {
260 "lodash": "^4.17.13" 324 "lodash": "^4.17.13"
261 } 325 }
262 }, 326 },
263 "@babel/helper-remap-async-to-generator": { 327 "@babel/helper-remap-async-to-generator": {
264 "version": "7.8.3", 328 "version": "7.10.3",
265 "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz", 329 "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.10.3.tgz",
266 "integrity": "sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA==", 330 "integrity": "sha512-sLB7666ARbJUGDO60ZormmhQOyqMX/shKBXZ7fy937s+3ID8gSrneMvKSSb+8xIM5V7Vn6uNVtOY1vIm26XLtA==",
267 "dev": true, 331 "dev": true,
268 "requires": { 332 "requires": {
269 "@babel/helper-annotate-as-pure": "^7.8.3", 333 "@babel/helper-annotate-as-pure": "^7.10.1",
270 "@babel/helper-wrap-function": "^7.8.3", 334 "@babel/helper-wrap-function": "^7.10.1",
271 "@babel/template": "^7.8.3", 335 "@babel/template": "^7.10.3",
272 "@babel/traverse": "^7.8.3", 336 "@babel/traverse": "^7.10.3",
273 "@babel/types": "^7.8.3" 337 "@babel/types": "^7.10.3"
274 } 338 }
275 }, 339 },
276 "@babel/helper-replace-supers": { 340 "@babel/helper-replace-supers": {
277 "version": "7.8.6", 341 "version": "7.10.1",
278 "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz", 342 "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz",
279 "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==", 343 "integrity": "sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A==",
280 "dev": true, 344 "dev": true,
281 "requires": { 345 "requires": {
282 "@babel/helper-member-expression-to-functions": "^7.8.3", 346 "@babel/helper-member-expression-to-functions": "^7.10.1",
283 "@babel/helper-optimise-call-expression": "^7.8.3", 347 "@babel/helper-optimise-call-expression": "^7.10.1",
284 "@babel/traverse": "^7.8.6", 348 "@babel/traverse": "^7.10.1",
285 "@babel/types": "^7.8.6" 349 "@babel/types": "^7.10.1"
286 } 350 }
287 }, 351 },
288 "@babel/helper-simple-access": { 352 "@babel/helper-simple-access": {
289 "version": "7.8.3", 353 "version": "7.10.1",
290 "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz", 354 "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz",
291 "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==", 355 "integrity": "sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw==",
292 "dev": true, 356 "dev": true,
293 "requires": { 357 "requires": {
294 "@babel/template": "^7.8.3", 358 "@babel/template": "^7.10.1",
295 "@babel/types": "^7.8.3" 359 "@babel/types": "^7.10.1"
296 } 360 }
297 }, 361 },
298 "@babel/helper-split-export-declaration": { 362 "@babel/helper-split-export-declaration": {
299 "version": "7.8.3", 363 "version": "7.10.1",
300 "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz", 364 "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz",
301 "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==", 365 "integrity": "sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g==",
302 "dev": true, 366 "dev": true,
303 "requires": { 367 "requires": {
304 "@babel/types": "^7.8.3" 368 "@babel/types": "^7.10.1"
305 } 369 }
306 }, 370 },
307 "@babel/helper-validator-identifier": { 371 "@babel/helper-validator-identifier": {
308 "version": "7.9.0", 372 "version": "7.10.3",
309 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz", 373 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.3.tgz",
310 "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==", 374 "integrity": "sha512-bU8JvtlYpJSBPuj1VUmKpFGaDZuLxASky3LhaKj3bmpSTY6VWooSM8msk+Z0CZoErFye2tlABF6yDkT3FOPAXw==",
311 "dev": true 375 "dev": true
312 }, 376 },
313 "@babel/helper-wrap-function": { 377 "@babel/helper-wrap-function": {
314 "version": "7.8.3", 378 "version": "7.10.1",
315 "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz", 379 "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.1.tgz",
316 "integrity": "sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ==", 380 "integrity": "sha512-C0MzRGteVDn+H32/ZgbAv5r56f2o1fZSA/rj/TYo8JEJNHg+9BdSmKBUND0shxWRztWhjlT2cvHYuynpPsVJwQ==",
317 "dev": true, 381 "dev": true,
318 "requires": { 382 "requires": {
319 "@babel/helper-function-name": "^7.8.3", 383 "@babel/helper-function-name": "^7.10.1",
320 "@babel/template": "^7.8.3", 384 "@babel/template": "^7.10.1",
321 "@babel/traverse": "^7.8.3", 385 "@babel/traverse": "^7.10.1",
322 "@babel/types": "^7.8.3" 386 "@babel/types": "^7.10.1"
323 } 387 }
324 }, 388 },
325 "@babel/helpers": { 389 "@babel/helpers": {
326 "version": "7.9.2", 390 "version": "7.10.1",
327 "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz", 391 "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz",
328 "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==", 392 "integrity": "sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw==",
329 "dev": true, 393 "dev": true,
330 "requires": { 394 "requires": {
331 "@babel/template": "^7.8.3", 395 "@babel/template": "^7.10.1",
332 "@babel/traverse": "^7.9.0", 396 "@babel/traverse": "^7.10.1",
333 "@babel/types": "^7.9.0" 397 "@babel/types": "^7.10.1"
334 } 398 }
335 }, 399 },
336 "@babel/highlight": { 400 "@babel/highlight": {
@@ -345,121 +409,132 @@
345 } 409 }
346 }, 410 },
347 "@babel/parser": { 411 "@babel/parser": {
348 "version": "7.9.4", 412 "version": "7.10.3",
349 "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz", 413 "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.10.3.tgz",
350 "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==", 414 "integrity": "sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA==",
351 "dev": true 415 "dev": true
352 }, 416 },
353 "@babel/plugin-proposal-async-generator-functions": { 417 "@babel/plugin-proposal-async-generator-functions": {
354 "version": "7.8.3", 418 "version": "7.10.3",
355 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz", 419 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.3.tgz",
356 "integrity": "sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw==", 420 "integrity": "sha512-WUUWM7YTOudF4jZBAJIW9D7aViYC/Fn0Pln4RIHlQALyno3sXSjqmTA4Zy1TKC2D49RCR8Y/Pn4OIUtEypK3CA==",
357 "dev": true, 421 "dev": true,
358 "requires": { 422 "requires": {
359 "@babel/helper-plugin-utils": "^7.8.3", 423 "@babel/helper-plugin-utils": "^7.10.3",
360 "@babel/helper-remap-async-to-generator": "^7.8.3", 424 "@babel/helper-remap-async-to-generator": "^7.10.3",
361 "@babel/plugin-syntax-async-generators": "^7.8.0" 425 "@babel/plugin-syntax-async-generators": "^7.8.0"
362 } 426 }
363 }, 427 },
364 "@babel/plugin-proposal-class-properties": { 428 "@babel/plugin-proposal-class-properties": {
365 "version": "7.8.3", 429 "version": "7.10.1",
366 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", 430 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.1.tgz",
367 "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", 431 "integrity": "sha512-sqdGWgoXlnOdgMXU+9MbhzwFRgxVLeiGBqTrnuS7LC2IBU31wSsESbTUreT2O418obpfPdGUR2GbEufZF1bpqw==",
368 "dev": true, 432 "dev": true,
369 "requires": { 433 "requires": {
370 "@babel/helper-create-class-features-plugin": "^7.8.3", 434 "@babel/helper-create-class-features-plugin": "^7.10.1",
371 "@babel/helper-plugin-utils": "^7.8.3" 435 "@babel/helper-plugin-utils": "^7.10.1"
372 } 436 }
373 }, 437 },
374 "@babel/plugin-proposal-decorators": { 438 "@babel/plugin-proposal-decorators": {
375 "version": "7.8.3", 439 "version": "7.10.3",
376 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz", 440 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.10.3.tgz",
377 "integrity": "sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w==", 441 "integrity": "sha512-Rzwn5tcYFTdWWK3IrhMZkMDjzFQLIGYqHvv9XuzNnEB91Y6gHr/JjazYV1Yec9g0yMLhy1p/21eiW1P7f5UN4A==",
378 "dev": true, 442 "dev": true,
379 "requires": { 443 "requires": {
380 "@babel/helper-create-class-features-plugin": "^7.8.3", 444 "@babel/helper-create-class-features-plugin": "^7.10.3",
381 "@babel/helper-plugin-utils": "^7.8.3", 445 "@babel/helper-plugin-utils": "^7.10.3",
382 "@babel/plugin-syntax-decorators": "^7.8.3" 446 "@babel/plugin-syntax-decorators": "^7.10.1"
383 } 447 }
384 }, 448 },
385 "@babel/plugin-proposal-dynamic-import": { 449 "@babel/plugin-proposal-dynamic-import": {
386 "version": "7.8.3", 450 "version": "7.10.1",
387 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", 451 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.1.tgz",
388 "integrity": "sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w==", 452 "integrity": "sha512-Cpc2yUVHTEGPlmiQzXj026kqwjEQAD9I4ZC16uzdbgWgitg/UHKHLffKNCQZ5+y8jpIZPJcKcwsr2HwPh+w3XA==",
389 "dev": true, 453 "dev": true,
390 "requires": { 454 "requires": {
391 "@babel/helper-plugin-utils": "^7.8.3", 455 "@babel/helper-plugin-utils": "^7.10.1",
392 "@babel/plugin-syntax-dynamic-import": "^7.8.0" 456 "@babel/plugin-syntax-dynamic-import": "^7.8.0"
393 } 457 }
394 }, 458 },
395 "@babel/plugin-proposal-json-strings": { 459 "@babel/plugin-proposal-json-strings": {
396 "version": "7.8.3", 460 "version": "7.10.1",
397 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz", 461 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.1.tgz",
398 "integrity": "sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q==", 462 "integrity": "sha512-m8r5BmV+ZLpWPtMY2mOKN7wre6HIO4gfIiV+eOmsnZABNenrt/kzYBwrh+KOfgumSWpnlGs5F70J8afYMSJMBg==",
399 "dev": true, 463 "dev": true,
400 "requires": { 464 "requires": {
401 "@babel/helper-plugin-utils": "^7.8.3", 465 "@babel/helper-plugin-utils": "^7.10.1",
402 "@babel/plugin-syntax-json-strings": "^7.8.0" 466 "@babel/plugin-syntax-json-strings": "^7.8.0"
403 } 467 }
404 }, 468 },
405 "@babel/plugin-proposal-nullish-coalescing-operator": { 469 "@babel/plugin-proposal-nullish-coalescing-operator": {
406 "version": "7.8.3", 470 "version": "7.10.1",
407 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz", 471 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.1.tgz",
408 "integrity": "sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw==", 472 "integrity": "sha512-56cI/uHYgL2C8HVuHOuvVowihhX0sxb3nnfVRzUeVHTWmRHTZrKuAh/OBIMggGU/S1g/1D2CRCXqP+3u7vX7iA==",
409 "dev": true, 473 "dev": true,
410 "requires": { 474 "requires": {
411 "@babel/helper-plugin-utils": "^7.8.3", 475 "@babel/helper-plugin-utils": "^7.10.1",
412 "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" 476 "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
413 } 477 }
414 }, 478 },
415 "@babel/plugin-proposal-numeric-separator": { 479 "@babel/plugin-proposal-numeric-separator": {
416 "version": "7.8.3", 480 "version": "7.10.1",
417 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz", 481 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.1.tgz",
418 "integrity": "sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ==", 482 "integrity": "sha512-jjfym4N9HtCiNfyyLAVD8WqPYeHUrw4ihxuAynWj6zzp2gf9Ey2f7ImhFm6ikB3CLf5Z/zmcJDri6B4+9j9RsA==",
419 "dev": true, 483 "dev": true,
420 "requires": { 484 "requires": {
421 "@babel/helper-plugin-utils": "^7.8.3", 485 "@babel/helper-plugin-utils": "^7.10.1",
422 "@babel/plugin-syntax-numeric-separator": "^7.8.3" 486 "@babel/plugin-syntax-numeric-separator": "^7.10.1"
423 } 487 }
424 }, 488 },
425 "@babel/plugin-proposal-object-rest-spread": { 489 "@babel/plugin-proposal-object-rest-spread": {
426 "version": "7.9.0", 490 "version": "7.10.3",
427 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.0.tgz", 491 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.10.3.tgz",
428 "integrity": "sha512-UgqBv6bjq4fDb8uku9f+wcm1J7YxJ5nT7WO/jBr0cl0PLKb7t1O6RNR1kZbjgx2LQtsDI9hwoQVmn0yhXeQyow==", 492 "integrity": "sha512-ZZh5leCIlH9lni5bU/wB/UcjtcVLgR8gc+FAgW2OOY+m9h1II3ItTO1/cewNUcsIDZSYcSaz/rYVls+Fb0ExVQ==",
429 "dev": true, 493 "dev": true,
430 "requires": { 494 "requires": {
431 "@babel/helper-plugin-utils": "^7.8.3", 495 "@babel/helper-plugin-utils": "^7.10.3",
432 "@babel/plugin-syntax-object-rest-spread": "^7.8.0" 496 "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
497 "@babel/plugin-transform-parameters": "^7.10.1"
433 } 498 }
434 }, 499 },
435 "@babel/plugin-proposal-optional-catch-binding": { 500 "@babel/plugin-proposal-optional-catch-binding": {
436 "version": "7.8.3", 501 "version": "7.10.1",
437 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz", 502 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.1.tgz",
438 "integrity": "sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw==", 503 "integrity": "sha512-VqExgeE62YBqI3ogkGoOJp1R6u12DFZjqwJhqtKc2o5m1YTUuUWnos7bZQFBhwkxIFpWYJ7uB75U7VAPPiKETA==",
439 "dev": true, 504 "dev": true,
440 "requires": { 505 "requires": {
441 "@babel/helper-plugin-utils": "^7.8.3", 506 "@babel/helper-plugin-utils": "^7.10.1",
442 "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" 507 "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
443 } 508 }
444 }, 509 },
445 "@babel/plugin-proposal-optional-chaining": { 510 "@babel/plugin-proposal-optional-chaining": {
446 "version": "7.9.0", 511 "version": "7.10.3",
447 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz", 512 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.10.3.tgz",
448 "integrity": "sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w==", 513 "integrity": "sha512-yyG3n9dJ1vZ6v5sfmIlMMZ8azQoqx/5/nZTSWX1td6L1H1bsjzA8TInDChpafCZiJkeOFzp/PtrfigAQXxI1Ng==",
449 "dev": true, 514 "dev": true,
450 "requires": { 515 "requires": {
451 "@babel/helper-plugin-utils": "^7.8.3", 516 "@babel/helper-plugin-utils": "^7.10.3",
452 "@babel/plugin-syntax-optional-chaining": "^7.8.0" 517 "@babel/plugin-syntax-optional-chaining": "^7.8.0"
453 } 518 }
454 }, 519 },
520 "@babel/plugin-proposal-private-methods": {
521 "version": "7.10.1",
522 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.1.tgz",
523 "integrity": "sha512-RZecFFJjDiQ2z6maFprLgrdnm0OzoC23Mx89xf1CcEsxmHuzuXOdniEuI+S3v7vjQG4F5sa6YtUp+19sZuSxHg==",
524 "dev": true,
525 "requires": {
526 "@babel/helper-create-class-features-plugin": "^7.10.1",
527 "@babel/helper-plugin-utils": "^7.10.1"
528 }
529 },
455 "@babel/plugin-proposal-unicode-property-regex": { 530 "@babel/plugin-proposal-unicode-property-regex": {
456 "version": "7.8.8", 531 "version": "7.10.1",
457 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz", 532 "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.1.tgz",
458 "integrity": "sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A==", 533 "integrity": "sha512-JjfngYRvwmPwmnbRZyNiPFI8zxCZb8euzbCG/LxyKdeTb59tVciKo9GK9bi6JYKInk1H11Dq9j/zRqIH4KigfQ==",
459 "dev": true, 534 "dev": true,
460 "requires": { 535 "requires": {
461 "@babel/helper-create-regexp-features-plugin": "^7.8.8", 536 "@babel/helper-create-regexp-features-plugin": "^7.10.1",
462 "@babel/helper-plugin-utils": "^7.8.3" 537 "@babel/helper-plugin-utils": "^7.10.1"
463 } 538 }
464 }, 539 },
465 "@babel/plugin-syntax-async-generators": { 540 "@babel/plugin-syntax-async-generators": {
@@ -471,13 +546,22 @@
471 "@babel/helper-plugin-utils": "^7.8.0" 546 "@babel/helper-plugin-utils": "^7.8.0"
472 } 547 }
473 }, 548 },
549 "@babel/plugin-syntax-class-properties": {
550 "version": "7.10.1",
551 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz",
552 "integrity": "sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ==",
553 "dev": true,
554 "requires": {
555 "@babel/helper-plugin-utils": "^7.10.1"
556 }
557 },
474 "@babel/plugin-syntax-decorators": { 558 "@babel/plugin-syntax-decorators": {
475 "version": "7.8.3", 559 "version": "7.10.1",
476 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz", 560 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.10.1.tgz",
477 "integrity": "sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ==", 561 "integrity": "sha512-a9OAbQhKOwSle1Vr0NJu/ISg1sPfdEkfRKWpgPuzhnWWzForou2gIeUIIwjAMHRekhhpJ7eulZlYs0H14Cbi+g==",
478 "dev": true, 562 "dev": true,
479 "requires": { 563 "requires": {
480 "@babel/helper-plugin-utils": "^7.8.3" 564 "@babel/helper-plugin-utils": "^7.10.1"
481 } 565 }
482 }, 566 },
483 "@babel/plugin-syntax-dynamic-import": { 567 "@babel/plugin-syntax-dynamic-import": {
@@ -499,12 +583,12 @@
499 } 583 }
500 }, 584 },
501 "@babel/plugin-syntax-jsx": { 585 "@babel/plugin-syntax-jsx": {
502 "version": "7.8.3", 586 "version": "7.10.1",
503 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.8.3.tgz", 587 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.10.1.tgz",
504 "integrity": "sha512-WxdW9xyLgBdefoo0Ynn3MRSkhe5tFVxxKNVdnZSh318WrG2e2jH+E9wd/++JsqcLJZPfz87njQJ8j2Upjm0M0A==", 588 "integrity": "sha512-+OxyOArpVFXQeXKLO9o+r2I4dIoVoy6+Uu0vKELrlweDM3QJADZj+Z+5ERansZqIZBcLj42vHnDI8Rz9BnRIuQ==",
505 "dev": true, 589 "dev": true,
506 "requires": { 590 "requires": {
507 "@babel/helper-plugin-utils": "^7.8.3" 591 "@babel/helper-plugin-utils": "^7.10.1"
508 } 592 }
509 }, 593 },
510 "@babel/plugin-syntax-nullish-coalescing-operator": { 594 "@babel/plugin-syntax-nullish-coalescing-operator": {
@@ -517,12 +601,12 @@
517 } 601 }
518 }, 602 },
519 "@babel/plugin-syntax-numeric-separator": { 603 "@babel/plugin-syntax-numeric-separator": {
520 "version": "7.8.3", 604 "version": "7.10.1",
521 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz", 605 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz",
522 "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==", 606 "integrity": "sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg==",
523 "dev": true, 607 "dev": true,
524 "requires": { 608 "requires": {
525 "@babel/helper-plugin-utils": "^7.8.3" 609 "@babel/helper-plugin-utils": "^7.10.1"
526 } 610 }
527 }, 611 },
528 "@babel/plugin-syntax-object-rest-spread": { 612 "@babel/plugin-syntax-object-rest-spread": {
@@ -553,398 +637,443 @@
553 } 637 }
554 }, 638 },
555 "@babel/plugin-syntax-top-level-await": { 639 "@babel/plugin-syntax-top-level-await": {
556 "version": "7.8.3", 640 "version": "7.10.1",
557 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz", 641 "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.1.tgz",
558 "integrity": "sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g==", 642 "integrity": "sha512-hgA5RYkmZm8FTFT3yu2N9Bx7yVVOKYT6yEdXXo6j2JTm0wNxgqaGeQVaSHRjhfnQbX91DtjFB6McRFSlcJH3xQ==",
559 "dev": true, 643 "dev": true,
560 "requires": { 644 "requires": {
561 "@babel/helper-plugin-utils": "^7.8.3" 645 "@babel/helper-plugin-utils": "^7.10.1"
562 } 646 }
563 }, 647 },
564 "@babel/plugin-transform-arrow-functions": { 648 "@babel/plugin-transform-arrow-functions": {
565 "version": "7.8.3", 649 "version": "7.10.1",
566 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz", 650 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.1.tgz",
567 "integrity": "sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg==", 651 "integrity": "sha512-6AZHgFJKP3DJX0eCNJj01RpytUa3SOGawIxweHkNX2L6PYikOZmoh5B0d7hIHaIgveMjX990IAa/xK7jRTN8OA==",
568 "dev": true, 652 "dev": true,
569 "requires": { 653 "requires": {
570 "@babel/helper-plugin-utils": "^7.8.3" 654 "@babel/helper-plugin-utils": "^7.10.1"
571 } 655 }
572 }, 656 },
573 "@babel/plugin-transform-async-to-generator": { 657 "@babel/plugin-transform-async-to-generator": {
574 "version": "7.8.3", 658 "version": "7.10.1",
575 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz", 659 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.1.tgz",
576 "integrity": "sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ==", 660 "integrity": "sha512-XCgYjJ8TY2slj6SReBUyamJn3k2JLUIiiR5b6t1mNCMSvv7yx+jJpaewakikp0uWFQSF7ChPPoe3dHmXLpISkg==",
577 "dev": true, 661 "dev": true,
578 "requires": { 662 "requires": {
579 "@babel/helper-module-imports": "^7.8.3", 663 "@babel/helper-module-imports": "^7.10.1",
580 "@babel/helper-plugin-utils": "^7.8.3", 664 "@babel/helper-plugin-utils": "^7.10.1",
581 "@babel/helper-remap-async-to-generator": "^7.8.3" 665 "@babel/helper-remap-async-to-generator": "^7.10.1"
582 } 666 }
583 }, 667 },
584 "@babel/plugin-transform-block-scoped-functions": { 668 "@babel/plugin-transform-block-scoped-functions": {
585 "version": "7.8.3", 669 "version": "7.10.1",
586 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz", 670 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.1.tgz",
587 "integrity": "sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg==", 671 "integrity": "sha512-B7K15Xp8lv0sOJrdVAoukKlxP9N59HS48V1J3U/JGj+Ad+MHq+am6xJVs85AgXrQn4LV8vaYFOB+pr/yIuzW8Q==",
588 "dev": true, 672 "dev": true,
589 "requires": { 673 "requires": {
590 "@babel/helper-plugin-utils": "^7.8.3" 674 "@babel/helper-plugin-utils": "^7.10.1"
591 } 675 }
592 }, 676 },
593 "@babel/plugin-transform-block-scoping": { 677 "@babel/plugin-transform-block-scoping": {
594 "version": "7.8.3", 678 "version": "7.10.1",
595 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz", 679 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.10.1.tgz",
596 "integrity": "sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w==", 680 "integrity": "sha512-8bpWG6TtF5akdhIm/uWTyjHqENpy13Fx8chg7pFH875aNLwX8JxIxqm08gmAT+Whe6AOmaTeLPe7dpLbXt+xUw==",
597 "dev": true, 681 "dev": true,
598 "requires": { 682 "requires": {
599 "@babel/helper-plugin-utils": "^7.8.3", 683 "@babel/helper-plugin-utils": "^7.10.1",
600 "lodash": "^4.17.13" 684 "lodash": "^4.17.13"
601 } 685 }
602 }, 686 },
603 "@babel/plugin-transform-classes": { 687 "@babel/plugin-transform-classes": {
604 "version": "7.9.2", 688 "version": "7.10.3",
605 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.2.tgz", 689 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.3.tgz",
606 "integrity": "sha512-TC2p3bPzsfvSsqBZo0kJnuelnoK9O3welkUpqSqBQuBF6R5MN2rysopri8kNvtlGIb2jmUO7i15IooAZJjZuMQ==", 690 "integrity": "sha512-irEX0ChJLaZVC7FvvRoSIxJlmk0IczFLcwaRXUArBKYHCHbOhe57aG8q3uw/fJsoSXvZhjRX960hyeAGlVBXZw==",
607 "dev": true, 691 "dev": true,
608 "requires": { 692 "requires": {
609 "@babel/helper-annotate-as-pure": "^7.8.3", 693 "@babel/helper-annotate-as-pure": "^7.10.1",
610 "@babel/helper-define-map": "^7.8.3", 694 "@babel/helper-define-map": "^7.10.3",
611 "@babel/helper-function-name": "^7.8.3", 695 "@babel/helper-function-name": "^7.10.3",
612 "@babel/helper-optimise-call-expression": "^7.8.3", 696 "@babel/helper-optimise-call-expression": "^7.10.3",
613 "@babel/helper-plugin-utils": "^7.8.3", 697 "@babel/helper-plugin-utils": "^7.10.3",
614 "@babel/helper-replace-supers": "^7.8.6", 698 "@babel/helper-replace-supers": "^7.10.1",
615 "@babel/helper-split-export-declaration": "^7.8.3", 699 "@babel/helper-split-export-declaration": "^7.10.1",
616 "globals": "^11.1.0" 700 "globals": "^11.1.0"
617 } 701 }
618 }, 702 },
619 "@babel/plugin-transform-computed-properties": { 703 "@babel/plugin-transform-computed-properties": {
620 "version": "7.8.3", 704 "version": "7.10.3",
621 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz", 705 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.3.tgz",
622 "integrity": "sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA==", 706 "integrity": "sha512-GWzhaBOsdbjVFav96drOz7FzrcEW6AP5nax0gLIpstiFaI3LOb2tAg06TimaWU6YKOfUACK3FVrxPJ4GSc5TgA==",
623 "dev": true, 707 "dev": true,
624 "requires": { 708 "requires": {
625 "@babel/helper-plugin-utils": "^7.8.3" 709 "@babel/helper-plugin-utils": "^7.10.3"
626 } 710 }
627 }, 711 },
628 "@babel/plugin-transform-destructuring": { 712 "@babel/plugin-transform-destructuring": {
629 "version": "7.8.8", 713 "version": "7.10.1",
630 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.8.8.tgz", 714 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.1.tgz",
631 "integrity": "sha512-eRJu4Vs2rmttFCdhPUM3bV0Yo/xPSdPw6ML9KHs/bjB4bLA5HXlbvYXPOD5yASodGod+krjYx21xm1QmL8dCJQ==", 715 "integrity": "sha512-V/nUc4yGWG71OhaTH705pU8ZSdM6c1KmmLP8ys59oOYbT7RpMYAR3MsVOt6OHL0WzG7BlTU076va9fjJyYzJMA==",
632 "dev": true, 716 "dev": true,
633 "requires": { 717 "requires": {
634 "@babel/helper-plugin-utils": "^7.8.3" 718 "@babel/helper-plugin-utils": "^7.10.1"
635 } 719 }
636 }, 720 },
637 "@babel/plugin-transform-dotall-regex": { 721 "@babel/plugin-transform-dotall-regex": {
638 "version": "7.8.3", 722 "version": "7.10.1",
639 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz", 723 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.1.tgz",
640 "integrity": "sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw==", 724 "integrity": "sha512-19VIMsD1dp02RvduFUmfzj8uknaO3uiHHF0s3E1OHnVsNj8oge8EQ5RzHRbJjGSetRnkEuBYO7TG1M5kKjGLOA==",
641 "dev": true, 725 "dev": true,
642 "requires": { 726 "requires": {
643 "@babel/helper-create-regexp-features-plugin": "^7.8.3", 727 "@babel/helper-create-regexp-features-plugin": "^7.10.1",
644 "@babel/helper-plugin-utils": "^7.8.3" 728 "@babel/helper-plugin-utils": "^7.10.1"
645 } 729 }
646 }, 730 },
647 "@babel/plugin-transform-duplicate-keys": { 731 "@babel/plugin-transform-duplicate-keys": {
648 "version": "7.8.3", 732 "version": "7.10.1",
649 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz", 733 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.1.tgz",
650 "integrity": "sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ==", 734 "integrity": "sha512-wIEpkX4QvX8Mo9W6XF3EdGttrIPZWozHfEaDTU0WJD/TDnXMvdDh30mzUl/9qWhnf7naicYartcEfUghTCSNpA==",
651 "dev": true, 735 "dev": true,
652 "requires": { 736 "requires": {
653 "@babel/helper-plugin-utils": "^7.8.3" 737 "@babel/helper-plugin-utils": "^7.10.1"
654 } 738 }
655 }, 739 },
656 "@babel/plugin-transform-exponentiation-operator": { 740 "@babel/plugin-transform-exponentiation-operator": {
657 "version": "7.8.3", 741 "version": "7.10.1",
658 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz", 742 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.1.tgz",
659 "integrity": "sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ==", 743 "integrity": "sha512-lr/przdAbpEA2BUzRvjXdEDLrArGRRPwbaF9rvayuHRvdQ7lUTTkZnhZrJ4LE2jvgMRFF4f0YuPQ20vhiPYxtA==",
660 "dev": true, 744 "dev": true,
661 "requires": { 745 "requires": {
662 "@babel/helper-builder-binary-assignment-operator-visitor": "^7.8.3", 746 "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.1",
663 "@babel/helper-plugin-utils": "^7.8.3" 747 "@babel/helper-plugin-utils": "^7.10.1"
664 } 748 }
665 }, 749 },
666 "@babel/plugin-transform-for-of": { 750 "@babel/plugin-transform-for-of": {
667 "version": "7.9.0", 751 "version": "7.10.1",
668 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz", 752 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.1.tgz",
669 "integrity": "sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ==", 753 "integrity": "sha512-US8KCuxfQcn0LwSCMWMma8M2R5mAjJGsmoCBVwlMygvmDUMkTCykc84IqN1M7t+agSfOmLYTInLCHJM+RUoz+w==",
670 "dev": true, 754 "dev": true,
671 "requires": { 755 "requires": {
672 "@babel/helper-plugin-utils": "^7.8.3" 756 "@babel/helper-plugin-utils": "^7.10.1"
673 } 757 }
674 }, 758 },
675 "@babel/plugin-transform-function-name": { 759 "@babel/plugin-transform-function-name": {
676 "version": "7.8.3", 760 "version": "7.10.1",
677 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz", 761 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.1.tgz",
678 "integrity": "sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ==", 762 "integrity": "sha512-//bsKsKFBJfGd65qSNNh1exBy5Y9gD9ZN+DvrJ8f7HXr4avE5POW6zB7Rj6VnqHV33+0vXWUwJT0wSHubiAQkw==",
679 "dev": true, 763 "dev": true,
680 "requires": { 764 "requires": {
681 "@babel/helper-function-name": "^7.8.3", 765 "@babel/helper-function-name": "^7.10.1",
682 "@babel/helper-plugin-utils": "^7.8.3" 766 "@babel/helper-plugin-utils": "^7.10.1"
683 } 767 }
684 }, 768 },
685 "@babel/plugin-transform-literals": { 769 "@babel/plugin-transform-literals": {
686 "version": "7.8.3", 770 "version": "7.10.1",
687 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz", 771 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.1.tgz",
688 "integrity": "sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A==", 772 "integrity": "sha512-qi0+5qgevz1NHLZroObRm5A+8JJtibb7vdcPQF1KQE12+Y/xxl8coJ+TpPW9iRq+Mhw/NKLjm+5SHtAHCC7lAw==",
689 "dev": true, 773 "dev": true,
690 "requires": { 774 "requires": {
691 "@babel/helper-plugin-utils": "^7.8.3" 775 "@babel/helper-plugin-utils": "^7.10.1"
692 } 776 }
693 }, 777 },
694 "@babel/plugin-transform-member-expression-literals": { 778 "@babel/plugin-transform-member-expression-literals": {
695 "version": "7.8.3", 779 "version": "7.10.1",
696 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz", 780 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.1.tgz",
697 "integrity": "sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA==", 781 "integrity": "sha512-UmaWhDokOFT2GcgU6MkHC11i0NQcL63iqeufXWfRy6pUOGYeCGEKhvfFO6Vz70UfYJYHwveg62GS83Rvpxn+NA==",
698 "dev": true, 782 "dev": true,
699 "requires": { 783 "requires": {
700 "@babel/helper-plugin-utils": "^7.8.3" 784 "@babel/helper-plugin-utils": "^7.10.1"
701 } 785 }
702 }, 786 },
703 "@babel/plugin-transform-modules-amd": { 787 "@babel/plugin-transform-modules-amd": {
704 "version": "7.9.0", 788 "version": "7.10.1",
705 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz", 789 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.1.tgz",
706 "integrity": "sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q==", 790 "integrity": "sha512-31+hnWSFRI4/ACFr1qkboBbrTxoBIzj7qA69qlq8HY8p7+YCzkCT6/TvQ1a4B0z27VeWtAeJd6pr5G04dc1iHw==",
707 "dev": true, 791 "dev": true,
708 "requires": { 792 "requires": {
709 "@babel/helper-module-transforms": "^7.9.0", 793 "@babel/helper-module-transforms": "^7.10.1",
710 "@babel/helper-plugin-utils": "^7.8.3", 794 "@babel/helper-plugin-utils": "^7.10.1",
711 "babel-plugin-dynamic-import-node": "^2.3.0" 795 "babel-plugin-dynamic-import-node": "^2.3.3"
712 } 796 }
713 }, 797 },
714 "@babel/plugin-transform-modules-commonjs": { 798 "@babel/plugin-transform-modules-commonjs": {
715 "version": "7.9.0", 799 "version": "7.10.1",
716 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz", 800 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.1.tgz",
717 "integrity": "sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g==", 801 "integrity": "sha512-AQG4fc3KOah0vdITwt7Gi6hD9BtQP/8bhem7OjbaMoRNCH5Djx42O2vYMfau7QnAzQCa+RJnhJBmFFMGpQEzrg==",
718 "dev": true, 802 "dev": true,
719 "requires": { 803 "requires": {
720 "@babel/helper-module-transforms": "^7.9.0", 804 "@babel/helper-module-transforms": "^7.10.1",
721 "@babel/helper-plugin-utils": "^7.8.3", 805 "@babel/helper-plugin-utils": "^7.10.1",
722 "@babel/helper-simple-access": "^7.8.3", 806 "@babel/helper-simple-access": "^7.10.1",
723 "babel-plugin-dynamic-import-node": "^2.3.0" 807 "babel-plugin-dynamic-import-node": "^2.3.3"
724 } 808 }
725 }, 809 },
726 "@babel/plugin-transform-modules-systemjs": { 810 "@babel/plugin-transform-modules-systemjs": {
727 "version": "7.9.0", 811 "version": "7.10.3",
728 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz", 812 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.3.tgz",
729 "integrity": "sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ==", 813 "integrity": "sha512-GWXWQMmE1GH4ALc7YXW56BTh/AlzvDWhUNn9ArFF0+Cz5G8esYlVbXfdyHa1xaD1j+GnBoCeoQNlwtZTVdiG/A==",
730 "dev": true, 814 "dev": true,
731 "requires": { 815 "requires": {
732 "@babel/helper-hoist-variables": "^7.8.3", 816 "@babel/helper-hoist-variables": "^7.10.3",
733 "@babel/helper-module-transforms": "^7.9.0", 817 "@babel/helper-module-transforms": "^7.10.1",
734 "@babel/helper-plugin-utils": "^7.8.3", 818 "@babel/helper-plugin-utils": "^7.10.3",
735 "babel-plugin-dynamic-import-node": "^2.3.0" 819 "babel-plugin-dynamic-import-node": "^2.3.3"
736 } 820 }
737 }, 821 },
738 "@babel/plugin-transform-modules-umd": { 822 "@babel/plugin-transform-modules-umd": {
739 "version": "7.9.0", 823 "version": "7.10.1",
740 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz", 824 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.1.tgz",
741 "integrity": "sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ==", 825 "integrity": "sha512-EIuiRNMd6GB6ulcYlETnYYfgv4AxqrswghmBRQbWLHZxN4s7mupxzglnHqk9ZiUpDI4eRWewedJJNj67PWOXKA==",
742 "dev": true, 826 "dev": true,
743 "requires": { 827 "requires": {
744 "@babel/helper-module-transforms": "^7.9.0", 828 "@babel/helper-module-transforms": "^7.10.1",
745 "@babel/helper-plugin-utils": "^7.8.3" 829 "@babel/helper-plugin-utils": "^7.10.1"
746 } 830 }
747 }, 831 },
748 "@babel/plugin-transform-named-capturing-groups-regex": { 832 "@babel/plugin-transform-named-capturing-groups-regex": {
749 "version": "7.8.3", 833 "version": "7.10.3",
750 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz", 834 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.3.tgz",
751 "integrity": "sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw==", 835 "integrity": "sha512-I3EH+RMFyVi8Iy/LekQm948Z4Lz4yKT7rK+vuCAeRm0kTa6Z5W7xuhRxDNJv0FPya/her6AUgrDITb70YHtTvA==",
752 "dev": true, 836 "dev": true,
753 "requires": { 837 "requires": {
754 "@babel/helper-create-regexp-features-plugin": "^7.8.3" 838 "@babel/helper-create-regexp-features-plugin": "^7.8.3"
755 } 839 }
756 }, 840 },
757 "@babel/plugin-transform-new-target": { 841 "@babel/plugin-transform-new-target": {
758 "version": "7.8.3", 842 "version": "7.10.1",
759 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz", 843 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.1.tgz",
760 "integrity": "sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw==", 844 "integrity": "sha512-MBlzPc1nJvbmO9rPr1fQwXOM2iGut+JC92ku6PbiJMMK7SnQc1rytgpopveE3Evn47gzvGYeCdgfCDbZo0ecUw==",
761 "dev": true, 845 "dev": true,
762 "requires": { 846 "requires": {
763 "@babel/helper-plugin-utils": "^7.8.3" 847 "@babel/helper-plugin-utils": "^7.10.1"
764 } 848 }
765 }, 849 },
766 "@babel/plugin-transform-object-super": { 850 "@babel/plugin-transform-object-super": {
767 "version": "7.8.3", 851 "version": "7.10.1",
768 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz", 852 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.1.tgz",
769 "integrity": "sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ==", 853 "integrity": "sha512-WnnStUDN5GL+wGQrJylrnnVlFhFmeArINIR9gjhSeYyvroGhBrSAXYg/RHsnfzmsa+onJrTJrEClPzgNmmQ4Gw==",
770 "dev": true, 854 "dev": true,
771 "requires": { 855 "requires": {
772 "@babel/helper-plugin-utils": "^7.8.3", 856 "@babel/helper-plugin-utils": "^7.10.1",
773 "@babel/helper-replace-supers": "^7.8.3" 857 "@babel/helper-replace-supers": "^7.10.1"
774 } 858 }
775 }, 859 },
776 "@babel/plugin-transform-parameters": { 860 "@babel/plugin-transform-parameters": {
777 "version": "7.9.3", 861 "version": "7.10.1",
778 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.3.tgz", 862 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.1.tgz",
779 "integrity": "sha512-fzrQFQhp7mIhOzmOtPiKffvCYQSK10NR8t6BBz2yPbeUHb9OLW8RZGtgDRBn8z2hGcwvKDL3vC7ojPTLNxmqEg==", 863 "integrity": "sha512-tJ1T0n6g4dXMsL45YsSzzSDZCxiHXAQp/qHrucOq5gEHncTA3xDxnd5+sZcoQp+N1ZbieAaB8r/VUCG0gqseOg==",
780 "dev": true, 864 "dev": true,
781 "requires": { 865 "requires": {
782 "@babel/helper-get-function-arity": "^7.8.3", 866 "@babel/helper-get-function-arity": "^7.10.1",
783 "@babel/helper-plugin-utils": "^7.8.3" 867 "@babel/helper-plugin-utils": "^7.10.1"
784 } 868 }
785 }, 869 },
786 "@babel/plugin-transform-property-literals": { 870 "@babel/plugin-transform-property-literals": {
787 "version": "7.8.3", 871 "version": "7.10.1",
788 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz", 872 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.1.tgz",
789 "integrity": "sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg==", 873 "integrity": "sha512-Kr6+mgag8auNrgEpbfIWzdXYOvqDHZOF0+Bx2xh4H2EDNwcbRb9lY6nkZg8oSjsX+DH9Ebxm9hOqtKW+gRDeNA==",
790 "dev": true, 874 "dev": true,
791 "requires": { 875 "requires": {
792 "@babel/helper-plugin-utils": "^7.8.3" 876 "@babel/helper-plugin-utils": "^7.10.1"
793 } 877 }
794 }, 878 },
795 "@babel/plugin-transform-regenerator": { 879 "@babel/plugin-transform-regenerator": {
796 "version": "7.8.7", 880 "version": "7.10.3",
797 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz", 881 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.3.tgz",
798 "integrity": "sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==", 882 "integrity": "sha512-H5kNeW0u8mbk0qa1jVIVTeJJL6/TJ81ltD4oyPx0P499DhMJrTmmIFCmJ3QloGpQG8K9symccB7S7SJpCKLwtw==",
799 "dev": true, 883 "dev": true,
800 "requires": { 884 "requires": {
801 "regenerator-transform": "^0.14.2" 885 "regenerator-transform": "^0.14.2"
802 } 886 }
803 }, 887 },
804 "@babel/plugin-transform-reserved-words": { 888 "@babel/plugin-transform-reserved-words": {
805 "version": "7.8.3", 889 "version": "7.10.1",
806 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz", 890 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.1.tgz",
807 "integrity": "sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A==", 891 "integrity": "sha512-qN1OMoE2nuqSPmpTqEM7OvJ1FkMEV+BjVeZZm9V9mq/x1JLKQ4pcv8riZJMNN3u2AUGl0ouOMjRr2siecvHqUQ==",
808 "dev": true, 892 "dev": true,
809 "requires": { 893 "requires": {
810 "@babel/helper-plugin-utils": "^7.8.3" 894 "@babel/helper-plugin-utils": "^7.10.1"
811 } 895 }
812 }, 896 },
813 "@babel/plugin-transform-runtime": { 897 "@babel/plugin-transform-runtime": {
814 "version": "7.9.0", 898 "version": "7.10.3",
815 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz", 899 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.10.3.tgz",
816 "integrity": "sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==", 900 "integrity": "sha512-b5OzMD1Hi8BBzgQdRHyVVaYrk9zG0wset1it2o3BgonkPadXfOv0aXRqd7864DeOIu3FGKP/h6lr15FE5mahVw==",
817 "dev": true, 901 "dev": true,
818 "requires": { 902 "requires": {
819 "@babel/helper-module-imports": "^7.8.3", 903 "@babel/helper-module-imports": "^7.10.3",
820 "@babel/helper-plugin-utils": "^7.8.3", 904 "@babel/helper-plugin-utils": "^7.10.3",
821 "resolve": "^1.8.1", 905 "resolve": "^1.8.1",
822 "semver": "^5.5.1" 906 "semver": "^5.5.1"
823 } 907 }
824 }, 908 },
825 "@babel/plugin-transform-shorthand-properties": { 909 "@babel/plugin-transform-shorthand-properties": {
826 "version": "7.8.3", 910 "version": "7.10.1",
827 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz", 911 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.1.tgz",
828 "integrity": "sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w==", 912 "integrity": "sha512-AR0E/lZMfLstScFwztApGeyTHJ5u3JUKMjneqRItWeEqDdHWZwAOKycvQNCasCK/3r5YXsuNG25funcJDu7Y2g==",
829 "dev": true, 913 "dev": true,
830 "requires": { 914 "requires": {
831 "@babel/helper-plugin-utils": "^7.8.3" 915 "@babel/helper-plugin-utils": "^7.10.1"
832 } 916 }
833 }, 917 },
834 "@babel/plugin-transform-spread": { 918 "@babel/plugin-transform-spread": {
835 "version": "7.8.3", 919 "version": "7.10.1",
836 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz", 920 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.10.1.tgz",
837 "integrity": "sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g==", 921 "integrity": "sha512-8wTPym6edIrClW8FI2IoaePB91ETOtg36dOkj3bYcNe7aDMN2FXEoUa+WrmPc4xa1u2PQK46fUX2aCb+zo9rfw==",
838 "dev": true, 922 "dev": true,
839 "requires": { 923 "requires": {
840 "@babel/helper-plugin-utils": "^7.8.3" 924 "@babel/helper-plugin-utils": "^7.10.1"
841 } 925 }
842 }, 926 },
843 "@babel/plugin-transform-sticky-regex": { 927 "@babel/plugin-transform-sticky-regex": {
844 "version": "7.8.3", 928 "version": "7.10.1",
845 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz", 929 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.1.tgz",
846 "integrity": "sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw==", 930 "integrity": "sha512-j17ojftKjrL7ufX8ajKvwRilwqTok4q+BjkknmQw9VNHnItTyMP5anPFzxFJdCQs7clLcWpCV3ma+6qZWLnGMA==",
847 "dev": true, 931 "dev": true,
848 "requires": { 932 "requires": {
849 "@babel/helper-plugin-utils": "^7.8.3", 933 "@babel/helper-plugin-utils": "^7.10.1",
850 "@babel/helper-regex": "^7.8.3" 934 "@babel/helper-regex": "^7.10.1"
851 } 935 }
852 }, 936 },
853 "@babel/plugin-transform-template-literals": { 937 "@babel/plugin-transform-template-literals": {
854 "version": "7.8.3", 938 "version": "7.10.3",
855 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz", 939 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.3.tgz",
856 "integrity": "sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ==", 940 "integrity": "sha512-yaBn9OpxQra/bk0/CaA4wr41O0/Whkg6nqjqApcinxM7pro51ojhX6fv1pimAnVjVfDy14K0ULoRL70CA9jWWA==",
857 "dev": true, 941 "dev": true,
858 "requires": { 942 "requires": {
859 "@babel/helper-annotate-as-pure": "^7.8.3", 943 "@babel/helper-annotate-as-pure": "^7.10.1",
860 "@babel/helper-plugin-utils": "^7.8.3" 944 "@babel/helper-plugin-utils": "^7.10.3"
861 } 945 }
862 }, 946 },
863 "@babel/plugin-transform-typeof-symbol": { 947 "@babel/plugin-transform-typeof-symbol": {
864 "version": "7.8.4", 948 "version": "7.10.1",
865 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz", 949 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.1.tgz",
866 "integrity": "sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg==", 950 "integrity": "sha512-qX8KZcmbvA23zDi+lk9s6hC1FM7jgLHYIjuLgULgc8QtYnmB3tAVIYkNoKRQ75qWBeyzcoMoK8ZQmogGtC/w0g==",
867 "dev": true, 951 "dev": true,
868 "requires": { 952 "requires": {
869 "@babel/helper-plugin-utils": "^7.8.3" 953 "@babel/helper-plugin-utils": "^7.10.1"
870 } 954 }
871 }, 955 },
872 "@babel/plugin-transform-unicode-regex": { 956 "@babel/plugin-transform-unicode-escapes": {
873 "version": "7.8.3", 957 "version": "7.10.1",
874 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz", 958 "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.1.tgz",
875 "integrity": "sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw==", 959 "integrity": "sha512-zZ0Poh/yy1d4jeDWpx/mNwbKJVwUYJX73q+gyh4bwtG0/iUlzdEu0sLMda8yuDFS6LBQlT/ST1SJAR6zYwXWgw==",
876 "dev": true, 960 "dev": true,
877 "requires": { 961 "requires": {
878 "@babel/helper-create-regexp-features-plugin": "^7.8.3", 962 "@babel/helper-plugin-utils": "^7.10.1"
879 "@babel/helper-plugin-utils": "^7.8.3"
880 } 963 }
881 }, 964 },
882 "@babel/preset-env": { 965 "@babel/plugin-transform-unicode-regex": {
883 "version": "7.9.0", 966 "version": "7.10.1",
884 "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.9.0.tgz", <