movie-monad 0.0.4.0 → 0.0.5.0
raw patch · 41 files changed
+2849/−1007 lines, 41 filesdep +bytestringdep +haskell-gi-overloadingdep ~gi-gtkdep ~haskell-gidep ~haskell-gi-base
Dependencies added: bytestring, haskell-gi-overloading
Dependency ranges changed: gi-gtk, haskell-gi, haskell-gi-base
Files
- CHANGELOG.md +32/−0
- README.md +105/−140
- makefile +49/−36
- movie-monad.cabal +35/−13
- src/About.hs +14/−19
- src/CommandLine.hs +1/−1
- src/Constants.hs +5/−2
- src/CssStyle.hs +121/−0
- src/ErrorMessage.hs +1/−1
- src/FileChooser.hs +109/−120
- src/Fullscreen.hs +5/−5
- src/Keyboard.hs +29/−24
- src/Main.hs +99/−84
- src/Mouse.hs +31/−22
- src/PlayPause.hs +27/−24
- src/Playbin.hs +120/−77
- src/Records.hs +60/−53
- src/Reset.hs +97/−0
- src/ScreensaverAndPowerManagement.hs +1/−1
- src/Seek.hs +62/−49
- src/SubtitleSelector.hs +5/−5
- src/Uri.hs +7/−5
- src/Utils.hs +40/−15
- src/VideoInfo.hs +49/−43
- src/VideoSizeSelector.hs +58/−24
- src/Window.hs +120/−112
- src/c/gst-ffi.c +1/−1
- src/c/gst-ffi.h +1/−1
- src/data/about-icon.svg +267/−0
- src/data/fullscreen-icon.svg +147/−0
- src/data/gui.glade +139/−121
- src/data/movie-monad-icon.png binary
- src/data/movie-monad-icon.svg +267/−0
- src/data/pause-icon.svg +83/−0
- src/data/play-icon.svg +77/−0
- src/data/repeat-icon.svg +193/−0
- src/data/style-3-18.css +40/−0
- src/data/style-3-20.css +24/−0
- src/data/style.css +299/−0
- src/dev/Paths_movie_monad.hs +1/−1
- stack.yaml +28/−8
CHANGELOG.md view
@@ -2,6 +2,38 @@ ## CHANGELOG +-------------------------------------------------------------------------------++### 0.0.5.0++#### Added++- Repeat mode+- Custom icons for new bottom controls+- Custom styling for new bottom controls+- Added a one second fade in animation for the bottom controls+- Added extra error checking around window width combo box selection+- Mac install script++#### Changed++- Tooltips+- Use a SVG icon instead of PNG+- Fixed video info being changed before selecting a video+- Use play and pause image widget names to determine state of the play pause button+- If the user sets the window to a custom size, select nothing in the window selection combo box+- Set timeout for hiding the bottom controls to seven seconds instead of five+- AppImage meta data+- AppImage install script+- Snap packaging+- AUR packaging++#### Removed++-++-------------------------------------------------------------------------------+ ### 0.0.4.0 #### Added
README.md view
@@ -1,43 +1,47 @@  -# Movie Monad--A free and simple to use video player built with Haskell.--## Screenshots+# Movie Monad? Another video player? Really? -### Linux+Yes really. -+Movie Monad is a free and simple to use video player made with Haskell.+Originally it was a proof of concept to add video playback to+[Gifcurry](https://lettier.github.io/gifcurry/) (another great app—check it out).+Nowadays it's a lightweight yet mighty media player used all over the+[world](https://snapcraft.io/movie-monad#js-snap-map)+everyday. -+Movie Monad is cross platform so you'll never have to compute without it.+You can play files on your computer or stream videos from the web.+Play, pause, seek, repeat, resize, expand, and turn it up—Movie Monad gets out of+the way so you can watch the videos you love. -### Mac+So put down your copy of mpv, VLC, or Elmedia and try out Movie Monad—it's FREE! -+## What does Movie Monad look like? -++ -## Features+## What can I do with Movie Monad? -* Local or Remote Video Playback- * `file://`- * `http://`- * `https://`-* Window Size Quick Select-* Responsive Window Resizing-* Fullscreen Mode-* Seek-* Play and Pause-* Volume-* Subtitles- * Disable- * List and Pick from the Available Languages-* Command-line Play+* You can play video files from your hard drive or stream videos from the web.+ * To play web videos, click the file open button, paste the URL into the text box, and click open.+ * Movie Monad can handle `file://`, `https://`, and `http://`.+* You can play and pause.+* You can seek/scrub through the video.+* You can put the video on repeat.+* You can turn subtitles off or on and pick your language.+* You can turn up, turn down, or mute the volume.+* You can expand the video to fullscreen.+* You can quickly resize the video to standard sizes.+* You can resize the video to a custom size by resizing the window.+ * Movie Monad will responsively adjust the video size to fill the window.+* You can play videos from the command line. * `movie-monad ./path/to/video/file.mp4` * `movie-monad http://www.domain.tld/path/to/video/file.mp4` -## Keyboard Shortcuts+## What are the keyboard controls? * Mute/Unmute * `m`@@ -46,6 +50,8 @@ * `f` * Show Controls * `c`+* Toggle Repeat+ * `r` * Volume Up * `ArrowUp` * `AudioRaiseVolume`@@ -60,152 +66,111 @@ * `Space` * `AudioPlay` -## Tested On--### Linux--* [Ubuntu 17.10](https://www.ubuntu.com/desktop)-* [Ubuntu 16.04](https://www.ubuntu.com/desktop)-* [Ubuntu 14.04](https://www.ubuntu.com/desktop)-* [Linux Mint 18.2](https://linuxmint.com/)-* [Deepin 15.4.1](https://www.deepin.org/en/dde/)-* [Manjaro 17.04](https://manjaro.org/)-* [Antergos 17.10](https://antergos.com/)-* [Fedora 27](https://getfedora.org/)-* [Solus 3](https://solus-project.com/2017/08/15/solus-3-released/)--### Mac--* [macOS Sierra 10.12.6](https://en.wikipedia.org/wiki/MacOS_Sierra)--## Dependencies--### Run--* [GTK+ >= 3.10](https://www.gtk.org/download/index.php)-* [GStreamer >= 1.0](https://gstreamer.freedesktop.org/download/)- * [GStreamer Good Plug-ins](https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)- * [GStreamer Bad Plug-ins >= 1.8](https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html)--### Build--* [Haskell](https://www.haskell.org/platform/prior.html)- * GHC == 8.0.2--## Install & Run--### Linux+## How do I get a copy of Movie Monad? -#### AppImage+Movie Monad works on Linux, Mac, and most likely Windows.+Make sure you have GStreamer and GTK+ installed on your machine.+To find the latest version of Movie Monad, head over to the+[releases page](https://github.com/lettier/movie-monad/releases). -##### Download & Run+### I use Linux. -```bash-# Install GTK+ >= 3.10 (https://www.gtk.org/download/index.php)-# Install GStreamer >= 1.0 (https://gstreamer.freedesktop.org/download/)-# Install GStreamer Good Plug-ins (https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)-# Install GStreamer Bad Plug-ins >= 1.8 (https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html)-# Install Wget (https://www.gnu.org/software/wget/)-# Visit https://github.com/lettier/movie-monad/releases-# Download the latest AppImage movie-monad-0.0.4.0-x86_64.AppImage-wget https://github.com/lettier/movie-monad/releases/download/0.0.4.0/movie-monad-0.0.4.0-x86_64.AppImage-chmod a+x movie-monad-0.0.4.0-x86_64.AppImage-./movie-monad-0.0.4.0-x86_64.AppImage-```+If you use Linux then the easiest way to grab a copy of Movie Monad is by downloading the+[AppImage](https://github.com/lettier/movie-monad/releases/download/0.0.5.0/movie-monad-0.0.5.0-x86_64.AppImage).+After you download the+[AppImage](https://github.com/lettier/movie-monad/releases/download/0.0.5.0/movie-monad-0.0.5.0-x86_64.AppImage),+right click on it, select permissions, and check the box near execute.+With that out of the way—you're all set—just double click on the AppImage+and Movie Monad will pop up. -##### Install+You can also download and install the+[AppImage](https://github.com/lettier/movie-monad/releases/download/0.0.5.0/movie-monad-0.0.5.0-x86_64.AppImage)+using the handy+[AppImage install script](https://raw.githubusercontent.com/lettier/movie-monad/master/packaging/linux/app-image/movie-monad-install-app-image-script.sh)+(right click the link and select "Save link as...").+Download the script, right click on it, select permissions, check the box near execute, and double click on it.+You should now see Movie Monad listed alongside your other installed programs. -```bash-# Install GTK+ >= 3.10 (https://www.gtk.org/download/index.php)-# Install GStreamer >= 1.0 (https://gstreamer.freedesktop.org/download/)-# Install GStreamer Good Plug-ins (https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)-# Install GStreamer Bad Plug-ins >= 1.8 (https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html)-# Install Wget (https://www.gnu.org/software/wget/)-wget "https://raw.githubusercontent.com/lettier/movie-monad/master/scripts/sh/install-app-image.sh" -O "movie-monad-install-app-image.sh"-chmod +x "movie-monad-install-app-image.sh"-./movie-monad-install-app-image.sh-```+#### I use Arch/Manjaro/Antergos/pacman. -#### [Arch/Manjaro/Antergos](https://aur.archlinux.org/packages/movie-monad/)+If you'd rather install Movie Monad via `pacman` then copy the following into your terminal. ```bash-cd-# Install Git (https://git-scm.com/downloads)+cd "$HOME/Downloads" sudo pacman -S git-# Install Movie Monad from the AUR (https://aur.archlinux.org/packages/movie-monad/)-mkdir -p movie-monad-tmp-cd movie-monad-tmp+mkdir -p build-movie-monad+cd build-movie-monad git clone https://aur.archlinux.org/movie-monad.git cd movie-monad makepkg -sic+cd "$HOME/Downloads"+rm -rf build-movie-monad cd-rm -rf movie-monad-tmp movie-monad ``` -### Mac+#### I use Ubuntu/Mint/Debian/Deepin/snap. -```bash-# Install Homebrew (https://brew.sh/#install)-cd ~/Downloads-brew update && brew upgrade-brew install git-git clone https://github.com/lettier/movie-monad.git-cd movie-monad-brew cask install haskell-platform-brew install pkg-config libffi libav libsvg librsvg libogg libvorbis openh264 theora \- gobject-introspection cairo gdk-pixbuf gsettings-desktop-schemas gtk+3 gtk-mac-integration \- gstreamer gst-libav gst-plugins-base gst-plugins-good-brew install --with-gtk+3 gst-plugins-bad-stack setup-stack install hsc2hs-stack install-export PATH=$PATH:"$HOME/.local/bin/"-movie-monad-```+Movie Monad is available as a snap from [Snapcraft](https://snapcraft.io/).+If you don't already have `snap`, go ahead and install it using the command `sudo apt install snapd`. -### [Hackage](https://hackage.haskell.org/package/movie-monad)+You can install the+[Movie Monad snap](https://snapcraft.io/movie-monad)+right from your browser or via the command line.+For the command line route, paste the following into your terminal. ```bash-# Install GObject Introspection (https://wiki.gnome.org/action/show/Projects/GObjectIntrospection)-# Install GTK+ >= 3.10 (https://www.gtk.org/download/index.php)-# Install GStreamer >= 1.0 (https://gstreamer.freedesktop.org/download/)-# Install GStreamer Good Plug-ins (https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)-# Install GStreamer Bad Plug-ins >= 1.8 (https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html)-# Install Cabal, GHC == 8.0.2 (https://www.haskell.org/platform/prior.html)-# Install Cabal Install (https://www.haskell.org/platform/prior.html)-cabal install movie-monad+snap install movie-monad+sudo snap connect movie-monad:mount-observe+sudo snap connect movie-monad:removable-media+sudo snap connect movie-monad:raw-usb movie-monad ``` -### [GitHub](https://github.com/lettier/movie-monad)+### I use Mac. +Mac users can download and run the+[Mac install script](https://raw.githubusercontent.com/lettier/movie-monad/master/packaging/mac/movie-monad-mac-install-script.command)+(hold down control, click the link, and select "Save Link As...").+After running the install script, a shortcut to Movie Monad will be on your desktop.++### I'm a Haskell developer.++If you develop Haskell programs then the easiest way to build Movie Monad is with+[Haskell Stack](https://docs.haskellstack.org/en/stable/README/).+Copy the following into your terminal.+ ```bash-# Install GObject Introspection (https://wiki.gnome.org/action/show/Projects/GObjectIntrospection)-# Install GTK+ >= 3.10 (https://www.gtk.org/download/index.php)-# Install GStreamer >= 1.0 (https://gstreamer.freedesktop.org/download/)-# Install GStreamer Good Plug-ins (https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)-# Install GStreamer Bad Plug-ins >= 1.8 (https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html)-# Install Git (https://git-scm.com/downloads)-# Install GNU Make (https://www.gnu.org/software/make/)-# Install Haskell, GHC == 8.0.2 (https://www.haskell.org/platform/prior.html)-# Install Haksell Stack (https://www.haskell.org/platform/)+cd "$HOME/Downloads" git clone https://github.com/lettier/movie-monad.git-cd movie-monad/-make-make install-make run+cd movie-monad+stack update+stack setup+stack install alex happy+stack install haskell-gi+stack install+stack exec -- movie-monad ``` -## Developer Documentation+## What dependencies does Movie Monad use? -[Let's make a GTK Video Player with Haskell](https://lettier.github.io/posts/2017-08-30-haskell-gtk-video-player.html)+### To run Movie Monad. -## License+* [GTK+ >= 3.10](https://www.gtk.org/download/index.php)+* [GStreamer >= 1.0](https://gstreamer.freedesktop.org/download/)+ * [GStreamer Good Plug-ins](https://gstreamer.freedesktop.org/modules/gst-plugins-good.html)+ * [GStreamer Bad Plug-ins >= 1.8](https://gstreamer.freedesktop.org/modules/gst-plugins-bad.html) +### To build Movie Monad.++* [GObject Introspection](https://wiki.gnome.org/action/show/Projects/GObjectIntrospection)+* [Haskell Stack](https://docs.haskellstack.org/en/stable/README/)++## What is the license?+ See [LICENSE](LICENSE). -## Copyright+## Who wrote Movie Monad? (C) 2017 David Lettier [lettier.com](http://www.lettier.com/)
makefile view
@@ -3,50 +3,63 @@ .RECIPEPREFIX != ps -STACK=stack --allow-different-user-STACK_SNAPSHOT_INSTALL_ROOT=`$(STACK) path --snapshot-install-root`-STACK_SNAPSHOT_INSTALL_ROOT_BIN=$(STACK_SNAPSHOT_INSTALL_ROOT)/bin-STACK_PATH_LOCAL_BIN=`$(STACK) path --local-bin`-STACK_GHC_EXE=`$(STACK) path --compiler-exe`-STACK_GHC_BIN=`$(STACK) path --compiler-bin`-STACK_PATHS=$(STACK_PATH_LOCAL_BIN):$(STACK_GHC_BIN):$(STACK_SNAPSHOT_INSTALL_ROOT):$(STACK_SNAPSHOT_INSTALL_ROOT_BIN)-CABAL=env PATH=$(PATH):$(STACK_PATHS) $(STACK_SNAPSHOT_INSTALL_ROOT_BIN)/cabal+_NAME="movie-monad"+_STACK=stack --allow-different-user+_STACK_SNAPSHOT_INSTALL_ROOT=`$(_STACK) path --snapshot-install-root`+_STACK_SNAPSHOT_INSTALL_ROOT_BIN="$(_STACK_SNAPSHOT_INSTALL_ROOT)/bin"+_STACK_PATH_LOCAL_BIN=`$(_STACK) path --local-bin`+_STACK_GHC_EXE=`$(_STACK) path --compiler-exe`+_STACK_GHC_BIN=`$(_STACK) path --compiler-bin`+_STACK_PATHS=$(_STACK_PATH_LOCAL_BIN):$(_STACK_GHC_BIN):$(_STACK_SNAPSHOT_INSTALL_ROOT):$(_STACK_SNAPSHOT_INSTALL_ROOT_BIN)+_CABAL=env PATH=$(PATH):$(_STACK_PATHS) "$(_STACK_SNAPSHOT_INSTALL_ROOT_BIN)/cabal"+_CABAL_SANDBOX_DIR=".cabal-sandbox"+_APPLICATIONS_DESKTOP_DIR="$(_CABAL_SANDBOX_DIR)/share/applications"+_ICONS_HICOLOR_SCALABLE_APPS_DIR="$(_CABAL_SANDBOX_DIR)/share/icons/hicolor/scalable/apps"+_PACKAGING_LINUX_COMMON_DIR="./packaging/linux/common" -export PATH := $(PATH):$(STACK_PATHS)+export PATH := $(PATH):$(_STACK_PATHS) -all: setup build+all: install setup:- $(STACK) setup && \- $(STACK) update && \- $(STACK) build alex && \- $(STACK) build happy+ $(_STACK) update && \+ $(_STACK) setup && \+ $(_STACK) install alex happy && \+ $(_STACK) install haskell-gi -build: setup- $(STACK) build+cabal_update: setup+ $(_CABAL) update -install: build- $(STACK) install+cabal_sandbox_init: cabal_update+ $(_CABAL) sandbox init -run: install- $(STACK) exec -- movie-monad+cabal_clean: cabal_update+ $(_CABAL) clean && \+ $(_CABAL) sandbox init && \+ $(_CABAL) sandbox delete && \+ $(_CABAL) sandbox init -build_sdist:- $(STACK) sdist+cabal_install_dependencies: cabal_sandbox_init+ $(_CABAL) --require-sandbox install --dependencies-only --force-reinstalls -j -w $(_STACK_GHC_EXE) -cabal_update: setup- $(STACK) build cabal-install && \- $(CABAL) update+cabal_configure: cabal_install_dependencies+ $(_CABAL) --require-sandbox configure --enable-relocatable -w $(_STACK_GHC_EXE) -cabal_clean: cabal_update- $(CABAL) clean && \- $(CABAL) sandbox init && \- $(CABAL) sandbox delete && \- $(CABAL) sandbox init+cabal_build: cabal_configure+ $(_CABAL) --require-sandbox build -j -cabal_install_relocatable_executable: cabal_clean- $(CABAL) sandbox init && \- $(CABAL) --require-sandbox install --dependencies-only --force-reinstalls -j -w $(STACK_GHC_EXE) && \- $(CABAL) --require-sandbox configure --enable-relocatable -w $(STACK_GHC_EXE) && \- $(CABAL) --require-sandbox build -j && \- $(CABAL) --require-sandbox install --enable-relocatable --force-reinstalls -j -w $(STACK_GHC_EXE)+cabal_install: cabal_build+ $(_CABAL) --require-sandbox install --enable-relocatable --force-reinstalls -j -w $(_STACK_GHC_EXE)++applications_desktop:+ mkdir -p $(_APPLICATIONS_DESKTOP_DIR) && \+ cp $(_PACKAGING_LINUX_COMMON_DIR)/$(_NAME).desktop $(_APPLICATIONS_DESKTOP_DIR)/++icons_hicolor_scalable_apps:+ mkdir -p $(_ICONS_HICOLOR_SCALABLE_APPS_DIR) && \+ cp $(_PACKAGING_LINUX_COMMON_DIR)/$(_NAME)-icon.svg $(_ICONS_HICOLOR_SCALABLE_APPS_DIR)/++install: cabal_install applications_desktop icons_hicolor_scalable_apps++build_sdist:+ $(_STACK) sdist
movie-monad.cabal view
@@ -1,13 +1,13 @@ name: movie-monad-version: 0.0.4.0+version: 0.0.5.0 synopsis: Plays videos using GStreamer and GTK+.-description: A free and simple to use video player built with Haskell.+description: A free and simple to use video player made with Haskell. homepage: https://github.com/lettier/movie-monad license: BSD3 license-file: LICENSE author: Lettier maintainer: Lettier-copyright: 2017 David Lettier+copyright: (C) 2017 David Lettier category: Application , Multimedia , Multimedia Player@@ -21,10 +21,19 @@ , stack.yaml , ./src/dev/Paths_movie_monad.hs , ./src/data/gui.glade+ , ./src/data/style.css+ , ./src/data/style-3-18.css+ , ./src/data/style-3-20.css , ./src/data/movie-monad-logo.svg- , ./src/data/movie-monad-icon.png+ , ./src/data/movie-monad-icon.svg+ , ./src/data/about-icon.svg+ , ./src/data/play-icon.svg+ , ./src/data/pause-icon.svg+ , ./src/data/repeat-icon.svg+ , ./src/data/fullscreen-icon.svg , ./src/Records.hs , ./src/Constants.hs+ , ./src/Reset.hs , ./src/Window.hs , ./src/CommandLine.hs , ./src/Keyboard.hs@@ -40,13 +49,22 @@ , ./src/VideoInfo.hs , ./src/Playbin.hs , ./src/Uri.hs+ , ./src/CssStyle.hs , ./src/Utils.hs , ./src/ScreensaverAndPowerManagement.hs , ./src/c/gst-ffi.h , ./src/c/gst-ffi.c data-files: data/gui.glade+ , data/style.css+ , data/style-3-18.css+ , data/style-3-20.css , data/movie-monad-logo.svg- , data/movie-monad-icon.png+ , data/movie-monad-icon.svg+ , data/about-icon.svg+ , data/play-icon.svg+ , data/pause-icon.svg+ , data/repeat-icon.svg+ , data/fullscreen-icon.svg data-dir: ./src/ source-repository head@@ -54,8 +72,8 @@ location: https://github.com/lettier/movie-monad.git executable movie-monad- main-is: Main.hs- default-language: Haskell2010+ main-is: Main.hs+ default-language: Haskell2010 build-depends: base == 4.9.* , filepath == 1.4.* , system-fileio == 0.3.*@@ -65,18 +83,21 @@ , process == 1.4.* , MissingH == 1.4.* , network-uri == 2.6.*- , haskell-gi == 0.20.*- , haskell-gi-base == 0.20.8+ , bytestring == 0.10.*+ , haskell-gi == 0.21.*+ , haskell-gi-base == 0.21.*+ , haskell-gi-overloading == 1.0 , gi-gobject == 2.0.* , gi-glib == 2.0.* , gi-gdk == 3.0.* , gi-gdkpixbuf == 2.0.* , gi-gst == 1.0.* , gi-gstvideo == 1.0.*- , gi-gtk == 3.0.18+ , gi-gtk == 3.0.* other-modules: Paths_movie_monad , Records , Constants+ , Reset , Window , CommandLine , Keyboard@@ -92,9 +113,10 @@ , VideoInfo , Uri , Playbin+ , CssStyle , Utils , ScreensaverAndPowerManagement- hs-source-dirs: ./src/- includes: ./src/c/gst-ffi.h- c-sources: ./src/c/gst-ffi.c+ hs-source-dirs: ./src/+ includes: ./src/c/gst-ffi.h+ c-sources: ./src/c/gst-ffi.c ghc-options: -rtsopts -with-rtsopts=-N -threaded -Wall -freverse-errors
src/About.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -14,26 +14,21 @@ addAboutHandler :: R.Application -> IO () addAboutHandler- R.Application {- R.guiObjects = R.GuiObjects {- R.aboutButton = aboutButton- , R.aboutDialog = aboutDialog+ R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.aboutButton = aboutButton+ , R.aboutDialog = aboutDialog } } =- void (- GI.Gtk.onWidgetButtonReleaseEvent aboutButton (aboutButtonReleaseHandler aboutDialog)- )+ void $+ GI.Gtk.onWidgetButtonReleaseEvent+ aboutButton+ (aboutButtonReleaseHandler aboutDialog) -aboutButtonReleaseHandler ::- GI.Gtk.AboutDialog ->- GI.Gdk.EventButton ->- IO Bool-aboutButtonReleaseHandler aboutDialog _ =- void (- GI.Gtk.onDialogResponse aboutDialog (\ _ -> GI.Gtk.widgetHide aboutDialog)- ) >>- void (- GI.Gtk.dialogRun aboutDialog- ) >>+aboutButtonReleaseHandler :: GI.Gtk.AboutDialog -> GI.Gdk.EventButton -> IO Bool+aboutButtonReleaseHandler aboutDialog _ = do+ _ <- GI.Gtk.onDialogResponse aboutDialog (\ _ -> GI.Gtk.widgetHide aboutDialog)+ _ <- GI.Gtk.dialogRun aboutDialog return True
src/CommandLine.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -}
src/Constants.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -11,10 +11,13 @@ import Data.Text hideOnScreenControlsInterval :: Integral a => a-hideOnScreenControlsInterval = 5+hideOnScreenControlsInterval = 7 invalidVideoWidgetName :: Data.Text.Text invalidVideoWidgetName = "invalid-video-widget" keyboardShortcutSeekAdvanceBy :: Double keyboardShortcutSeekAdvanceBy = 1.0++windowMinimumSize :: Integral a => a+windowMinimumSize = 448
+ src/CssStyle.hs view
@@ -0,0 +1,121 @@+{-+ Movie Monad+ (C) 2017 David Lettier+ lettier.com+-}++{-# LANGUAGE OverloadedStrings #-}++module CssStyle where++import Prelude+import Control.Monad+import Data.Word+import Data.Text+import qualified Data.ByteString+import qualified GI.Gdk+import qualified GI.Gtk++import qualified Records as R++import Paths_movie_monad++cssPriority :: Word32+cssPriority =+ fromIntegral GI.Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION :: Word32++applyCss :: R.GuiObjects -> IO ()+applyCss+ guiObjects+ = do+ maybeScreen <- GI.Gdk.screenGetDefault+ provider <- GI.Gtk.cssProviderNew+ styleFile <- getDataFileName "data/style.css"+ styleFile318 <- getDataFileName "data/style-3-18.css"+ styleFile320 <- getDataFileName "data/style-3-20.css"+ isGtkVersionGte310 <- isGtkVersionGte 3 10+ isGtkVersionGte318 <- isGtkVersionGte 3 18+ isGtkVersionGte320 <- isGtkVersionGte 3 20+ case ( maybeScreen+ , isGtkVersionGte310+ , isGtkVersionGte318+ , isGtkVersionGte320+ )+ of+ (Just screen, True, False, False) -> do+ GI.Gtk.cssProviderLoadFromPath provider (Data.Text.pack styleFile)+ GI.Gtk.styleContextAddProviderForScreen+ screen+ provider+ cssPriority+ setScaleSizeForLegacyGtk guiObjects+ (Just screen, True, True, False) -> do+ styleFileContents <- Data.ByteString.readFile styleFile+ styleFileContents318 <- Data.ByteString.readFile styleFile318+ let totalStyleFileContents =+ Data.ByteString.concat+ [styleFileContents, styleFileContents318]+ GI.Gtk.cssProviderLoadFromData provider totalStyleFileContents+ GI.Gtk.styleContextAddProviderForScreen+ screen+ provider+ cssPriority+ setScaleSizeForLegacyGtk guiObjects+ (Just screen, True, True, True) -> do+ styleFileContents <- Data.ByteString.readFile styleFile+ styleFileContents318 <- Data.ByteString.readFile styleFile318+ styleFileContents320 <- Data.ByteString.readFile styleFile320+ let totalStyleFileContents =+ Data.ByteString.concat+ [styleFileContents, styleFileContents318, styleFileContents320]+ GI.Gtk.cssProviderLoadFromData provider totalStyleFileContents+ GI.Gtk.styleContextAddProviderForScreen+ screen+ provider+ cssPriority+ _ -> return ()++setScaleSizeForLegacyGtk :: R.GuiObjects -> IO ()+setScaleSizeForLegacyGtk+ R.GuiObjects+ { R.window = window+ , R.seekScale = seekScale+ }+ = do+ GI.Gtk.containerForall+ window+ (\ windowChild -> do+ windowChildName <- GI.Gtk.widgetGetName windowChild+ when (windowChildName == "GtkPopover") $ do+ maybePopover <- GI.Gtk.castTo GI.Gtk.Popover windowChild+ case maybePopover of+ Just popover ->+ GI.Gtk.containerForall+ popover+ (\ popoverChild -> do+ popoverChildName <- GI.Gtk.widgetGetName popoverChild+ when (popoverChildName == "GtkBox") $ do+ maybeBox <- GI.Gtk.castTo GI.Gtk.Box popoverChild+ case maybeBox of+ Just box ->+ GI.Gtk.containerForall+ box+ (\ boxChild -> do+ boxChildName <- GI.Gtk.widgetGetName boxChild+ when (boxChildName == "GtkScale") $ do+ maybeScale <- GI.Gtk.castTo GI.Gtk.Scale boxChild+ case maybeScale of+ Just scale -> GI.Gtk.rangeSetMinSliderSize scale 15+ _ -> return ()+ )+ _ -> return ()+ )+ _ -> return ()+ )+ GI.Gtk.rangeSetMinSliderSize seekScale 15++isGtkVersionGte :: Word32 -> Word32 -> IO Bool+isGtkVersionGte major minor = do+ major' <- GI.Gtk.getMajorVersion+ minor' <- GI.Gtk.getMinorVersion+ return (major' >= major && minor' >= minor)
src/ErrorMessage.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -}
src/FileChooser.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -9,6 +9,7 @@ module FileChooser where import Control.Monad+import Data.Maybe import Data.Int import Data.Text import Data.IORef@@ -19,8 +20,8 @@ import qualified Records as R import Constants+import Reset import Window-import PlayPause import ErrorMessage import VideoInfo import Playbin@@ -29,125 +30,108 @@ addFileChooserHandlers :: R.Application -> IO () addFileChooserHandlers- application@R.Application {- R.guiObjects = R.GuiObjects {- R.fileChooserButton = fileChooserButton- , R.fileChooserDialog = fileChooserDialog- , R.fileChooserWidget = fileChooserWidget- , R.fileChooserEntry = fileChooserEntry+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.fileChooserButton = fileChooserButton+ , R.fileChooserDialog = fileChooserDialog+ , R.fileChooserWidget = fileChooserWidget+ , R.fileChooserEntry = fileChooserEntry } }- =- void (GI.Gtk.onWidgetButtonReleaseEvent fileChooserButton (fileChooserButtonClickHandler application)) >>- void (GI.Gtk.onDialogResponse fileChooserDialog (fileChooserDialogResponseHandler application)) >>- void (GI.Gtk.onFileChooserSelectionChanged fileChooserWidget (fileChooserSelectionChangedHandler application)) >>- void (GI.Gtk.onEntryIconRelease fileChooserEntry (\ _ _ -> GI.Gtk.entrySetText fileChooserEntry ""))+ = do+ void $+ GI.Gtk.onWidgetButtonReleaseEvent fileChooserButton (fileChooserButtonClickHandler application)+ void $+ GI.Gtk.onDialogResponse fileChooserDialog (fileChooserDialogResponseHandler application)+ void $+ GI.Gtk.onFileChooserSelectionChanged fileChooserWidget (fileChooserSelectionChangedHandler application)+ void $+ GI.Gtk.onEntryIconRelease fileChooserEntry (\ _ _ -> GI.Gtk.entrySetText fileChooserEntry "") -fileChooserDialogResponseHandler ::- R.Application ->- Int32 ->- IO ()+fileChooserDialogResponseHandler :: R.Application -> Int32 -> IO () fileChooserDialogResponseHandler- R.Application {- R.guiObjects = guiObjects@R.GuiObjects {- R.videoWidget = videoWidget- , R.seekScale = seekScale- , R.playPauseButton = playPauseButton- , R.videoWidthSelectionComboBox = videoWidthSelectionComboBox- , R.fullscreenButton = fullscreenButton- , R.fileChooserEntry = fileChooserEntry- , R.fileChooserButtonLabel = fileChooserButtonLabel- , R.volumeButton = volumeButton- , R.errorMessageDialog = errorMessageDialog- , R.fileChooserDialog = fileChooserDialog- , R.playImage = playImage- , R.pauseImage = pauseImage+ application@R.Application+ { R.guiObjects =+ guiObjects@R.GuiObjects+ { R.window = window+ , R.videoWidget = videoWidget+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText+ , R.fileChooserEntry = fileChooserEntry+ , R.fileChooserButtonLabel = fileChooserButtonLabel+ , R.volumeButton = volumeButton+ , R.errorMessageDialog = errorMessageDialog+ , R.fileChooserDialog = fileChooserDialog }- , R.ioRefs = R.IORefs {- R.isWindowFullScreenRef = isWindowFullScreenRef- , R.videoInfoRef = videoInfoRef- , R.previousFileNamePathRef = previousFileNamePathRef+ , R.ioRefs =+ R.IORefs+ { R.isWindowFullScreenRef = isWindowFullScreenRef+ , R.videoInfoRef = videoInfoRef+ , R.previousFileNamePathRef = previousFileNamePathRef }- , R.playbin = playbin+ , R.playbin = playbin } responseId = do GI.Gtk.widgetHide fileChooserDialog- handleResponseType GI.Gtk.ResponseTypeOk- where- handleResponseType :: (Enum a, Ord a) => a -> IO ()- handleResponseType enum- | enumToInt32 enum == responseId = do- _ <- GI.Gst.elementSetState playbin GI.Gst.StateNull- filePathName <- GI.Gtk.entryGetText fileChooserEntry- let filePathNameStr = Data.Text.unpack filePathName- (_, fileNameEmpty) <- setFileChooserButtonLabel fileChooserButtonLabel filePathName- isWindowFullScreen <- readIORef isWindowFullScreenRef- videoWidthSelection <- getSelectedVideoWidth videoWidthSelectionComboBox- setPlaybinUriAndVolume playbin filePathNameStr volumeButton- handleFileName- fileNameEmpty- filePathNameStr- isWindowFullScreen- videoWidthSelection- | otherwise = do- filePathName <- readIORef previousFileNamePathRef- _ <- setFileChooserButtonLabel fileChooserButtonLabel filePathName- GI.Gtk.entrySetText fileChooserEntry filePathName- handleFileName ::- Bool ->- Prelude.String ->- Bool ->- Int ->- IO ()- handleFileName True _ _ _ = atomicWriteIORef videoInfoRef R.defaultVideoInfo >> resetWindow guiObjects- handleFileName- _- filePathNameStr- isWindowFullScreen- videoWidthSelection- = do- retrievedVideoInfo <- getVideoInfo videoInfoRef filePathNameStr- maybeWindowSize <- calculateWindowSize guiObjects videoWidthSelection retrievedVideoInfo- GI.Gtk.widgetSetSensitive seekScale True- if R.isSeekable retrievedVideoInfo- then GI.Gtk.widgetShow seekScale- else GI.Gtk.widgetHide seekScale- case maybeWindowSize of- Nothing -> do- resetWindow guiObjects- runErrorMessageDialog- errorMessageDialog- (Data.Text.pack $ Prelude.concat ["\"", filePathNameStr, "\" is not a video."])- Just (width, height) -> do- videoWidgetName <- GI.Gtk.widgetGetName videoWidget- if videoWidgetName == invalidVideoWidgetName- then do- resetWindow guiObjects+ if enumToInt32 GI.Gtk.ResponseTypeOk == responseId+ then do+ filePathName <- GI.Gtk.entryGetText fileChooserEntry+ maybeFileName <- setFileChooserButtonLabel fileChooserButtonLabel filePathName+ case maybeFileName of+ (Just _) -> do+ let filePathNameStr = Data.Text.unpack filePathName+ videoInfo <- fromMaybe R.defaultVideoInfo <$> getVideoInfo videoInfoRef filePathNameStr+ desiredWindowWidth <- getDesiredWindowWidth windowWidthSelectionComboBoxText window+ maybeWindowSize <- calculateWindowSize guiObjects desiredWindowWidth videoInfo+ case maybeWindowSize of+ Just (width, height) -> do+ videoWidgetName <- GI.Gtk.widgetGetName videoWidget+ if videoWidgetName == invalidVideoWidgetName+ then do+ resetApplication application+ runErrorMessageDialog+ errorMessageDialog+ "Cannot play the video. Please install the bad plugins, version 1.8 or higher, for GStreamer version 1."+ else do+ isWindowFullScreen <- readIORef isWindowFullScreenRef+ setupWindowForPlayback+ guiObjects+ (R.isSeekable videoInfo)+ isWindowFullScreen+ width+ height+ saveVideoInfo videoInfoRef videoInfo+ resetPlaybin playbin+ setPlaybinUriAndVolume playbin filePathNameStr volumeButton+ void $ GI.Gst.elementSetState playbin GI.Gst.StatePlaying+ _ -> do+ resetApplication application runErrorMessageDialog- errorMessageDialog- "Cannot play the video. Please install the bad plugins, version 1.8 or higher, for GStreamer version 1."- else do- GI.Gtk.widgetShow videoWidget- GI.Gtk.widgetShow playPauseButton- GI.Gtk.widgetShow fullscreenButton- setPlayPauseButton playPauseButton playImage pauseImage True- unless isWindowFullScreen $- setWindowSize guiObjects width height- void $ GI.Gst.elementSetState playbin GI.Gst.StatePlaying+ errorMessageDialog $+ Data.Text.pack $+ Prelude.concat ["\"", filePathNameStr, "\" is not a video."]+ _ ->+ resetApplication application+ else do+ filePathName <- readIORef previousFileNamePathRef+ fromMaybe R.defaultVideoInfo <$>+ getVideoInfo videoInfoRef (Data.Text.unpack filePathName) >>=+ saveVideoInfo videoInfoRef+ _ <- setFileChooserButtonLabel fileChooserButtonLabel filePathName+ GI.Gtk.entrySetText fileChooserEntry filePathName -fileChooserButtonClickHandler ::- R.Application ->- GI.Gdk.EventButton ->- IO Bool+fileChooserButtonClickHandler :: R.Application -> GI.Gdk.EventButton -> IO Bool fileChooserButtonClickHandler- R.Application {- R.guiObjects = R.GuiObjects {- R.fileChooserEntry = fileChooserEntry- , R.fileChooserDialog = fileChooserDialog+ R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.fileChooserEntry = fileChooserEntry+ , R.fileChooserDialog = fileChooserDialog }- , R.ioRefs = R.IORefs {- R.previousFileNamePathRef = previousFileNamePathRef+ , R.ioRefs =+ R.IORefs+ { R.previousFileNamePathRef = previousFileNamePathRef } } _@@ -157,17 +141,17 @@ _ <- GI.Gtk.dialogRun fileChooserDialog return True -fileChooserSelectionChangedHandler ::- R.Application ->- IO ()+fileChooserSelectionChangedHandler :: R.Application -> IO () fileChooserSelectionChangedHandler- R.Application {- R.guiObjects = R.GuiObjects {- R.fileChooserWidget = fileChooserWidget- , R.fileChooserEntry = fileChooserEntry+ R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.fileChooserWidget = fileChooserWidget+ , R.fileChooserEntry = fileChooserEntry }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef } } = do@@ -177,12 +161,17 @@ Just uri' -> do let uri = Network.URI.unEscapeString $ Data.Text.unpack uri' local <- isLocalFile uri- video <- R.isVideo <$> getVideoInfo videoInfoRef uri+ video <- R.isVideo . fromMaybe R.defaultVideoInfo <$> getVideoInfo videoInfoRef uri GI.Gtk.entrySetText fileChooserEntry (if local && video then Data.Text.pack uri else "") -setFileChooserButtonLabel :: GI.Gtk.Label -> Data.Text.Text -> IO (Data.Text.Text, Bool)+setFileChooserButtonLabel :: GI.Gtk.Label -> Data.Text.Text -> IO (Maybe Data.Text.Text) setFileChooserButtonLabel fileChooserButtonLabel filePathName = do let fileName = fileNameFromFilePathName filePathName let fileNameEmpty = isTextEmpty fileName- GI.Gtk.labelSetText fileChooserButtonLabel (if fileNameEmpty then "Open" else fileName)- return (fileName, fileNameEmpty)+ if fileNameEmpty+ then do+ GI.Gtk.labelSetText fileChooserButtonLabel "Open"+ return Nothing+ else do+ GI.Gtk.labelSetText fileChooserButtonLabel fileName+ return $ Just fileName
src/Fullscreen.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -31,8 +31,8 @@ R.Application { R.guiObjects = R.GuiObjects { R.window = window- , R.fileChooserButton = fileChooserButton- , R.videoWidthSelectionComboBox = videoWidthSelectionComboBox+ , R.fileChooserButton = fileChooserButton+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText } , R.ioRefs = R.IORefs { R.isWindowFullScreenRef = isWindowFullScreenRef@@ -43,11 +43,11 @@ isWindowFullScreen <- readIORef isWindowFullScreenRef if isWindowFullScreen then do- GI.Gtk.widgetShow videoWidthSelectionComboBox+ GI.Gtk.widgetShow windowWidthSelectionComboBoxText GI.Gtk.widgetShow fileChooserButton void $ GI.Gtk.windowUnfullscreen window else do- GI.Gtk.widgetHide videoWidthSelectionComboBox+ GI.Gtk.widgetHide windowWidthSelectionComboBoxText GI.Gtk.widgetHide fileChooserButton void $ GI.Gtk.windowFullscreen window return True
src/Keyboard.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -21,37 +21,38 @@ addKeyboardEventHandler :: R.Application -> IO () addKeyboardEventHandler- application@R.Application {- R.guiObjects = R.GuiObjects {- R.window = window- }+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.window = window+ } } = void $ GI.Gtk.onWidgetKeyPressEvent window $ keyboardEventHandler application -keyboardEventHandler ::- R.Application ->- GI.Gdk.EventKey ->- IO Bool+keyboardEventHandler :: R.Application -> GI.Gdk.EventKey -> IO Bool keyboardEventHandler- application@R.Application {- R.guiObjects = R.GuiObjects {- R.volumeButton = volumeButton- , R.seekScale = seekScale+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.volumeButton = volumeButton+ , R.seekScale = seekScale+ , R.repeatCheckButton = repeatCheckButton }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef- }+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ } } eventKey = do- videoInfoGathered <- readIORef videoInfoRef- let isVideo = R.isVideo videoInfoGathered- let volumeDelta = 0.05- oldVolume <- GI.Gtk.scaleButtonGetValue volumeButton- keyValue <- GI.Gdk.getEventKeyKeyval eventKey+ videoInfo <- readIORef videoInfoRef+ oldVolume <- GI.Gtk.scaleButtonGetValue volumeButton+ keyValue <- GI.Gdk.getEventKeyKeyval eventKey eventButton <- GI.Gdk.newZeroEventButton- rangeValue <- GI.Gtk.rangeGetValue seekScale+ rangeValue <- GI.Gtk.rangeGetValue seekScale+ let isVideo = R.isVideo videoInfo+ let volumeDelta = 0.05 -- Mute Toggle when (keyValue == GI.Gdk.KEY_m || keyValue == GI.Gdk.KEY_AudioMute) $ do let newVolume = if oldVolume <= 0.0 then 0.5 else 0.0@@ -59,6 +60,10 @@ -- Play/Pause Toggle when ((keyValue == GI.Gdk.KEY_space || keyValue == GI.Gdk.KEY_AudioPlay) && isVideo) $ void $ playPauseButtonClickHandler application eventButton+ -- Fullscreen Toggle+ when (keyValue == GI.Gdk.KEY_r && isVideo) $ do+ repeatVideo <- GI.Gtk.toggleButtonGetActive repeatCheckButton+ void $ GI.Gtk.toggleButtonSetActive repeatCheckButton (not repeatVideo) -- Volume Up when (keyValue == GI.Gdk.KEY_Up || keyValue == GI.Gdk.KEY_AudioRaiseVolume) $ do let newVolume = if oldVolume >= 1.0 then 1.0 else oldVolume + volumeDelta@@ -68,12 +73,12 @@ let newVolume = if oldVolume <= 0.0 then 0.0 else oldVolume - volumeDelta GI.Gtk.scaleButtonSetValue volumeButton newVolume -- Seek left- when (keyValue == GI.Gdk.KEY_Left) $+ when (keyValue == GI.Gdk.KEY_Left && isVideo) $ void $ GI.Gtk.rangeSetValue seekScale (clamp 0.0 100.0 (rangeValue - keyboardShortcutSeekAdvanceBy)) -- Seek right- when (keyValue == GI.Gdk.KEY_Right) $+ when (keyValue == GI.Gdk.KEY_Right && isVideo) $ void $ GI.Gtk.rangeSetValue seekScale (clamp 0.0 100.0 (rangeValue + keyboardShortcutSeekAdvanceBy))
src/Main.hs view
@@ -1,11 +1,13 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} -{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE+ OverloadedStrings+ , ScopedTypeVariables+#-} module Main where @@ -24,6 +26,7 @@ import qualified Records as R import Constants+import Reset import Window import CommandLine import Mouse@@ -38,6 +41,7 @@ import SubtitleSelector import Playbin import ScreensaverAndPowerManagement (disable, enable)+import CssStyle import Utils import Paths_movie_monad@@ -54,30 +58,31 @@ _ <- GI.Gtk.init Nothing gladeFile <- getDataFileName "data/gui.glade"- builder <- GI.Gtk.builderNewFromFile (pack gladeFile)+ builder <- GI.Gtk.builderNewFromFile (pack gladeFile) - window <- builderGetObject GI.Gtk.Window builder "window"- fileChooserButton <- builderGetObject GI.Gtk.Button builder "file-chooser-button"- fileChooserButtonLabel <- builderGetObject GI.Gtk.Label builder "file-chooser-button-label"- fileChooserDialog <- builderGetObject GI.Gtk.Dialog builder "file-chooser-dialog"- fileChooserEntry <- builderGetObject GI.Gtk.Entry builder "file-chooser-entry"- fileChooserWidget <- builderGetObject GI.Gtk.FileChooserWidget builder "file-chooser-widget"- fileChooserCancelButton <- builderGetObject GI.Gtk.Button builder "file-chooser-cancel-button"- fileChooserOpenButton <- builderGetObject GI.Gtk.Button builder "file-chooser-open-button"- videoWidgetBox <- builderGetObject GI.Gtk.Box builder "video-widget-box"- bottomControlsGtkBox <- builderGetObject GI.Gtk.Box builder "bottom-controls-gtk-box"- seekScale <- builderGetObject GI.Gtk.Scale builder "seek-scale"- playPauseButton <- builderGetObject GI.Gtk.Button builder "play-pause-button"- playImage <- builderGetObject GI.Gtk.Image builder "play-image"- pauseImage <- builderGetObject GI.Gtk.Image builder "pause-image"- volumeButton <- builderGetObject GI.Gtk.VolumeButton builder "volume-button"- videoWidthSelectionComboBox <- builderGetObject GI.Gtk.ComboBoxText builder "video-width-selection-combo-box"- subtitleSelectionComboBox <- builderGetObject GI.Gtk.ComboBoxText builder "subtitle-selection-combo-box"- fullscreenButton <- builderGetObject GI.Gtk.Button builder "fullscreen-button"- bufferingSpinner <- builderGetObject GI.Gtk.Spinner builder "buffering-spinner"- errorMessageDialog <- builderGetObject GI.Gtk.MessageDialog builder "error-message-dialog"- aboutButton <- builderGetObject GI.Gtk.Button builder "about-button"- aboutDialog <- builderGetObject GI.Gtk.AboutDialog builder "about-dialog"+ window <- builderGetObject GI.Gtk.Window builder "window"+ fileChooserButtonLabel <- builderGetObject GI.Gtk.Label builder "file-chooser-button-label"+ fileChooserEntry <- builderGetObject GI.Gtk.Entry builder "file-chooser-entry"+ fileChooserWidget <- builderGetObject GI.Gtk.FileChooserWidget builder "file-chooser-widget"+ videoWidgetBox <- builderGetObject GI.Gtk.Box builder "video-widget-box"+ bottomControlsGtkBox <- builderGetObject GI.Gtk.Box builder "bottom-controls-gtk-box"+ seekScale <- builderGetObject GI.Gtk.Scale builder "seek-scale"+ fileChooserButton <- builderGetObject GI.Gtk.Button builder "file-chooser-button"+ fileChooserCancelButton <- builderGetObject GI.Gtk.Button builder "file-chooser-cancel-button"+ fileChooserOpenButton <- builderGetObject GI.Gtk.Button builder "file-chooser-open-button"+ playPauseButton <- builderGetObject GI.Gtk.Button builder "play-pause-button"+ fullscreenButton <- builderGetObject GI.Gtk.Button builder "fullscreen-button"+ aboutButton <- builderGetObject GI.Gtk.Button builder "about-button"+ repeatCheckButton <- builderGetObject GI.Gtk.CheckButton builder "repeat-check-button"+ volumeButton <- builderGetObject GI.Gtk.VolumeButton builder "volume-button"+ playImage <- builderGetObject GI.Gtk.Image builder "play-image"+ pauseImage <- builderGetObject GI.Gtk.Image builder "pause-image"+ windowWidthSelectionComboBoxText <- builderGetObject GI.Gtk.ComboBoxText builder "window-width-selection-combo-box-text"+ subtitleSelectionComboBoxText <- builderGetObject GI.Gtk.ComboBoxText builder "subtitle-selection-combo-box-text"+ bufferingSpinner <- builderGetObject GI.Gtk.Spinner builder "buffering-spinner"+ fileChooserDialog <- builderGetObject GI.Gtk.Dialog builder "file-chooser-dialog"+ errorMessageDialog <- builderGetObject GI.Gtk.MessageDialog builder "error-message-dialog"+ aboutDialog <- builderGetObject GI.Gtk.AboutDialog builder "about-dialog" logoFile <- getDataFileName "data/movie-monad-logo.svg" logo <- GI.GdkPixbuf.pixbufNewFromFile (pack logoFile)@@ -87,17 +92,18 @@ GI.Gtk.dialogAddActionWidget fileChooserDialog fileChooserCancelButton (enumToInt32 GI.Gtk.ResponseTypeCancel) GI.Gtk.dialogAddActionWidget fileChooserDialog fileChooserOpenButton (enumToInt32 GI.Gtk.ResponseTypeOk) - isWindowFullScreenRef <- newIORef False- mouseMovedLastRef <- newIORef 0+ isWindowFullScreenRef <- newIORef False+ mouseMovedLastRef <- newIORef 0 previousFileNamePathRef <- newIORef ""- videoInfoRef <- newIORef R.defaultVideoInfo+ videoInfoRef <- newIORef R.defaultVideoInfo - let ioRefs = R.IORefs {- R.isWindowFullScreenRef = isWindowFullScreenRef- , R.mouseMovedLastRef = mouseMovedLastRef- , R.previousFileNamePathRef = previousFileNamePathRef- , R.videoInfoRef = videoInfoRef- }+ let ioRefs =+ R.IORefs+ { R.isWindowFullScreenRef = isWindowFullScreenRef+ , R.mouseMovedLastRef = mouseMovedLastRef+ , R.previousFileNamePathRef = previousFileNamePathRef+ , R.videoInfoRef = videoInfoRef+ } playbin <- fromJust <$> GI.Gst.elementFactoryMake "playbin" (Just "MultimediaPlayerPlaybin") maybeGtkSink <- GI.Gst.elementFactoryMake "gtksink" (Just "MultimediaPlayerGtkSink")@@ -114,73 +120,82 @@ Data.GI.Base.Properties.setObjectPropertyObject playbin "video-sink" maybeGtkSink Data.GI.Base.Properties.setObjectPropertyBool playbin "force-aspect-ratio" True GI.Gtk.boxPackStart videoWidgetBox videoWidget True True 0- GI.Gtk.widgetSetHexpand videoWidget True- GI.Gtk.widgetSetVexpand videoWidget True+ GI.Gtk.widgetSetHexpand videoWidget True+ GI.Gtk.widgetSetVexpand videoWidget True GI.Gtk.widgetSetSensitive videoWidget True turnOffSubtitles playbin playbinBus <- GI.Gst.elementGetBus playbin - let guiObjects = R.GuiObjects {- R.window = window- , R.fileChooserButton = fileChooserButton- , R.fileChooserButtonLabel = fileChooserButtonLabel- , R.fileChooserDialog = fileChooserDialog- , R.fileChooserEntry = fileChooserEntry- , R.fileChooserWidget = fileChooserWidget- , R.fileChooserCancelButton = fileChooserCancelButton- , R.fileChooserOpenButton = fileChooserOpenButton- , R.videoWidget = videoWidget- , R.bottomControlsGtkBox = bottomControlsGtkBox- , R.seekScale = seekScale- , R.playPauseButton = playPauseButton- , R.playImage = playImage- , R.pauseImage = pauseImage- , R.volumeButton = volumeButton- , R.videoWidthSelectionComboBox = videoWidthSelectionComboBox- , R.subtitleSelectionComboBox = subtitleSelectionComboBox- , R.fullscreenButton = fullscreenButton- , R.bufferingSpinner = bufferingSpinner- , R.errorMessageDialog = errorMessageDialog- , R.aboutButton = aboutButton- , R.aboutDialog = aboutDialog- }+ let guiObjects =+ R.GuiObjects+ { R.window = window+ , R.fileChooserButtonLabel = fileChooserButtonLabel+ , R.fileChooserEntry = fileChooserEntry+ , R.fileChooserWidget = fileChooserWidget+ , R.fileChooserCancelButton = fileChooserCancelButton+ , R.fileChooserOpenButton = fileChooserOpenButton+ , R.videoWidget = videoWidget+ , R.bottomControlsGtkBox = bottomControlsGtkBox+ , R.seekScale = seekScale+ , R.fileChooserButton = fileChooserButton+ , R.playPauseButton = playPauseButton+ , R.fullscreenButton = fullscreenButton+ , R.volumeButton = volumeButton+ , R.repeatCheckButton = repeatCheckButton+ , R.playImage = playImage+ , R.pauseImage = pauseImage+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText+ , R.subtitleSelectionComboBoxText = subtitleSelectionComboBoxText+ , R.bufferingSpinner = bufferingSpinner+ , R.errorMessageDialog = errorMessageDialog+ , R.fileChooserDialog = fileChooserDialog+ , R.aboutButton = aboutButton+ , R.aboutDialog = aboutDialog+ } - let application = R.Application {- R.guiObjects = guiObjects- , R.ioRefs = ioRefs- , R.playbin = playbin- , R.playbinBus = playbinBus- }+ let application =+ R.Application+ { R.guiObjects = guiObjects+ , R.ioRefs = ioRefs+ , R.playbin = playbin+ , R.playbinBus = playbinBus+ } - addWindowHandlers application [playVideoFromCommandLineIfNeeded]- addPlaybinHandlers application- addFileChooserHandlers application- addPlayPauseButtonClickHandler application- addSeekHandlers application- addVideoSizeSelectorHandler application- addSubtitleSelectorHandler application+ addWindowHandlers application [playVideoFromCommandLineIfNeeded]+ addPlaybinHandlers application+ addFileChooserHandlers application+ addPlayPauseButtonClickHandler application+ addSeekHandlers application+ addVideoSizeSelectorHandlers application+ addSubtitleSelectorHandler application addFullscreenButtonReleaseHandler application- addMouseMoveHandlers application [fillWindowWithVideo]- addAboutHandler application- addKeyboardEventHandler application- addErrorMessageDialogHandler application+ addMouseMoveHandlers application [fillWindowWithVideo]+ addAboutHandler application+ addKeyboardEventHandler application+ addErrorMessageDialogHandler application let operatingSystem = System.Info.os screenAndPowerManagementActions <- ScreensaverAndPowerManagement.disable operatingSystem + applyCss guiObjects+ GI.Gtk.widgetShowAll window+ GI.Gtk.main + resetPlaybin playbin+ ScreensaverAndPowerManagement.enable operatingSystem screenAndPowerManagementActions -builderGetObject ::- (GI.GObject.GObject b, GI.Gtk.IsBuilder a) =>- (Data.GI.Base.ManagedPtr b -> b) ->- a ->- Prelude.String ->- IO b+builderGetObject+ :: (GI.GObject.GObject b, GI.Gtk.IsBuilder a)+ => (Data.GI.Base.ManagedPtr b -> b)+ -> a+ -> Prelude.String+ -> IO b builderGetObject objectTypeClass builder objectId = fromJust <$> GI.Gtk.builderGetObject builder (pack objectId) >>= GI.Gtk.unsafeCastTo objectTypeClass+
src/Mouse.hs view
@@ -1,8 +1,9 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -}+{-# LANGUAGE OverloadedStrings #-} module Mouse where @@ -18,43 +19,51 @@ addMouseMoveHandlers :: R.Application -> [R.Application -> IO ()] -> IO () addMouseMoveHandlers- application@R.Application {- R.guiObjects = R.GuiObjects {- R.videoWidget = videoWidget- , R.seekScale = seekScale+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.videoWidget = videoWidget+ , R.seekScale = seekScale } } onMouseMoveCallbacks- =- void (GI.Gtk.onWidgetMotionNotifyEvent videoWidget mouseMoveHandler')- >> void (GI.Gtk.onWidgetMotionNotifyEvent seekScale mouseMoveHandler')+ = do+ void $ GI.Gtk.onWidgetMotionNotifyEvent videoWidget mouseMoveHandler'+ void $ GI.Gtk.onWidgetMotionNotifyEvent seekScale mouseMoveHandler' where mouseMoveHandler' :: GI.Gdk.EventMotion -> IO Bool mouseMoveHandler' = mouseMoveHandler application onMouseMoveCallbacks mouseMoveHandler- :: R.Application- -> [R.Application -> IO ()]- -> GI.Gdk.EventMotion- -> IO Bool+ :: R.Application+ -> [R.Application -> IO ()]+ -> GI.Gdk.EventMotion+ -> IO Bool mouseMoveHandler- application@R.Application {- R.guiObjects = R.GuiObjects {- R.window = window- , R.fileChooserButton = fileChooserButton- , R.bottomControlsGtkBox = bottomControlsGtkBox+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.window = window+ , R.fileChooserButton = fileChooserButton+ , R.bottomControlsGtkBox = bottomControlsGtkBox }- , R.ioRefs = R.IORefs {- R.isWindowFullScreenRef = isWindowFullScreenRef- , R.mouseMovedLastRef = mouseMovedLastRef- }+ , R.ioRefs =+ R.IORefs+ { R.isWindowFullScreenRef = isWindowFullScreenRef+ , R.mouseMovedLastRef = mouseMovedLastRef+ , R.videoInfoRef = videoInfoRef+ } } onMouseMoveCallbacks _ = do isWindowFullScreen <- readIORef isWindowFullScreenRef+ videoInfo <- readIORef videoInfoRef unless isWindowFullScreen $ GI.Gtk.widgetShow fileChooserButton- GI.Gtk.widgetShow bottomControlsGtkBox+ when (R.isVideo videoInfo) $ do+ GI.Gtk.widgetShow bottomControlsGtkBox+ styleContext <- GI.Gtk.widgetGetStyleContext bottomControlsGtkBox+ GI.Gtk.styleContextAddClass styleContext "movie-monad-fade-in" setCursor window Nothing timeNow <- getPOSIXTime atomicWriteIORef mouseMovedLastRef (round timeNow)
src/PlayPause.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -18,26 +18,31 @@ addPlayPauseButtonClickHandler :: R.Application -> IO () addPlayPauseButtonClickHandler- application@R.Application {- R.guiObjects = R.GuiObjects {- R.playPauseButton = playPauseButton+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.playPauseButton = playPauseButton } } =- void $ GI.Gtk.onWidgetButtonReleaseEvent playPauseButton (playPauseButtonClickHandler application)+ void $+ GI.Gtk.onWidgetButtonReleaseEvent+ playPauseButton $+ playPauseButtonClickHandler application playPauseButtonClickHandler :: R.Application -> GI.Gdk.EventButton -> IO Bool playPauseButtonClickHandler- R.Application {- R.guiObjects = R.GuiObjects {- R.playPauseButton = playPauseButton- , R.playImage = playImage- , R.pauseImage = pauseImage+ R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.playPauseButton = playPauseButton+ , R.playImage = playImage+ , R.pauseImage = pauseImage }- , R.playbin = playbin+ , R.playbin = playbin } _ = do@@ -51,22 +56,20 @@ void $ GI.Gst.elementSetState playbin GI.Gst.StatePlaying return False -setPlayPauseButton ::- GI.Gtk.Button ->- GI.Gtk.Image ->- GI.Gtk.Image ->- Bool ->- IO ()+setPlayPauseButton+ :: GI.Gtk.Button+ -> GI.Gtk.Image+ -> GI.Gtk.Image+ -> Bool+ -> IO () setPlayPauseButton playPauseButton _ pauseImage True = do GI.Gtk.buttonSetImage playPauseButton (Just pauseImage)- GI.Gtk.widgetSetTooltipText playPauseButton (Just "Click to pause")+ GI.Gtk.widgetSetTooltipText playPauseButton (Just "Click to Pause") setPlayPauseButton playPauseButton playImage _ False = do GI.Gtk.buttonSetImage playPauseButton (Just playImage)- GI.Gtk.widgetSetTooltipText playPauseButton (Just "Click to play")+ GI.Gtk.widgetSetTooltipText playPauseButton (Just "Click to Play") -isPlayPauseButtonPlaying ::- GI.Gtk.Button ->- IO Bool+isPlayPauseButtonPlaying :: GI.Gtk.Button -> IO Bool isPlayPauseButtonPlaying playPauseButton = GI.Gtk.buttonGetImage playPauseButton >>= getImage >>= getName >>= getMatch where@@ -75,7 +78,7 @@ getImage (Just widget) = GI.Gtk.castTo GI.Gtk.Image widget getName :: Maybe GI.Gtk.Image -> IO (Maybe Text) getName Nothing = return Nothing- getName (Just image) = GI.Gtk.getImageStock image+ getName (Just image) = Just . Data.Text.strip . Data.Text.toLower <$> GI.Gtk.widgetGetName image getMatch :: Maybe Text -> IO Bool getMatch Nothing = return False- getMatch (Just text) = return ("gtk-media-pause" == text)+ getMatch (Just text) = return ("pause-image" == text)
src/Playbin.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -14,6 +14,7 @@ import Data.Bits import Data.Text import Data.Maybe+import Data.Int import Data.GI.Base.Properties import Data.GI.Base.ManagedPtr import qualified GI.GLib@@ -21,7 +22,7 @@ import qualified GI.Gst import qualified Records as R-import Window+import Reset import PlayPause import ErrorMessage import Uri@@ -31,69 +32,72 @@ addPlaybinHandlers :: R.Application -> IO () addPlaybinHandlers- R.Application {- R.guiObjects = guiObjects@R.GuiObjects {- R.volumeButton = volumeButton+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.volumeButton = volumeButton+ , R.repeatCheckButton = repeatCheckButton }- , R.playbin = playbin- , R.playbinBus = playbinBus+ , R.playbin = playbin+ , R.playbinBus = playbinBus }- =- void(- GI.Gst.busAddWatch playbinBus GI.GLib.PRIORITY_DEFAULT (- pipelineBusMessageHandler- guiObjects- playbin- )- ) >>- void (- GI.Gtk.onScaleButtonValueChanged volumeButton (volumeButtonValueChangedHandler playbin)- )+ = do+ void $+ GI.Gst.busAddWatch playbinBus GI.GLib.PRIORITY_DEFAULT $+ pipelineBusMessageHandler application+ void $+ GI.Gtk.onScaleButtonValueChanged+ volumeButton+ (setPlaybinVolume playbin)+ void $+ GI.GLib.timeoutAddSeconds GI.GLib.PRIORITY_DEFAULT 1 $ do+ rewindPlaybackIfVideoEndedAndRepeat+ playbin+ repeatCheckButton+ return True -pipelineBusMessageHandler ::- R.GuiObjects ->- GI.Gst.Element ->- GI.Gst.Bus ->- GI.Gst.Message ->- IO Bool pipelineBusMessageHandler- guiObjects@R.GuiObjects {- R.seekScale = seekScale- , R.fileChooserEntry = fileChooserEntry- , R.fileChooserButtonLabel = fileChooserButtonLabel- , R.volumeButton = volumeButton- , R.errorMessageDialog = errorMessageDialog- , R.bufferingSpinner = bufferingSpinner- , R.playPauseButton = playPauseButton- , R.subtitleSelectionComboBox = subtitleSelectionComboBox+ :: R.Application+ -> GI.Gst.Bus+ -> GI.Gst.Message+ -> IO Bool+pipelineBusMessageHandler+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.seekScale = seekScale+ , R.fileChooserEntry = fileChooserEntry+ , R.fileChooserButtonLabel = fileChooserButtonLabel+ , R.errorMessageDialog = errorMessageDialog+ , R.bufferingSpinner = bufferingSpinner+ , R.playPauseButton = playPauseButton+ , R.repeatCheckButton = repeatCheckButton+ , R.subtitleSelectionComboBoxText = subtitleSelectionComboBoxText+ }+ , R.playbin = playbin }- playbin _ message = do messageTypes <- GI.Gst.getMessageType message- let messageType = case messageTypes of- [] -> GI.Gst.MessageTypeUnknown- (msg:_) -> msg+ let messageType =+ case messageTypes of+ [] -> GI.Gst.MessageTypeUnknown+ (msg:_) -> msg entryText <- GI.Gtk.entryGetText fileChooserEntry labelText <- GI.Gtk.labelGetText fileChooserButtonLabel- when (- messageType == GI.Gst.MessageTypeError && (- (not . Data.Text.null) entryText ||- labelText /= "Open"- )+ when+ ( messageType == GI.Gst.MessageTypeError+ && ((not . Data.Text.null) entryText || labelText /= "Open") ) $ do (gError, text) <- GI.Gst.messageParseError message gErrorText <- GI.Gst.gerrorMessage gError putStr ((Data.Text.unpack . Data.Text.unlines) [text, gErrorText])- GI.Gtk.entrySetText fileChooserEntry ""- GI.Gtk.labelSetText fileChooserButtonLabel "Open"- _ <- GI.Gst.elementSetState playbin GI.Gst.StateNull- setPlaybinUriAndVolume playbin "" volumeButton- resetWindow guiObjects+ resetApplication application runErrorMessageDialog- errorMessageDialog- (Data.Text.concat ["There was a problem trying to play the video \"", entryText, "\"."])+ errorMessageDialog $+ Data.Text.concat+ ["There was a problem trying to play the video \"", entryText, "\"."] when (messageType == GI.Gst.MessageTypeBuffering) $ do percent <- GI.Gst.messageParseBuffering message isPlaying <- isPlayPauseButtonPlaying playPauseButton@@ -102,7 +106,9 @@ GI.Gtk.widgetHide bufferingSpinner GI.Gtk.setSpinnerActive bufferingSpinner False GI.Gtk.widgetSetSensitive seekScale True- when isPlaying $ void $ GI.Gst.elementSetState playbin GI.Gst.StatePlaying+ when isPlaying $+ void $+ GI.Gst.elementSetState playbin GI.Gst.StatePlaying else do GI.Gtk.widgetShow bufferingSpinner GI.Gtk.setSpinnerActive bufferingSpinner True@@ -112,41 +118,72 @@ when (messageType == GI.Gst.MessageTypeStreamStart) $ do turnOffSubtitles playbin nText <- getTextStreamCount playbin- GI.Gtk.comboBoxTextRemoveAll subtitleSelectionComboBox+ GI.Gtk.comboBoxTextRemoveAll subtitleSelectionComboBoxText GI.Gtk.comboBoxTextAppend- subtitleSelectionComboBox+ subtitleSelectionComboBoxText (Just "-1") "None"- _ <- GI.Gtk.comboBoxSetActiveId subtitleSelectionComboBox (Just "-1")- GI.Gtk.widgetHide subtitleSelectionComboBox+ _ <- GI.Gtk.comboBoxSetActiveId subtitleSelectionComboBoxText (Just "-1")+ GI.Gtk.widgetHide subtitleSelectionComboBoxText when (nText > 0) $ mapM_ (\ i -> do (_, maybeCode) <- getTextTagLanguageNameAndCode playbin i case maybeCode of Nothing -> return () Just code -> do- GI.Gtk.widgetShow subtitleSelectionComboBox+ GI.Gtk.widgetShow subtitleSelectionComboBoxText GI.Gtk.comboBoxTextAppend- subtitleSelectionComboBox+ subtitleSelectionComboBoxText (Just (Data.Text.pack (show i))) code ) [0..(nText-1)]+ when (messageType == GI.Gst.MessageTypeEos) $+ rewindPlaybackIfRepeat playbin repeatCheckButton return True -volumeButtonValueChangedHandler ::- GI.Gst.Element ->- Double ->- IO ()-volumeButtonValueChangedHandler playbin volume =+rewindPlaybackIfVideoEndedAndRepeat :: GI.Gst.Element -> GI.Gtk.CheckButton -> IO ()+rewindPlaybackIfVideoEndedAndRepeat playbin repeatCheckButton = do+ maybeDurationAndPosition <- queryPlaybinForDurationAndPosition playbin+ case maybeDurationAndPosition of+ (Just (duration, position)) ->+ -- Position may never be >= duration even though an EOS event has occurred.+ -- Allow for a half second tolerance.+ when (position >= duration || ((duration - position) < 50000000)) $+ rewindPlaybackIfRepeat playbin repeatCheckButton+ _ -> return ()++rewindPlaybackIfRepeat :: GI.Gst.Element -> GI.Gtk.CheckButton -> IO ()+rewindPlaybackIfRepeat playbin repeatCheckButton = do+ repeatVideo <- GI.Gtk.toggleButtonGetActive repeatCheckButton+ when repeatVideo $+ void $+ GI.Gst.elementSeekSimple playbin GI.Gst.FormatTime [ GI.Gst.SeekFlagsFlush ] 0++setPlaybinVolume :: GI.Gst.Element -> Double -> IO ()+setPlaybinVolume playbin volume = void $ Data.GI.Base.Properties.setObjectPropertyDouble playbin "volume" volume +setPlaybinUri :: GI.Gst.Element -> Maybe String -> IO ()+setPlaybinUri playbin (Just uri) =+ void $ Data.GI.Base.Properties.setObjectPropertyString playbin "uri" (Just $ pack uri)+setPlaybinUri playbin Nothing =+ void $ Data.GI.Base.Properties.setObjectPropertyString playbin "uri" (Just "")+ setPlaybinUriAndVolume :: GI.Gst.Element -> Prelude.String -> GI.Gtk.VolumeButton -> IO () setPlaybinUriAndVolume playbin fileName volumeButton = do- uri <- addUriSchemeIfNone fileName+ uri <- addUriSchemeIfNone fileName volume <- GI.Gtk.scaleButtonGetValue volumeButton- Data.GI.Base.Properties.setObjectPropertyDouble playbin "volume" volume- Data.GI.Base.Properties.setObjectPropertyString playbin "uri" (Just $ pack uri)+ setPlaybinVolume playbin volume+ setPlaybinUri playbin (Just uri) +queryPlaybinForDurationAndPosition :: GI.Gst.Element -> IO (Maybe (Int64, Int64))+queryPlaybinForDurationAndPosition playbin = do+ (couldQueryDuration, duration) <- GI.Gst.elementQueryDuration playbin GI.Gst.FormatTime+ (couldQueryPosition, position) <- GI.Gst.elementQueryPosition playbin GI.Gst.FormatTime+ if couldQueryDuration && couldQueryPosition && duration > 0 && position >= 0+ then return (Just (duration, position))+ else return Nothing+ getTextTagLanguageNameAndCode :: GI.Gst.Element -> Int -> IO (Maybe Text, Maybe Text) getTextTagLanguageNameAndCode playbin streamId = do nText <- getTextStreamCount playbin@@ -160,15 +197,17 @@ else do tagList <- wrapBoxed GI.Gst.TagList tagListPtr tagListAsString <- fmap (fromMaybe "") (GI.Gst.tagListToString tagList)- (successName, name) <- if "language-name" `Data.Text.isInfixOf` tagListAsString- then GI.Gst.tagListGetString tagList "language-name"- else return (False, "")- (successCode, code) <- if "language-code" `Data.Text.isInfixOf` tagListAsString- then GI.Gst.tagListGetString tagList "language-code"- else return (False, "")- return (- if successName then Just name else Nothing- , if successCode then Just code else Nothing+ (successName, name) <-+ if "language-name" `Data.Text.isInfixOf` tagListAsString+ then GI.Gst.tagListGetString tagList "language-name"+ else return (False, "")+ (successCode, code) <-+ if "language-code" `Data.Text.isInfixOf` tagListAsString+ then GI.Gst.tagListGetString tagList "language-code"+ else return (False, "")+ return+ ( if successName then Just name else Nothing+ , if successCode then Just code else Nothing ) else return (Nothing, Nothing) @@ -198,13 +237,17 @@ getTextStreamCount :: GI.Gst.Element -> IO Int getTextStreamCount playbin =- Data.GI.Base.Properties.getObjectPropertyInt playbin "n-text"- >>= \ x -> return (if x < 0 then 0 else fromIntegral x :: Int)+ Data.GI.Base.Properties.getObjectPropertyInt playbin "n-text" >>=+ \ x -> return (if x < 0 then 0 else fromIntegral x :: Int) getCurrentTextStreamId :: GI.Gst.Element -> IO Int getCurrentTextStreamId playbin =- Data.GI.Base.Properties.getObjectPropertyInt playbin "current-text" >>= \ x -> return (fromIntegral x :: Int)+ Data.GI.Base.Properties.getObjectPropertyInt playbin "current-text" >>=+ \ x -> return (fromIntegral x :: Int) setCurrentTextStreamId :: GI.Gst.Element -> Int -> IO () setCurrentTextStreamId playbin streamId =- Data.GI.Base.Properties.setObjectPropertyInt playbin "current-text" (fromIntegral streamId :: CInt)+ Data.GI.Base.Properties.setObjectPropertyInt+ playbin+ "current-text"+ (fromIntegral streamId :: CInt)
src/Records.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -11,67 +11,74 @@ import qualified GI.Gtk import qualified GI.Gst -data VideoInfo = VideoInfo {- uri :: Prelude.String+data Application =+ Application+ { guiObjects :: GuiObjects+ , ioRefs :: IORefs+ , playbin :: GI.Gst.Element+ , playbinBus :: GI.Gst.Bus+ }++data GuiObjects =+ GuiObjects+ { window :: GI.Gtk.Window+ , fileChooserButtonLabel :: GI.Gtk.Label+ , fileChooserDialog :: GI.Gtk.Dialog+ , fileChooserEntry :: GI.Gtk.Entry+ , fileChooserWidget :: GI.Gtk.FileChooserWidget+ , videoWidget :: GI.Gtk.Widget+ , bottomControlsGtkBox :: GI.Gtk.Box+ , seekScale :: GI.Gtk.Scale+ , fileChooserButton :: GI.Gtk.Button+ , playPauseButton :: GI.Gtk.Button+ , fullscreenButton :: GI.Gtk.Button+ , fileChooserCancelButton :: GI.Gtk.Button+ , fileChooserOpenButton :: GI.Gtk.Button+ , aboutButton :: GI.Gtk.Button+ , repeatCheckButton :: GI.Gtk.CheckButton+ , volumeButton :: GI.Gtk.VolumeButton+ , playImage :: GI.Gtk.Image+ , pauseImage :: GI.Gtk.Image+ , windowWidthSelectionComboBoxText :: GI.Gtk.ComboBoxText+ , subtitleSelectionComboBoxText :: GI.Gtk.ComboBoxText+ , bufferingSpinner :: GI.Gtk.Spinner+ , errorMessageDialog :: GI.Gtk.MessageDialog+ , aboutDialog :: GI.Gtk.AboutDialog+ }++data IORefs =+ IORefs+ { isWindowFullScreenRef :: IORef Bool+ , mouseMovedLastRef :: IORef Integer+ , previousFileNamePathRef :: IORef Data.Text.Text+ , videoInfoRef :: IORef VideoInfo+ }++data VideoInfo =+ VideoInfo+ { uri :: Prelude.String , isLocalFile :: Bool , isVideo :: Bool , isSeekable :: Bool , videoWidth :: Int , videoHeight :: Int- }+ } +data ScreensaverAndPowerManagementActions =+ ScreensaverAndPowerManagementActions+ { disabledPowerManagement :: Bool+ , disabledXScreensaver :: Bool+ , disabledCinnamonScreensaver :: Bool+ , disabledGnomeScreensaver :: Bool+ }+ defaultVideoInfo :: VideoInfo-defaultVideoInfo = VideoInfo {- uri = ""+defaultVideoInfo =+ VideoInfo+ { uri = "" , isLocalFile = False , isVideo = False , isSeekable = False , videoWidth = 800 , videoHeight = 600- }--data GuiObjects = GuiObjects {- window :: GI.Gtk.Window- , fileChooserButton :: GI.Gtk.Button- , fileChooserButtonLabel :: GI.Gtk.Label- , fileChooserDialog :: GI.Gtk.Dialog- , fileChooserEntry :: GI.Gtk.Entry- , fileChooserWidget :: GI.Gtk.FileChooserWidget- , fileChooserCancelButton :: GI.Gtk.Button- , fileChooserOpenButton :: GI.Gtk.Button- , videoWidget :: GI.Gtk.Widget- , bottomControlsGtkBox :: GI.Gtk.Box- , seekScale :: GI.Gtk.Scale- , playPauseButton :: GI.Gtk.Button- , playImage :: GI.Gtk.Image- , pauseImage :: GI.Gtk.Image- , volumeButton :: GI.Gtk.VolumeButton- , videoWidthSelectionComboBox :: GI.Gtk.ComboBoxText- , subtitleSelectionComboBox :: GI.Gtk.ComboBoxText- , fullscreenButton :: GI.Gtk.Button- , bufferingSpinner :: GI.Gtk.Spinner- , errorMessageDialog :: GI.Gtk.MessageDialog- , aboutButton :: GI.Gtk.Button- , aboutDialog :: GI.Gtk.AboutDialog- }--data IORefs = IORefs {- isWindowFullScreenRef :: IORef Bool- , mouseMovedLastRef :: IORef Integer- , previousFileNamePathRef :: IORef Data.Text.Text- , videoInfoRef :: IORef VideoInfo- }--data ScreensaverAndPowerManagementActions = ScreensaverAndPowerManagementActions {- disabledPowerManagement :: Bool- , disabledXScreensaver :: Bool- , disabledCinnamonScreensaver :: Bool- , disabledGnomeScreensaver :: Bool- }--data Application = Application {- guiObjects :: GuiObjects- , ioRefs :: IORefs- , playbin :: GI.Gst.Element- , playbinBus :: GI.Gst.Bus- }+ }
+ src/Reset.hs view
@@ -0,0 +1,97 @@+{-+ Movie Monad+ (C) 2017 David Lettier+ lettier.com+-}++{-# LANGUAGE OverloadedStrings #-}++module Reset where++import Control.Monad+import Data.Int+import Data.IORef+import Data.GI.Base.Properties+import qualified GI.Gtk+import qualified GI.Gst++import qualified Records as R+import Constants+import Mouse+import VideoInfo+import PlayPause+import Utils++resetApplication :: R.Application -> IO ()+resetApplication+ R.Application+ { R.guiObjects = guiObjects+ , R.playbin = playbin+ , R.ioRefs = ioRefs+ }+ = do+ resetIoRefs ioRefs+ resetPlaybin playbin+ resetGuiObjects guiObjects++resetIoRefs :: R.IORefs -> IO ()+resetIoRefs+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ , R.previousFileNamePathRef = previousFileNamePathRef+ }+ = do+ void $ resetVideoInfo videoInfoRef+ atomicWriteIORef previousFileNamePathRef ""++resetVideoInfo :: IORef R.VideoInfo -> IO R.VideoInfo+resetVideoInfo videoInfoRef = do+ let videoInfo = R.defaultVideoInfo+ saveVideoInfo videoInfoRef videoInfo+ return videoInfo++resetPlaybin :: GI.Gst.Element -> IO ()+resetPlaybin playbin = do+ void $ GI.Gst.elementSetState playbin GI.Gst.StateNull+ void $ Data.GI.Base.Properties.setObjectPropertyDouble playbin "volume" 0.0+ void $ Data.GI.Base.Properties.setObjectPropertyString playbin "uri" (Just "")++resetGuiObjects :: R.GuiObjects -> IO ()+resetGuiObjects+ R.GuiObjects+ { R.window = window+ , R.fileChooserButton = fileChooserButton+ , R.fileChooserEntry = fileChooserEntry+ , R.fileChooserButtonLabel = fileChooserButtonLabel+ , R.videoWidget = videoWidget+ , R.seekScale = seekScale+ , R.playPauseButton = playPauseButton+ , R.repeatCheckButton = repeatCheckButton+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText+ , R.subtitleSelectionComboBoxText = subtitleSelectionComboBoxText+ , R.fullscreenButton = fullscreenButton+ , R.playImage = playImage+ , R.pauseImage = pauseImage+ , R.bottomControlsGtkBox = bottomControlsGtkBox+ }+ = do+ desiredWindowWidth <- getDesiredWindowWidth windowWidthSelectionComboBoxText window+ styleContext <- GI.Gtk.widgetGetStyleContext bottomControlsGtkBox+ GI.Gtk.widgetSetSizeRequest window windowMinimumSize (-1)+ GI.Gtk.windowUnfullscreen window+ GI.Gtk.widgetHide videoWidget+ GI.Gtk.widgetHide bottomControlsGtkBox+ GI.Gtk.widgetHide seekScale+ GI.Gtk.widgetHide playPauseButton+ GI.Gtk.widgetHide repeatCheckButton+ GI.Gtk.widgetHide fullscreenButton+ GI.Gtk.widgetHide subtitleSelectionComboBoxText+ GI.Gtk.widgetShow fileChooserButton+ GI.Gtk.widgetShow windowWidthSelectionComboBoxText+ GI.Gtk.setToggleButtonActive repeatCheckButton False+ GI.Gtk.entrySetText fileChooserEntry ""+ GI.Gtk.labelSetText fileChooserButtonLabel "Open"+ GI.Gtk.windowResize window (fromIntegral desiredWindowWidth :: Int32) 1+ GI.Gtk.styleContextRemoveClass styleContext "movie-monad-fade-in"+ setCursor window Nothing+ setPlayPauseButton playPauseButton playImage pauseImage False
src/ScreensaverAndPowerManagement.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -}
src/Seek.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -8,7 +8,6 @@ import Control.Monad import Data.IORef-import Data.Int import Data.GI.Base.Signals import GI.GLib import GI.GObject@@ -16,73 +15,87 @@ import qualified GI.Gst import qualified Records as R+import Playbin+import Utils addSeekHandlers :: R.Application -> IO () addSeekHandlers- R.Application {- R.guiObjects = R.GuiObjects {- R.seekScale = seekScale+ R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.seekScale = seekScale }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef- }- , R.playbin = playbin+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ }+ , R.playbin = playbin } = do- seekScaleHandlerId <- GI.Gtk.onRangeValueChanged seekScale (+ seekScaleHandlerId <-+ GI.Gtk.onRangeValueChanged seekScale $ onRangeValueChanged playbin seekScale videoInfoRef- )- void (- GI.GLib.timeoutAdd GI.GLib.PRIORITY_DEFAULT 41 (- updateSeekScale- playbin- seekScale- seekScaleHandlerId- )- )+ void $+ GI.GLib.timeoutAdd GI.GLib.PRIORITY_DEFAULT 41 $+ updateSeekScale+ playbin+ seekScale+ seekScaleHandlerId -onRangeValueChanged ::- GI.Gst.Element ->- GI.Gtk.Scale ->- IORef R.VideoInfo ->- IO ()+onRangeValueChanged :: GI.Gst.Element -> GI.Gtk.Scale -> IORef R.VideoInfo -> IO () onRangeValueChanged playbin seekScale videoInfoRef = do- (couldQueryDuration, duration) <- GI.Gst.elementQueryDuration playbin GI.Gst.FormatTime- when couldQueryDuration $ do- percentage' <- GI.Gtk.rangeGetValue seekScale- let percentage = percentage' / 100.0- let position = fromIntegral (round ((fromIntegral duration :: Double) * percentage) :: Int) :: Int64- void $ GI.Gst.elementSeekSimple playbin GI.Gst.FormatTime [ GI.Gst.SeekFlagsFlush ] position- videoInfoGathered <- readIORef videoInfoRef- -- When playing over a network (not local),- -- sending too many asynchronous seek requests will cause GStreamer to error.- -- Block until this seek request finishes which will block the main GTK main thread.- -- Note that by blocking here, the seek scale will not slide.- -- The user will have to point and click on the scale track.- unless (R.isLocalFile videoInfoGathered) $ void $ GI.Gst.elementGetState playbin GI.Gst.CLOCK_TIME_NONE+ maybeDurationAndPosition <- queryPlaybinForDurationAndPosition playbin+ case maybeDurationAndPosition of+ (Just (duration, _)) -> do+ percentage <- clamp 0.0 1.0 . flip (/) 100.0 . clamp 0.0 100.0 <$> GI.Gtk.rangeGetValue seekScale+ let position =+ clamp 0 duration $+ doubleToInt64 $+ int64toDouble duration * percentage+ void $ GI.Gst.elementSeekSimple playbin GI.Gst.FormatTime [ GI.Gst.SeekFlagsFlush ] position+ videoInfo <- readIORef videoInfoRef+ -- When playing over a network (not local),+ -- sending too many asynchronous seek requests will cause GStreamer to error.+ -- Block until this seek request finishes which will block the main GTK main thread.+ -- Note that by blocking here, the seek scale will not slide.+ -- The user will have to point and click on the scale track.+ unless (R.isLocalFile videoInfo) $+ void $+ GI.Gst.elementGetState playbin GI.Gst.CLOCK_TIME_NONE+ _ -> return () -updateSeekScale ::- GI.Gst.Element ->- GI.Gtk.Scale ->- Data.GI.Base.Signals.SignalHandlerId ->- IO Bool updateSeekScale+ :: GI.Gst.Element+ -> GI.Gtk.Scale+ -> Data.GI.Base.Signals.SignalHandlerId+ -> IO Bool+updateSeekScale playbin seekScale seekScaleHandlerId = do- (couldQueryDuration, duration) <- GI.Gst.elementQueryDuration playbin GI.Gst.FormatTime- (couldQueryPosition, position) <- GI.Gst.elementQueryPosition playbin GI.Gst.FormatTime- when (couldQueryDuration && couldQueryPosition && duration > 0) $ do- let percentage = 100.0 * (fromIntegral position / fromIntegral duration :: Double)- GI.GObject.signalHandlerBlock seekScale seekScaleHandlerId- GI.Gtk.rangeSetValue seekScale percentage- GI.GObject.signalHandlerUnblock seekScale seekScaleHandlerId+ maybeDurationAndPosition <- queryPlaybinForDurationAndPosition playbin+ case maybeDurationAndPosition of+ (Just (duration, position)) ->+ when (duration > 0) $ do+ let percentage = 100.0 * (int64toDouble position / int64toDouble duration)+ GI.GObject.signalHandlerBlock seekScale seekScaleHandlerId+ GI.Gtk.rangeSetValue seekScale percentage+ GI.GObject.signalHandlerUnblock seekScale seekScaleHandlerId+ _ -> return () return True++hideOrShowSeekScale :: GI.Gtk.Scale -> Bool -> IO ()+hideOrShowSeekScale seekScale True = do+ GI.Gtk.widgetSetSensitive seekScale True+ GI.Gtk.widgetShow seekScale+hideOrShowSeekScale seekScale False = do+ GI.Gtk.widgetSetSensitive seekScale False+ GI.Gtk.widgetHide seekScale
src/SubtitleSelector.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -17,12 +17,12 @@ addSubtitleSelectorHandler application@R.Application { R.guiObjects = R.GuiObjects {- R.subtitleSelectionComboBox = subtitleSelectionComboBox+ R.subtitleSelectionComboBoxText = subtitleSelectionComboBoxText } } = void ( GI.Gtk.onComboBoxChanged- subtitleSelectionComboBox+ subtitleSelectionComboBoxText (subtitleSelectorHandler application) ) @@ -30,12 +30,12 @@ subtitleSelectorHandler R.Application { R.guiObjects = R.GuiObjects {- R.subtitleSelectionComboBox = subtitleSelectionComboBox+ R.subtitleSelectionComboBoxText = subtitleSelectionComboBoxText } , R.playbin = playbin } = do- maybeActiveId <- GI.Gtk.getComboBoxActiveId subtitleSelectionComboBox+ maybeActiveId <- GI.Gtk.getComboBoxActiveId subtitleSelectionComboBoxText nText <- getTextStreamCount playbin case maybeActiveId of Nothing -> return ()
src/Uri.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -49,14 +49,16 @@ else if hasHttpUriScheme filePathName then filePathName else "http://" ++ filePathName isLocalFile :: Prelude.String -> IO Bool-isLocalFile = Filesystem.isFile . Filesystem.Path.CurrentOS.fromText . Data.Text.pack . removeFileUriScheme+isLocalFile =+ Filesystem.isFile . Filesystem.Path.CurrentOS.fromText . Data.Text.pack . removeFileUriScheme toAbsoluteUri :: String -> IO String toAbsoluteUri uri = do cwd <- getWorkingDirectory- let cwd' = case toText cwd of- Right x -> x- Left y -> y+ let cwd' =+ case toText cwd of+ Right x -> x+ Left y -> y isLocal <- isLocalFile uri if not isLocal then return uri
src/Utils.hs view
@@ -1,11 +1,9 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} -{-# LANGUAGE ScopedTypeVariables #-}- module Utils where import System.Exit@@ -13,6 +11,7 @@ import System.FilePath import Control.Monad import Control.Exception+import Text.Read import Data.List import Data.Text import Data.Int@@ -24,12 +23,36 @@ enumToInt32 :: (Enum a, Ord a) => a -> Int32 enumToInt32 enum = fromIntegral (fromEnum enum) :: Int32 +int64toDouble :: Int64 -> Double+int64toDouble i = fromIntegral i :: Double++doubleToInt64 :: Double -> Int64+doubleToInt64 d = fromIntegral (round d :: Int) :: Int64+ isTextEmpty :: Data.Text.Text -> Bool isTextEmpty = Data.Text.null . Data.Text.strip -getSelectedVideoWidth :: GI.Gtk.ComboBoxText -> IO Int-getSelectedVideoWidth = fmap (\ x -> read (Data.Text.unpack x) :: Int) . GI.Gtk.comboBoxTextGetActiveText+getDesiredWindowWidth :: GI.Gtk.ComboBoxText -> GI.Gtk.Window -> IO Int+getDesiredWindowWidth windowWidthSelectionComboBoxText window = do+ maybeSelectedWindowWidth <- getSelectedWindowWidth windowWidthSelectionComboBoxText+ case maybeSelectedWindowWidth of+ Just selectedWidth -> return selectedWidth+ _ -> do+ (windowWidth, _) <- GI.Gtk.windowGetSize window+ return (fromIntegral windowWidth :: Int) +getSelectedWindowWidth :: GI.Gtk.ComboBoxText -> IO (Maybe Int)+getSelectedWindowWidth windowWidthSelectionComboBoxText = do+ activeId <- GI.Gtk.comboBoxGetActive windowWidthSelectionComboBoxText+ if activeId == (-1)+ then return Nothing+ else do+ string <-+ Data.Text.unpack <$>+ GI.Gtk.comboBoxTextGetActiveText+ windowWidthSelectionComboBoxText+ return (readMaybe string :: Maybe Int)+ linuxProcessIsRunning :: String -> IO Bool linuxProcessIsRunning processName = do (_, out, _) <- safeRunProcessGetOutput "pgrep" ["-f", processName]@@ -39,23 +62,25 @@ spawnLinuxProcessAndDisown processCommand = void $ System.Process.spawnCommand- (- "nohup "- ++ processCommand- ++ " </dev/null &>/dev/null & disown"- )+ ( "nohup "+ ++ processCommand+ ++ " </dev/null &>/dev/null & disown"+ ) safeRunProcessGetOutput :: String -> [String] -> IO (System.Exit.ExitCode, String, String) safeRunProcessGetOutput processName args =- catch (+ catch readProcess' catchError+ where+ readProcess' :: IO (System.Exit.ExitCode, String, String)+ readProcess' = readProcessWithExitCode processName args ""- ) (\ (e :: Control.Exception.IOException) ->- putStr (show e) >>- return (ExitFailure 1, "", "")- )+ catchError :: Control.Exception.IOException -> IO (System.Exit.ExitCode, String, String)+ catchError e = do+ putStr $ show e+ return (ExitFailure 1, "", "") clamp :: Ord a => a -> a -> a -> a clamp minimum' maximum' el
src/VideoInfo.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -19,58 +19,64 @@ import Uri import Utils -getVideoInfoRaw :: Prelude.String -> IO (Maybe Prelude.String)-getVideoInfoRaw uri = do+getRawVideoInfo :: Prelude.String -> IO (Maybe Prelude.String)+getRawVideoInfo uri = do (code, out, _) <- safeRunProcessGetOutput "gst-discoverer-1.0" [uri, "-v"] if code == System.Exit.ExitSuccess then return (Just out) else return Nothing -getVideoInfo :: IORef R.VideoInfo -> Prelude.String -> IO R.VideoInfo-getVideoInfo videoInfoRef filePathName = do- videoInfoGathered <- readIORef videoInfoRef- uri <- addUriSchemeIfNone filePathName- cacheDo (R.uri videoInfoGathered == uri) videoInfoGathered uri+processRawVideoInfo :: Maybe Prelude.String -> Prelude.String -> Maybe R.VideoInfo+processRawVideoInfo Nothing _ = Nothing+processRawVideoInfo (Just str) uri = do+ let text = Data.Text.toLower $ Data.Text.pack str+ let textLines = Data.Text.lines text+ let videoInfo =+ R.VideoInfo+ { R.uri = uri+ , R.isLocalFile = hasFileUriScheme uri+ , R.isVideo = "video: video/" `Data.Text.isInfixOf` text+ , R.isSeekable = "yes" == getField seekableField textLines+ , R.videoWidth = getDimension R.videoWidth widthField textLines+ , R.videoHeight = getDimension R.videoHeight heightField textLines+ }+ Just videoInfo where- widthField :: Data.Text.Text- widthField = "width: "- heightField :: Data.Text.Text- heightField = "height: "+ widthField :: Data.Text.Text+ widthField = "width: "+ heightField :: Data.Text.Text+ heightField = "height: " seekableField :: Data.Text.Text seekableField = "seekable: "- cacheDo :: Bool -> R.VideoInfo -> Prelude.String -> IO R.VideoInfo- cacheDo True videoInfoGathered _ = return videoInfoGathered- cacheDo False _ uri = do- videoInfoRaw <- getVideoInfoRaw uri- processVideoInfoRaw videoInfoRaw uri- processVideoInfoRaw :: Maybe Prelude.String -> Prelude.String -> IO R.VideoInfo- processVideoInfoRaw Nothing _ = do- let videoInfoGathered = R.defaultVideoInfo- atomicWriteIORef videoInfoRef videoInfoGathered- return videoInfoGathered- processVideoInfoRaw (Just str) uri = do- let text = Data.Text.toLower $ Data.Text.pack str- let textLines = Data.Text.lines text- let videoInfoGathered = R.VideoInfo {- R.uri = uri- , R.isLocalFile = hasFileUriScheme uri- , R.isVideo = "video: video/" `Data.Text.isInfixOf` text- , R.isSeekable = "yes" == getField seekableField textLines- , R.videoWidth = getDimension R.videoWidth widthField textLines- , R.videoHeight = getDimension R.videoHeight heightField textLines- }- atomicWriteIORef videoInfoRef videoInfoGathered- return videoInfoGathered getDimension :: (R.VideoInfo -> Int) -> Data.Text.Text -> [Data.Text.Text] -> Int- getDimension f field lines' = fromMaybe (- f R.defaultVideoInfo- ) (readMaybe (Data.Text.unpack $ getField field lines') :: Maybe Int)+ getDimension f field lines' =+ fromMaybe+ (f R.defaultVideoInfo)+ (readMaybe (Data.Text.unpack $ getField field lines') :: Maybe Int) getField :: Data.Text.Text -> [Data.Text.Text] -> Data.Text.Text getField field =- Prelude.foldl (\ acc l ->+ Prelude.foldl+ (\ acc l -> if not $ Data.Text.null acc then acc- else if field `Data.Text.isInfixOf` l- then Data.Text.replace field "" $ Data.Text.strip l- else ""- ) ""+ else+ if field `Data.Text.isInfixOf` l+ then Data.Text.replace field "" $ Data.Text.strip l+ else ""+ )+ ""+getVideoInfo :: IORef R.VideoInfo -> Prelude.String -> IO (Maybe R.VideoInfo)+getVideoInfo videoInfoRef filePathName = do+ videoInfo <- readIORef videoInfoRef+ uri <- addUriSchemeIfNone filePathName+ if R.uri videoInfo == uri+ then return $ Just videoInfo+ else do+ rawVideoInfo <- getRawVideoInfo uri+ case processRawVideoInfo rawVideoInfo uri of+ (Just videoInfo') -> return $ Just videoInfo'+ _ -> return Nothing++saveVideoInfo :: IORef R.VideoInfo -> R.VideoInfo -> IO ()+saveVideoInfo = atomicWriteIORef+
src/VideoSizeSelector.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -8,42 +8,76 @@ import Control.Monad import Data.Text+import Data.IORef+import qualified GI.GLib import qualified GI.Gtk import qualified Records as R+import Reset import Window-import VideoInfo import Utils -addVideoSizeSelectorHandler :: R.Application -> IO ()-addVideoSizeSelectorHandler- application@R.Application {- R.guiObjects = R.GuiObjects {- R.videoWidthSelectionComboBox = videoWidthSelectionComboBox+addVideoSizeSelectorHandlers :: R.Application -> IO ()+addVideoSizeSelectorHandlers+ application@R.Application+ { R.guiObjects =+ guiObjects@R.GuiObjects+ { R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText } }- = void (- GI.Gtk.onComboBoxChanged- videoWidthSelectionComboBox- (videoSizeSelectionHandler application)- )+ = do+ void $+ GI.Gtk.onComboBoxChanged+ windowWidthSelectionComboBoxText $+ videoSizeSelectionHandler application+ void $+ GI.GLib.timeoutAddSeconds+ GI.GLib.PRIORITY_DEFAULT+ 1 $+ setToCustomIfNeeded guiObjects videoSizeSelectionHandler :: R.Application -> IO () videoSizeSelectionHandler- R.Application {- R.guiObjects = guiObjects@R.GuiObjects {- R.videoWidthSelectionComboBox = videoWidthSelectionComboBox- , R.fileChooserEntry = fileChooserEntry+ application@R.Application+ { R.guiObjects =+ guiObjects@R.GuiObjects+ { R.window = window+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef- }+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ } } = do- filePathName <- Data.Text.unpack <$> GI.Gtk.entryGetText fileChooserEntry- videoWidthSelection <- getSelectedVideoWidth videoWidthSelectionComboBox- retrievedVideoInfo <- getVideoInfo videoInfoRef filePathName- maybeWindowSize <- calculateWindowSize guiObjects videoWidthSelection retrievedVideoInfo+ videoInfo <- readIORef videoInfoRef+ desiredWindowWidth <- getDesiredWindowWidth windowWidthSelectionComboBoxText window+ maybeWindowSize <- calculateWindowSize guiObjects desiredWindowWidth videoInfo case maybeWindowSize of- Nothing -> resetWindow guiObjects+ Nothing -> resetApplication application Just (width, height) -> setWindowSize guiObjects width height++setToCustomIfNeeded :: R.GuiObjects -> IO Bool+setToCustomIfNeeded+ R.GuiObjects+ { R.window = window+ , R.windowWidthSelectionComboBoxText = windowWidthSelectionComboBoxText+ }+ = do+ (windowWidth', _) <- GI.Gtk.windowGetSize window+ maybeSelectedWidth <- getSelectedWindowWidth windowWidthSelectionComboBoxText+ let windowWidth = fromIntegral windowWidth' :: Int+ case maybeSelectedWidth of+ Just selectedWidth ->+ when (windowWidth /= selectedWidth) $+ GI.Gtk.comboBoxSetActive windowWidthSelectionComboBoxText (-1)+ Nothing -> do+ let windowWidthText = Data.Text.pack $ show windowWidth+ present <-+ GI.Gtk.comboBoxSetActiveId+ windowWidthSelectionComboBoxText $+ Just windowWidthText+ if present+ then return ()+ else GI.Gtk.comboBoxSetActive windowWidthSelectionComboBoxText (-1)+ return True
src/Window.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -} @@ -21,66 +21,67 @@ import qualified Records as R import Constants+import Reset import Mouse import PlayPause-import Utils+import Seek addWindowHandlers :: R.Application -> [R.Application -> IO ()] -> IO () addWindowHandlers- application@R.Application {- R.guiObjects = R.GuiObjects {- R.window = window- , R.videoWidget = videoWidget+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.window = window+ , R.videoWidget = videoWidget }- , R.ioRefs = R.IORefs {- R.isWindowFullScreenRef = isWindowFullScreenRef+ , R.ioRefs =+ R.IORefs+ { R.isWindowFullScreenRef = isWindowFullScreenRef }- , R.playbin = playbin+ , R.playbin = playbin } onWidgetRealizeCallbacks- =- void (- GI.Gtk.onWidgetRealize videoWidget (- windowRealizedHandler- application- onWidgetRealizeCallbacks- )- ) >>- void (- GI.Gtk.onWidgetWindowStateEvent window (widgetWindowStateEventHandler isWindowFullScreenRef)- ) >>- void (- GI.Gtk.onWidgetDestroy window (windowDestroyHandler playbin)- ) >>- void (- GI.GLib.timeoutAddSeconds GI.GLib.PRIORITY_DEFAULT 1 (hideOnScreenControls application)- )+ = do+ void $+ GI.Gtk.onWidgetRealize videoWidget $+ windowRealizedHandler+ application+ onWidgetRealizeCallbacks+ void $+ GI.Gtk.onWidgetWindowStateEvent window (widgetWindowStateEventHandler isWindowFullScreenRef)+ void $+ GI.Gtk.onWidgetDestroy window (windowDestroyHandler playbin)+ void $+ GI.GLib.timeoutAddSeconds GI.GLib.PRIORITY_DEFAULT 1 (adjustWindow application) windowRealizedHandler- :: R.Application- -> [R.Application -> IO ()]- -> GI.Gtk.WidgetRealizeCallback+ :: R.Application+ -> [R.Application -> IO ()]+ -> GI.Gtk.WidgetRealizeCallback windowRealizedHandler- application@R.Application {- R.guiObjects = guiObjects@R.GuiObjects {- R.videoWidget = videoWidget- , R.seekScale = seekScale+ application@R.Application+ { R.guiObjects =+ guiObjects@R.GuiObjects+ { R.videoWidget = videoWidget+ , R.seekScale = seekScale } } onWidgetRealizeCallbacks = do- let eventMask = enumToInt32 GI.Gdk.EventMaskAllEventsMask+ let eventMask = [GI.Gdk.EventMaskAllEventsMask] GI.Gtk.widgetAddEvents videoWidget eventMask- GI.Gtk.widgetAddEvents seekScale eventMask- resetWindow guiObjects+ GI.Gtk.widgetAddEvents seekScale eventMask+ resetGuiObjects guiObjects mapM_ (\ f -> f application) onWidgetRealizeCallbacks widgetWindowStateEventHandler :: IORef Bool -> GI.Gdk.EventWindowState -> IO Bool widgetWindowStateEventHandler isWindowFullScreenRef eventWindowState = do windowStates <- GI.Gdk.getEventWindowStateNewWindowState eventWindowState- let isWindowFullScreen = Prelude.foldl (\ acc x ->- acc || GI.Gdk.WindowStateFullscreen == x- ) False windowStates+ let isWindowFullScreen =+ Prelude.foldl+ (\ acc x -> acc || GI.Gdk.WindowStateFullscreen == x)+ False+ windowStates atomicWriteIORef isWindowFullScreenRef isWindowFullScreen return True @@ -90,53 +91,59 @@ _ <- GI.Gst.objectUnref playbin GI.Gtk.mainQuit -hideOnScreenControls :: R.Application -> IO Bool-hideOnScreenControls- application@R.Application {- R.guiObjects = R.GuiObjects {- R.window = window- , R.fileChooserButton = fileChooserButton- , R.bottomControlsGtkBox = bottomControlsGtkBox+adjustWindow :: R.Application -> IO Bool+adjustWindow+ application@R.Application+ { R.guiObjects =+ R.GuiObjects+ { R.window = window+ , R.fileChooserButton = fileChooserButton+ , R.bottomControlsGtkBox = bottomControlsGtkBox }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef- , R.mouseMovedLastRef = mouseMovedLastRef+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ , R.mouseMovedLastRef = mouseMovedLastRef }- , R.playbin = playbin+ , R.playbin = playbin } = do- videoInfoGathered <- readIORef videoInfoRef- let isVideo = R.isVideo videoInfoGathered- mouseMovedLast <- readIORef mouseMovedLastRef- timeNow <- fmap round getPOSIXTime+ videoInfo <- readIORef videoInfoRef+ mouseMovedLast <- readIORef mouseMovedLastRef+ timeNow <- fmap round getPOSIXTime (_, playBinState, _) <- GI.Gst.elementGetState playbin (fromIntegral GI.Gst.MSECOND :: GHC.Word.Word64) let isPlaying = GI.Gst.StatePlaying == playBinState- let delta = timeNow - mouseMovedLast+ let delta = timeNow - mouseMovedLast+ let isVideo = R.isVideo videoInfo when (isPlaying && isVideo && delta >= hideOnScreenControlsInterval) $ do GI.Gtk.widgetHide fileChooserButton GI.Gtk.widgetHide bottomControlsGtkBox+ styleContext <- GI.Gtk.widgetGetStyleContext bottomControlsGtkBox+ GI.Gtk.styleContextRemoveClass styleContext "movie-monad-fade-in" setCursor window (Just "none") atomicWriteIORef mouseMovedLastRef timeNow- fillWindowWithVideo application+ fillWindowWithVideo application return True fillWindowWithVideo :: R.Application -> IO () fillWindowWithVideo- R.Application {- R.guiObjects = guiObjects@R.GuiObjects {- R.window = window+ R.Application+ { R.guiObjects =+ guiObjects@R.GuiObjects+ { R.window = window }- , R.ioRefs = R.IORefs {- R.videoInfoRef = videoInfoRef- , R.isWindowFullScreenRef = isWindowFullScreenRef+ , R.ioRefs =+ R.IORefs+ { R.videoInfoRef = videoInfoRef+ , R.isWindowFullScreenRef = isWindowFullScreenRef } } = do- isWindowFullScreen <- readIORef isWindowFullScreenRef- unless isWindowFullScreen $ do- videoInfoGathered <- readIORef videoInfoRef- (width, _) <- GI.Gtk.windowGetSize window- maybeWindowSize <- calculateWindowSize guiObjects (fromIntegral width :: Int) videoInfoGathered+ isWindowFullScreen <- readIORef isWindowFullScreenRef+ videoInfo <- readIORef videoInfoRef+ when (R.isVideo videoInfo && not isWindowFullScreen) $ do+ (width, _) <- GI.Gtk.windowGetSize window+ maybeWindowSize <- calculateWindowSize guiObjects (fromIntegral width :: Int) videoInfo when (isJust maybeWindowSize) $ do let (windowWidth, windowHeight) = fromMaybe (0, 0) maybeWindowSize setWindowSize guiObjects windowWidth windowHeight@@ -145,67 +152,68 @@ calculateWindowSize :: R.GuiObjects -> Int -> R.VideoInfo -> IO (Maybe (Int32, Int32)) calculateWindowSize _ _ R.VideoInfo { R.isVideo = False } = return Nothing calculateWindowSize- R.GuiObjects {- R.fileChooserButton = fileChooserButton- , R.bottomControlsGtkBox = bottomControlsGtkBox+ R.GuiObjects+ { R.fileChooserButton = fileChooserButton } desiredWidth- R.VideoInfo { R.videoWidth = videoWidth, R.videoHeight = videoHeight }+ R.VideoInfo+ { R.videoWidth = videoWidth+ , R.videoHeight = videoHeight+ } = do- fileChooserButtonIsVisible <- GI.Gtk.widgetGetVisible fileChooserButton- bottomControlsGtkBoxIsVisible <- GI.Gtk.widgetGetVisible bottomControlsGtkBox+ fileChooserButtonIsVisible <- GI.Gtk.widgetGetVisible fileChooserButton fileChooserButtonHeight <- GI.Gtk.widgetGetAllocation fileChooserButton >>= GI.Gdk.getRectangleHeight- bottomControlsGtkBoxHeight <- GI.Gtk.widgetGetAllocation bottomControlsGtkBox >>= GI.Gdk.getRectangleHeight- let videoWidthDouble = fromIntegral videoWidth :: Double+ let videoWidthDouble = fromIntegral videoWidth :: Double let videoHeightDouble = fromIntegral videoHeight :: Double- let ratio = if videoWidthDouble <= 0.0 then 0.0 else videoHeightDouble / videoWidthDouble+ let ratio =+ if videoWidthDouble <= 0.0+ then 0.0+ else videoHeightDouble / videoWidthDouble let desiredWidthDouble = fromIntegral desiredWidth :: Double- let topMargin = if fileChooserButtonIsVisible- then (fromIntegral fileChooserButtonHeight :: Double)- else 0.0- let bottomMargin = if bottomControlsGtkBoxIsVisible- then (fromIntegral bottomControlsGtkBoxHeight :: Double)- else 0.0+ let topMargin =+ if fileChooserButtonIsVisible+ then (fromIntegral fileChooserButtonHeight :: Double)+ else 0.0+ let bottomMargin = 0.0 let height = topMargin + (desiredWidthDouble * ratio) + bottomMargin- return (Just (fromIntegral desiredWidth:: Int32, round height :: Int32))+ return $ Just (fromIntegral desiredWidth:: Int32, round height :: Int32) setWindowSize :: R.GuiObjects -> Int32 -> Int32 -> IO () setWindowSize- R.GuiObjects {- R.window = window+ R.GuiObjects+ { R.window = window } width height = GI.Gtk.windowResize window width (if height <= 0 then 1 else height) -resetWindow :: R.GuiObjects -> IO ()-resetWindow- guiObjects@R.GuiObjects {- R.window = window- , R.fileChooserButton = fileChooserButton- , R.videoWidget = videoWidget- , R.seekScale = seekScale- , R.playPauseButton = playPauseButton- , R.videoWidthSelectionComboBox = videoWidthSelectionComboBox- , R.subtitleSelectionComboBox = subtitleSelectionComboBox- , R.fullscreenButton = fullscreenButton- , R.playImage = playImage- , R.pauseImage = pauseImage- , R.bottomControlsGtkBox = bottomControlsGtkBox+setupWindowForPlayback :: R.GuiObjects -> Bool -> Bool -> Int32 -> Int32 -> IO ()+setupWindowForPlayback+ guiObjects@R.GuiObjects+ { R.window = window+ , R.videoWidget = videoWidget+ , R.bottomControlsGtkBox = bottomControlsGtkBox+ , R.seekScale = seekScale+ , R.playPauseButton = playPauseButton+ , R.repeatCheckButton = repeatCheckButton+ , R.fullscreenButton = fullscreenButton+ , R.playImage = playImage+ , R.pauseImage = pauseImage }+ isSeekable+ isWindowFullScreen+ windowWidth+ windowHeight = do- videoWidthSelection <- getSelectedVideoWidth videoWidthSelectionComboBox- let width = fromIntegral videoWidthSelection :: Int32- GI.Gtk.windowUnfullscreen window- GI.Gtk.widgetHide videoWidget- GI.Gtk.widgetHide seekScale- GI.Gtk.widgetHide playPauseButton- GI.Gtk.widgetHide fullscreenButton- GI.Gtk.widgetHide subtitleSelectionComboBox- GI.Gtk.widgetShow fileChooserButton GI.Gtk.widgetShow bottomControlsGtkBox- GI.Gtk.widgetShow videoWidthSelectionComboBox- setCursor window Nothing- setPlayPauseButton playPauseButton playImage pauseImage False- setWindowSize guiObjects width 0+ GI.Gtk.widgetShow videoWidget+ GI.Gtk.widgetShow playPauseButton+ GI.Gtk.widgetShow repeatCheckButton+ GI.Gtk.widgetShow fullscreenButton+ GI.Gtk.setToggleButtonActive repeatCheckButton False+ GI.Gtk.widgetSetSizeRequest window windowMinimumSize 100+ setPlayPauseButton playPauseButton playImage pauseImage True+ unless isWindowFullScreen $+ setWindowSize guiObjects windowWidth windowHeight+ hideOrShowSeekScale seekScale isSeekable
src/c/gst-ffi.c view
@@ -1,6 +1,6 @@ /* Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com */
src/c/gst-ffi.h view
@@ -1,6 +1,6 @@ /* Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com */
+ src/data/about-icon.svg view
@@ -0,0 +1,267 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<svg+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:xlink="http://www.w3.org/1999/xlink"+ width="30"+ height="30"+ viewBox="0 0 30 30"+ version="1.1"+ id="svg8">+ <defs+ id="defs2">+ <linearGradient+ id="linearGradient5445">+ <stop+ style="stop-color:#57ace3;stop-opacity:1;"+ offset="0"+ id="stop5441" />+ <stop+ style="stop-color:#57ace3;stop-opacity:0;"+ offset="1"+ id="stop5443" />+ </linearGradient>+ <marker+ orient="auto"+ refY="0"+ refX="0"+ id="Arrow1Mend"+ style="overflow:visible">+ <path+ id="path10335"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ style="fill:#57ace3;fill-opacity:1;fill-rule:evenodd;stroke:#57ace3;stroke-width:1.00000003pt;stroke-opacity:1"+ transform="matrix(-0.4,0,0,-0.4,-4,0)" />+ </marker>+ <marker+ orient="auto"+ refY="0"+ refX="0"+ id="marker10589"+ style="overflow:visible">+ <path+ id="path10326"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ style="fill:#57ace3;fill-opacity:1;fill-rule:evenodd;stroke:#57ace3;stroke-width:1.00000003pt;stroke-opacity:1"+ transform="matrix(0.8,0,0,0.8,10,0)" />+ </marker>+ <linearGradient+ id="linearGradient10200">+ <stop+ id="stop10196"+ offset="0"+ style="stop-color:#57ace3;stop-opacity:1" />+ <stop+ id="stop10198"+ offset="1"+ style="stop-color:#e0437f;stop-opacity:0.89019608" />+ </linearGradient>+ <linearGradient+ id="linearGradient8935"+ osb:paint="solid">+ <stop+ style="stop-color:#373737;stop-opacity:1;"+ offset="0"+ id="stop8933" />+ </linearGradient>+ <linearGradient+ id="linearGradient5282">+ <stop+ style="stop-color:#814dd2;stop-opacity:1;"+ offset="0"+ id="stop5278" />+ <stop+ style="stop-color:#b46bd3;stop-opacity:0.89019608"+ offset="1"+ id="stop5280" />+ </linearGradient>+ <marker+ orient="auto"+ refY="0"+ refX="0"+ id="Arrow1Lend"+ style="overflow:visible">+ <path+ id="path4997"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"+ transform="matrix(-0.8,0,0,-0.8,-10,0)" />+ </marker>+ <marker+ orient="auto"+ refY="0"+ refX="0"+ id="Arrow1Lstart"+ style="overflow:visible">+ <path+ id="path4994"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"+ transform="matrix(0.8,0,0,0.8,10,0)" />+ </marker>+ <linearGradient+ xlink:href="#linearGradient5282"+ id="linearGradient5284"+ x1="-119.13808"+ y1="53.642838"+ x2="-64.290207"+ y2="53.285694"+ gradientUnits="userSpaceOnUse" />+ <linearGradient+ xlink:href="#linearGradient5282"+ id="linearGradient5300"+ gradientUnits="userSpaceOnUse"+ x1="-119.13808"+ y1="53.642838"+ x2="-58.218777"+ y2="55.071407" />+ <linearGradient+ xlink:href="#linearGradient5282"+ id="linearGradient5352"+ gradientUnits="userSpaceOnUse"+ x1="-119.13808"+ y1="53.642838"+ x2="-58.218777"+ y2="55.071407" />+ <linearGradient+ xlink:href="#linearGradient5282"+ id="linearGradient5354"+ gradientUnits="userSpaceOnUse"+ x1="-119.13808"+ y1="53.642838"+ x2="-64.290207"+ y2="53.285694" />+ <linearGradient+ xlink:href="#linearGradient10200"+ id="linearGradient5260"+ x1="61.251041"+ y1="250.69791"+ x2="128.98438"+ y2="250.69791"+ gradientUnits="userSpaceOnUse"+ gradientTransform="matrix(1.1521699,0,0,1.1943224,-10.9053,-54.269335)" />+ <clipPath+ clipPathUnits="userSpaceOnUse"+ id="clipPath5388">+ <g+ id="g5394">+ <path+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.23003563;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"+ d="m 125.5315,249.78764 c -3.34965,-1.30393 -6.69931,-2.60787 -10.04896,-3.9118 5.21848,-2.15262 10.43696,-4.30525 15.65545,-6.45787 -0.92835,-2.01253 -1.85669,-4.02505 -2.78504,-6.03758 -6.83922,2.90641 -13.67843,5.81282 -20.51763,8.71921 0.0104,2.54721 0.0208,5.09442 0.0312,7.64163 6.86079,2.8724 13.7216,5.74479 20.58242,8.61717 0.90892,-2.11466 1.81783,-4.22931 2.72675,-6.34397 -1.76975,-0.68894 -3.53951,-1.37789 -5.30926,-2.06683 m -2.62477,-4.90221 c 3.04901,-1.25752 6.09801,-2.51505 9.14702,-3.77257 -0.92751,-2.01274 -1.85501,-4.02549 -2.78252,-6.03823 -2.59416,1.10259 -5.18831,2.20519 -7.78247,3.30778 m 5.56493,-1.53082 c -5.40972,2.29966 -10.81943,4.59932 -16.22916,6.89899 0.0117,2.54697 0.0234,5.09394 0.0352,7.64091 6.86463,2.8717 13.72924,5.74341 20.59384,8.61511 0.91009,-2.11486 1.82018,-4.22973 2.73027,-6.3446 -5.23684,-2.04024 -10.47368,-4.08049 -15.71053,-6.12073 0.75831,-0.31271 1.51662,-0.62542 2.27492,-0.93812 m -14.17992,-7.36348 c -0.76309,-1.65493 -1.52619,-3.30987 -2.28928,-4.9648 -6.839321,2.90343 -13.678636,5.80688 -20.517944,8.71032 0.01054,2.5462 0.02107,5.0924 0.03161,7.6386 6.860547,2.86946 13.721102,5.73892 20.581664,8.60838 0.90903,-2.11556 1.81807,-4.23112 2.72711,-6.34668 -5.23993,-2.04195 -10.479853,-4.08389 -15.719771,-6.12583 3.538493,-1.46115 7.076989,-2.9223 10.615481,-4.38345 m -9.578034,6.75815 c -0.379995,-0.14802 -0.759989,-0.29603 -1.139983,-0.44404 5.220982,-2.15291 10.441957,-4.30583 15.662927,-6.45875 -0.54602,-1.18498 -1.09203,-2.36995 -1.63805,-3.55493 m -30.75959,4.52156 c 2.327107,-4.2e-4 4.654213,-8.4e-4 6.981318,-0.001 4.72e-4,-2.42569 9.42e-4,-4.85139 0.0014,-7.27708 -5.608879,-0.001 -11.217765,-0.002 -16.826659,-0.003 4.62e-4,2.42483 9.24e-4,4.84967 0.0014,7.2745 5.611028,-9.8e-4 11.22205,-0.002 16.833063,-0.003 4.54e-4,-2.42568 9.07e-4,-4.85135 0.0014,-7.27703 -1.723988,-3e-4 -3.447976,-5.9e-4 -5.171966,-8.9e-4 m -2.024007,22.444 c 2.816132,-10e-6 5.632262,-2e-5 8.448391,-3e-5 4.56e-4,-2.64572 9.1e-4,-5.29144 0.0014,-7.93716 -5.637754,-2e-5 -11.275514,-5e-5 -16.913281,-7e-5 4.48e-4,2.6457 8.94e-4,5.29139 0.0013,7.93709 5.639668,-2e-5 11.279329,-5e-5 16.918984,-7e-5 4.39e-4,-2.64571 8.77e-4,-5.29143 0.0013,-7.93714 -0.03972,0 -0.07944,0 -0.119166,0 m 27.325493,-18.3087 -17.328909,7.36254 m 21.261659,1.45287 -0.93476,0.39715 m 0.92531,12.30443 14.19828,5.93971"+ id="path5390" />+ <path+ id="path5392"+ d="m 650.1385,82.874465 c -10.14856,3.782654 -20.17926,7.700083 -30.11698,11.72366 3e-5,-0.006 -0.20482,33.232065 -0.20478,33.226075 10.46549,4.53108 20.80642,9.17856 30.98016,13.96537 M 633.88611,89.913445 c -4.37599,1.711249 -8.73217,3.445238 -13.07064,5.199586 10e-6,-4.22e-4 -0.0731,11.184859 -0.0731,11.184439 m 0.3725,-3.80674 c 2e-5,-0.002 -0.17666,25.85227 -0.17665,25.8502 14.60689,6.33968 28.96767,12.90811 42.96621,19.76778 m -31.32028,-14.07007 c 25.19819,11.26699 49.55187,23.27873 72.44648,36.3659 1.42471,-2.72961 2.86128,-5.45544 4.31003,-8.17738 m -6.9747,6.68407 c 0.92932,0.52537 1.85629,1.05248 2.78088,1.58133 4.58589,-8.78001 9.29471,-17.52088 14.13698,-26.21901 -6.95333,-3.77163 -14.01978,-7.44184 -21.18454,-11.01929 m 1.28755,-0.18569 c -14.81139,-7.42465 -30.04545,-14.44997 -45.57119,-21.15245 12.62262,-4.62919 25.39834,-9.03993 38.37684,-13.17341 m -18.736,22.83496 c -6.26352,-2.87301 -12.58606,-5.68603 -18.95852,-8.44437 23.14013,-8.47831 46.79246,-16.218619 71.2638,-22.85755 -0.22881,-0.662606 -0.45833,-1.325109 -0.68856,-1.987508 M 654.01463,113.139 c -2.7e-4,-1.2e-4 -0.7157,-0.30906 -0.71597,-0.30917 23.13517,-8.5031 46.78037,-16.274199 71.2423,-22.950019 -2.81543,-8.107892 -5.73743,-16.200324 -8.75838,-24.277065 m -26.0906,33.266668 C 700.9826,95.2376 712.42531,91.81337 724.05294,88.63561 723.6003,87.337599 723.14495,86.039985 722.6869,84.742768 m -0.61698,6.067377 c 0.81695,-0.226028 1.6348,-0.450842 2.45357,-0.674428 -3.17915,-9.162957 -6.49443,-18.306184 -9.93482,-27.429347 -0.62065,0.179639 -1.24074,0.359926 -1.86026,0.540855 m 11.24057,25.511777 c -3e-5,7e-6 0.25989,-0.07102 0.25987,-0.07101 -3.19279,-9.161294 -6.52126,-18.302817 -9.97442,-27.424233 -10.91387,3.159213 -21.65318,6.518244 -32.24401,10.04705 m 11.85645,-2.486221 c -23.89063,7.594747 -46.99669,16.092552 -69.6095,25.158099 m -0.43504,1.234896 c -0.86163,0.346106 -1.72255,0.693034 -2.58277,1.040765 0,-6.34e-4 -0.0817,11.715582 -0.0816,11.714952 m -1.1452,-4.62256 c 2e-5,-0.003 -0.15748,25.97022 -0.15747,25.96764 19.67826,8.52466 38.91018,17.46103 57.41168,26.96201 m -5.18017,-4.09637 c 11.17724,5.62986 22.1038,11.4573 32.71864,17.51516 1.06549,-2.04103 2.13762,-4.07996 3.21651,-6.11673 m -16.16776,-0.69646 c 4.49775,2.43586 8.94607,4.90905 13.34063,7.42189 4.58695,-8.78083 9.2969,-17.5225 14.14034,-26.22142 -13.91794,-7.55008 -28.28862,-14.69392 -42.99342,-21.50079 m 3.21074,0.98686 c -8.79479,-4.11181 -17.71249,-8.10054 -26.7275,-11.98114 9.58226,-3.52312 19.25253,-6.92117 29.03252,-10.1684 m -6.29117,3.40887 c 16.00699,-5.451542 32.29632,-10.509544 48.965,-15.0591 -2.7328,-7.869445 -5.56598,-15.724327 -8.49254,-23.564436 m 9.71391,23.600286 c 0,0 0.0757,-0.02053 0.0757,-0.02053 -3.16863,-9.16775 -6.47406,-18.315717 -9.90529,-27.443567 -14.81942,4.262317 -29.3167,8.895683 -43.55719,13.824889 m 47.96342,-1.486613 c -1.4697,-4.050884 -2.96505,-8.097851 -4.48508,-12.14087 -10.36572,2.9834 -20.57391,6.148352 -30.64696,9.469099 m 34.56573,1.426708 c -1.47522,-4.049947 -2.97598,-8.095973 -4.5013,-12.138051 -19.92422,5.742688 -39.26545,12.153458 -58.18225,19.049877 m 27.30054,-7.799146 c -7.20357,2.383909 -14.33829,4.847277 -21.41236,7.380658 m 13.91885,-6.240903 C 658.33096,80.00152 640.22123,86.8241 622.41471,93.993846 M 522.52817,91.33976 c -3.71543,1.71506 -7.42434,3.436 -11.12792,5.16192 -5e-5,-0.0011 0.51202,11.70155 0.51197,11.70043 m -1.1665,-9.974259 c -2e-5,7e-6 -0.1003,0.04677 -0.10032,0.04678 -4.8e-4,-0.01106 1.45486,33.189159 1.45438,33.178099 14.55619,5.39325 29.02314,10.86367 43.33703,16.46536 m -44.30747,-34.95594 c -1.2e-4,-0.003 0.7663,17.43323 0.76618,17.43044 2.49473,0.92408 4.98688,1.85041 7.47614,2.77928 m -7.7994,-15.73106 c -6e-5,-0.001 0.55121,12.57744 0.55114,12.57602 16.53443,6.12668 32.95588,12.35293 49.17089,18.75796 m -49.99946,-25.64531 c -2e-5,-4.2e-4 0.29602,6.72016 0.296,6.71974 21.69281,8.03096 43.19288,16.23183 64.28933,24.78141 m -55.73533,-22.29122 c 16.28128,6.07809 32.43879,12.26569 48.38274,18.6389 m -29.93723,-10.07554 c 13.09037,4.99891 26.07571,10.08848 38.90831,15.30914 4.92668,2.00718 9.8291,4.03142 14.70284,6.07511 m -42.55877,-18.2672 c 9.34563,3.62215 18.63091,7.2968 27.83828,11.03885 8.29429,3.37568 16.52059,6.79982 24.65785,10.28374 2.01069,-4.82106 4.0379,-9.63863 6.08313,-14.45221 m -27.09237,6.5496 c 6.76797,2.77515 13.48798,5.5838 20.1485,8.43215 3.83273,-9.20444 7.72504,-18.39642 11.68744,-27.57238 -2.66279,-1.06701 -5.33349,-2.1269 -8.01145,-3.18005 m -17.67348,24.80831 c -4e-4,-1.7e-4 0.71089,0.29523 0.71049,0.29506 m 0.1423,0.48985 c 4.49734,1.87003 8.97142,3.75596 13.41882,5.65962 m -10.07756,-3.99132 c 3.3045,1.3838 6.59589,2.77646 9.8728,4.17875 3.83071,-9.20427 7.72094,-18.39609 11.68121,-27.57188 -4.68156,-1.87698 -9.38775,-3.73191 -14.11494,-5.56693 m -3.47113,28.46889 c 2.5033,1.05562 4.99884,2.11653 7.48603,3.18308 3.84259,-9.20093 7.74586,-18.38896 11.72032,-27.56052 -12.40258,-4.98562 -24.97809,-9.81439 -37.65896,-14.52577 -3.82029,-1.41856 -7.65021,-2.82596 -11.48865,-4.22321 m 48.53743,21.60948 c -1.7e-4,3.9e-4 0.39562,-0.91482 0.39545,-0.91442 -12.31989,-4.95543 -24.81309,-9.75643 -37.41315,-14.4418 0,0 0,0 0,0 -0.002,-6.7e-4 -1.5944,-0.59165 -1.59619,-0.59232 m 14.92841,5.28033 c -4.43048,-1.68898 -8.87723,-3.36174 -13.33731,-5.02001 -10.81095,-4.01704 -21.70034,-7.94452 -32.64285,-11.80547 3.60406,-1.59938 7.21381,-3.19151 10.83032,-4.77558 m 3.29087,8.88546 c -4.50086,-1.62052 -9.01254,-3.22799 -13.53326,-4.82404 10.49312,-4.65332 21.03521,-9.24496 31.65268,-13.754409 6.66805,-2.833165 13.36682,-5.635506 20.10392,-8.398021 m -42.45579,26.47275 c -2.78093,-0.99529 -5.56581,-1.98581 -8.35423,-2.97194 3.53011,-1.56467 7.06571,-3.12228 10.60782,-4.67206 m -6.28217,1.12112 c 8.75211,-3.85687 17.54116,-7.66857 26.38242,-11.423276 6.20558,-2.636402 12.43772,-5.246109 18.70256,-7.821867 M 565.235,104.41462 c 1.69001,-0.73028 3.38168,-1.45864 5.07513,-2.185 m -3.7095,0.27093 c 3.32978,-1.43549 6.66623,-2.863461 10.01016,-4.283286 12.05562,-5.120857 24.21185,-10.14093 36.5136,-15.007053 -3.81958,-8.195982 -7.69977,-16.37731 -11.6316,-24.543711 m 7.66441,15.992954 c -2.66865,-5.659947 -5.36479,-11.312843 -8.08546,-16.958599 -6.13403,2.520537 -12.22664,5.07595 -18.28339,7.659824 m 21.84963,0.238651 c -1.20001,-2.513838 -2.40514,-5.026273 -3.61513,-7.537296 -5.45027,2.240821 -10.8679,4.509159 -16.25681,6.80051 m 12.33523,-6.475731 c -6.71383,2.781303 -13.37891,5.602978 -20.0026,8.456552 m 5.22342,-1.425141 c -2.06169,0.880321 -4.11923,1.763923 -6.17285,2.650552 -21.36486,9.204436 -42.34641,18.729808 -63.15655,28.416385 m 73.147,-32.390491 c -3.33946,1.415917 -6.66778,2.840803 -9.98587,4.27359 -14.08986,6.07131 -28.0133,12.282249 -41.83112,18.58698 m 34.13476,-15.102029 c -13.55068,5.91156 -26.95662,11.945573 -40.2726,18.06074 m 39.16746,-18.497686 c -10.0099,4.372426 -19.94106,8.811076 -29.81557,13.299296 m 19.59876,-7.374448 c -15.5269,6.890006 -30.88255,13.927354 -46.15087,21.048813 -1e-4,-0.0022 0.70303,16.025174 0.70293,16.022934 m 0.87606,-18.197656 c -1.8e-4,8.6e-5 -0.35811,0.166728 -0.35829,0.166814 m 1.0845,0.822688 c -0.004,0.0019 -1.6924,0.788526 -1.69655,0.790459 -1.3e-4,-0.0029 0.8415,19.229225 0.84138,19.226345 m 0.27161,-20.309876 c -7.4e-4,3.43e-4 -0.7139,0.332478 -0.71464,0.332822 -4.1e-4,-0.0093 1.44551,33.189744 1.44511,33.180454 11.28037,4.18384 22.50704,8.41503 33.65029,12.71877 m -35.32335,-28.4736 c -1.1e-4,-0.002 0.69833,15.95299 0.69823,15.95058 17.67847,6.5524 35.2262,13.2193 52.52889,20.09755 m -13.02772,-5.47913 c 6.6484,2.58631 13.26536,5.19988 19.84453,7.84608 m -14.54076,-5.47895 c 3.37538,1.32474 6.74215,2.65692 10.09948,3.99724 m -5.39576,-1.55957 c 5.19891,2.05665 10.37627,4.13181 15.52899,6.22812 7.99932,3.25904 15.93464,6.56309 23.78707,9.92231 3.57334,-8.58229 7.19846,-17.15376 10.88388,-25.71151 m -48.34699,8.62713 c 4.56751,1.81107 9.1183,3.63669 13.65027,5.47863 8.54576,3.47808 17.01964,7.00763 25.39866,10.60104 1.91828,-4.59494 3.85169,-9.18667 5.80151,-13.77474 m -41.52622,0.53198 c 3.46016,1.38089 6.91028,2.77041 10.34944,4.16935 8.32169,3.38981 16.57422,6.82834 24.73632,10.32703 3.83666,-9.20168 7.7334,-18.39069 11.70074,-27.56344 -5.91972,-2.37789 -11.87907,-4.72026 -17.87072,-7.03142 m 13.95401,4.36254 c -0.002,-8.8e-4 -1.79942,-0.71399 -1.80164,-0.71487 m 0.2527,1.27065 c -10.383,-4.11626 -20.88016,-8.12817 -31.45225,-12.05866 -10.56518,-3.92547 -21.20529,-7.76542 -31.89671,-11.54133 -0.0133,0.006 3.635,-1.60838 3.62171,-1.60249 m 48.06573,20.84643 c -4.71759,-1.82299 -9.45546,-3.6265 -14.21001,-5.41264 m 2.40102,-0.24272 c -2.66027,-1.00343 -5.32589,-2.00128 -7.99623,-2.99393 -10.42273,-3.87217 -20.91774,-7.66119 -31.46237,-11.38766 -0.0155,0.007 3.94408,-1.74398 3.92858,-1.73711 m 20.40457,11.06315 c -7.93034,-2.90965 -15.89953,-5.77414 -23.89767,-8.60246 5.07406,-2.24838 10.15954,-4.48219 15.25944,-6.69909 m -13.61623,6.67486 c -0.009,-0.003 -3.05456,-1.0798 -3.06326,-1.08288 10.62529,-4.71174 21.30067,-9.36051 32.05354,-13.925016 7.17818,-3.048345 14.3921,-6.060956 21.6512,-9.026612 m -8.83851,3.867272 c 7.88156,-3.275909 15.81224,-6.50137 23.80435,-9.661803 -0.90946,-1.951272 -1.82236,-3.901714 -2.73857,-5.851321 m 2.26344,3.123577 c -3.69749,-7.913834 -7.45102,-15.813948 -11.25251,-23.700094 -8.52807,3.498878 -16.97554,7.065434 -25.35735,10.682462 -4.89403,2.107372 -9.76789,4.231576 -14.62411,6.370693 M 445.26039,104.95921 c 8.95388,-0.41892 2.48979,-0.11655 11.44367,-0.53548 m -10.32304,0.17021 c 17.33763,-0.81148 34.68486,-1.62857 52.04397,-2.35972 0,2e-5 -0.46265,-11.003332 -0.46265,-11.003312 m -45.86181,13.509922 c 10.91924,-0.51039 21.84207,-1.01902 32.76909,-1.50304 m -10.72124,-0.82499 c 8.06799,-0.36738 16.13864,-0.72541 24.21221,-1.06487 0.002,0.0443 -1.33278,-31.644013 -1.33091,-31.599662 -6.59015,0.277373 -13.17046,0.56677 -19.74107,0.863273 m 2.25648,0.535649 c -7.33994,0.328149 -36.12847,1.680751 -43.46841,2.0089 m 35.77564,-0.870908 c -10.87947,0.497595 -31.75687,1.489268 -42.63634,1.986863 m 3.35972,-1.504318 c 0.3926,-0.01824 -9.26877,0.428031 -8.87616,0.409785 -0.001,-0.02231 1.44585,31.619878 1.44483,31.597578 0.10319,-0.005 5.20958,-0.23887 5.31278,-0.24357 m -0.204,-30.764537 c 0.20259,-0.0094 -6.92127,0.318259 -6.71869,0.308893 -9.8e-4,-0.02167 1.4404,31.616444 1.43942,31.594774 0.18506,-0.008 6.8961,-0.31721 7.08117,-0.32567 m -6.69282,-6.800653 c 0,-4e-6 0.31803,6.962623 0.31803,6.962613 0.24334,-0.0111 7.70728,-0.35517 7.95063,-0.3663 m -8.35399,-1.37173 c 0,0 0.0827,1.80758 0.0827,1.80758 3.05198,-0.1396 22.3444,-1.0416 25.39639,-1.1812 m 20.54411,-1.2031 c 8.98415,-0.412 17.97129,-0.81375 26.96173,-1.19252 0.002,0.0378 -1.33278,-31.63929 -1.33119,-31.601527 -10.17041,0.427735 -20.31779,0.884055 -30.44258,1.350874 m 30.68618,-0.727576 c -20.40162,0.859073 -40.71202,1.833698 -60.93492,2.777862 m 28.41956,-1.684043 c -4.22241,0.195401 -19.86403,0.929934 -24.08644,1.125334 m 22.1757,-1.068146 c -22.67755,1.053109 -16.70814,0.783245 -39.38568,1.836354 -1.5e-4,-0.0032 0.53526,11.761592 0.53512,11.758434 M 456.1832,71.641038 c -107.36134,5.003653 74.40662,-3.471827 -32.95473,1.531826 -1e-4,-0.0021 0.45249,9.905361 0.45239,9.903239 m 25.13451,-10.51949 c 11.4671,-0.537186 -36.69231,1.710473 -25.2252,1.173287 -10e-4,-0.02348 1.44302,31.62008 1.44195,31.5966 6.6279,-0.30246 28.48629,-1.33026 35.11418,-1.63271 m -34.01894,1.55836 c 13.40919,-0.61298 30.78484,-1.43956 44.19403,-2.05254 m -9.57076,1.21557 c 12.84616,-0.59866 25.69743,-1.18654 38.55477,-1.72643 0.003,0.0687 -1.20262,-28.704057 -1.19974,-28.635325 m -20.19182,84.780915 c -0.21095,0.01 8.4496,-0.38049 8.23866,-0.3709 m -8.41928,0.49644 c 7.79043,-0.35497 15.56308,-0.70026 23.31815,-1.02742 0.007,0.17634 -1.454,-34.6511 -1.4466,-34.47476 -7.23283,0.30431 -14.47011,0.62392 -21.71203,0.95211 m 9.43944,34.49334 c 4.35639,-0.19382 8.70719,-0.3835 13.05244,-0.56757 0.003,0.0658 -1.45774,-34.5418 -1.45496,-34.47597 -0.0566,0.002 -5.57856,0.23811 -5.63518,0.2405 m 7.67487,28.58015 c 0,0 -0.41001,-9.7569 -0.41001,-9.7569 m 0.84075,6.75642 c 0.001,0.0345 -1.11266,-26.54189 -1.11121,-26.50737 -17.97928,0.75466 -35.9856,1.60511 -54.02154,2.44839 m 55.02012,23.80444 c 0.006,0.15291 -0.85594,-20.44976 -0.84954,-20.29685 m 0.21926,1.51521 c 3.2e-4,0.007 -0.35057,-8.37981 -0.35026,-8.37231 -10.56586,0.44235 -21.14047,0.91781 -31.72435,1.40548 m 9.07711,1.51928 c -17.08329,0.77653 -35.79512,1.67755 -52.8784,2.45408 -10e-4,-0.0288 1.56889,34.50005 1.56758,34.4713 0.0578,-0.003 4.17177,-0.18968 4.22958,-0.1923 m -4.9898,-19.88838 c -3.9e-4,-0.009 0.87703,19.28511 0.87665,19.27657 18.52645,-0.84154 35.36,-1.65485 53.88645,-2.49639 m 11.79881,0.19044 c -0.15813,0.007 8.99192,-0.38652 8.83379,-0.37961 0,-8e-5 -1.43645,-34.11648 -1.43645,-34.11656 m -1.69544,33.35022 c -0.0262,0.001 3.81656,-0.16211 3.79034,-0.16098 0.0154,0.36787 -1.45891,-34.8442 -1.44351,-34.47633 -0.0214,9e-4 -3.51047,0.14833 -3.53187,0.14923 m 4.61961,19.10903 c 0.004,0.0846 -0.7849,-18.76637 -0.78136,-18.68176 -24.53906,1.02942 -49.13067,2.23808 -73.78157,3.36404 m 73.39732,-3.66621 c 0,0 -0.0474,-1.127 -0.0474,-1.127 -8.93561,0.37444 -17.87754,0.77245 -26.82607,1.18138 m 15.15017,0.12669 c -0.22973,0.0101 -9.6171,0.43046 -9.84682,0.44058 m 1.52062,0.345 c -16.3477,0.7365 -38.85642,1.81571 -55.20412,2.55222 -0.001,-0.024 1.47399,32.4516 1.4729,32.4276 m 40.34206,-35.16508 c -25.57791,1.18495 -15.88789,0.74325 -41.4658,1.92819 -7.8e-4,-0.0171 1.20903,26.53287 1.20826,26.51578 m 24.69612,-28.18016 c 9.38054,-0.43806 -35.6539,1.65382 -26.27337,1.21576 -10e-4,-0.0299 1.57081,34.49549 1.56944,34.46557 0.0759,-0.003 4.73497,-0.21628 4.81082,-0.21973 m -2.79194,-33.16411 c 0.024,-10e-4 -2.59955,0.11863 -2.57551,0.11753 -3.8e-4,-0.008 0.81071,17.75552 0.81033,17.74722 m -1.05401,-3.95996 c -4.1e-4,-0.009 0.893,19.58434 0.89259,19.57526 0.0996,-0.005 5.38625,-0.24533 5.48582,-0.24984 m -0.33746,0.29461 c 18.09098,-0.82865 28.05353,-1.30984 46.14451,-2.13849 m -30.04522,0.96991 c 1.36603,-0.0638 6.13168,-0.28688 7.4977,-0.35072 m -6.93486,1.30994 c 17.84352,-0.83316 35.59379,-1.67094 53.25327,-2.41376 10e-4,0.025 -0.89264,-21.27401 -0.89159,-21.24898 M 645.80356,40.256829 c -23.8913,8.70051 -47.01068,18.108537 -69.65321,27.884575 -12.80286,5.515966 -25.46813,11.14719 -38.04142,16.859298 m 110.06361,-0.565846 c -1.94967,0.731567 -3.89505,1.468057 -5.83632,2.209266 m -8.16639,48.076008 c 27.78565,12.47688 54.52593,25.87031 79.39341,40.62548"+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"+ transform="matrix(0.23003563,0,0,0.23003563,-34.32847,220.35427)" />+ </g>+ </clipPath>+ <linearGradient+ xlink:href="#linearGradient5445"+ id="linearGradient5447"+ x1="194.11444"+ y1="171.69249"+ x2="208.0477"+ y2="171.69249"+ gradientUnits="userSpaceOnUse" />+ </defs>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ id="layer1"+ transform="matrix(0.41323205,0,0,0.41323205,-25.73224,-69.525257)"+ style="display:inline">+ <rect+ style="display:inline;opacity:1;fill:url(#linearGradient5260);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.31037128;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"+ id="rect5250"+ width="77.735458"+ height="77.735466"+ x="59.818722"+ y="206.27705"+ ry="2.3587098"+ clip-path="url(#clipPath5388)"+ transform="translate(2.9514358e-6,-40.596579)" />+ <path+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2a144d;stroke-width:0.23003563;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"+ d="m 125.5315,209.19106 c -3.34965,-1.30393 -6.69931,-2.60787 -10.04896,-3.9118 5.21848,-2.15262 10.43696,-4.30525 15.65545,-6.45787 -0.92835,-2.01253 -1.85669,-4.02505 -2.78504,-6.03758 -6.83922,2.90641 -13.67843,5.81282 -20.51763,8.71921 0.0104,2.54721 0.0208,5.09442 0.0312,7.64163 6.86079,2.8724 13.7216,5.74479 20.58242,8.61717 0.90892,-2.11466 1.81783,-4.22931 2.72675,-6.34397 -1.76975,-0.68894 -3.53951,-1.37789 -5.30926,-2.06683 m -2.62477,-4.90221 c 3.04901,-1.25752 6.09801,-2.51505 9.14702,-3.77257 -0.92751,-2.01274 -1.85501,-4.02549 -2.78252,-6.03823 -2.59416,1.10259 -5.18831,2.20519 -7.78247,3.30778 m 5.56493,-1.53082 c -5.40972,2.29966 -10.81943,4.59932 -16.22916,6.89899 0.0117,2.54697 0.0234,5.09394 0.0352,7.64091 6.86463,2.8717 13.72924,5.74341 20.59384,8.61511 0.91009,-2.11486 1.82018,-4.22973 2.73027,-6.3446 -5.23684,-2.04024 -10.47368,-4.08049 -15.71053,-6.12073 0.75831,-0.31271 1.51662,-0.62542 2.27492,-0.93812 m -14.17992,-7.36348 c -0.76309,-1.65493 -1.52619,-3.30987 -2.28928,-4.9648 -6.839318,2.90343 -13.678633,5.80688 -20.517941,8.71032 0.01054,2.5462 0.02107,5.0924 0.03161,7.6386 6.860547,2.86946 13.721102,5.73892 20.581661,8.60838 0.90903,-2.11556 1.81807,-4.23112 2.72711,-6.34668 -5.23993,-2.04195 -10.47985,-4.08389 -15.719768,-6.12583 3.538493,-1.46115 7.076989,-2.9223 10.615478,-4.38345 m -9.578031,6.75815 c -0.379995,-0.14802 -0.759989,-0.29603 -1.139983,-0.44404 5.220982,-2.15291 10.441954,-4.30583 15.662924,-6.45875 -0.54602,-1.18498 -1.09203,-2.36995 -1.63805,-3.55493 m -30.759587,4.52156 c 2.327107,-4.2e-4 4.654213,-8.4e-4 6.981318,-0.001 4.72e-4,-2.42569 9.42e-4,-4.85139 0.0014,-7.27708 -5.608879,-0.001 -11.217765,-0.002 -16.826659,-0.003 4.62e-4,2.42483 9.24e-4,4.84967 0.0014,7.2745 5.611028,-9.8e-4 11.22205,-0.002 16.833063,-0.003 4.54e-4,-2.42568 9.07e-4,-4.85135 0.0014,-7.27703 -1.723988,-3e-4 -3.447976,-5.9e-4 -5.171966,-8.9e-4 m -2.024007,22.444 c 2.816132,-1e-5 5.632262,-2e-5 8.448391,-3e-5 4.56e-4,-2.64572 9.1e-4,-5.29144 0.0014,-7.93716 -5.637754,-2e-5 -11.275514,-5e-5 -16.913281,-7e-5 4.48e-4,2.6457 8.94e-4,5.29139 0.0013,7.93709 5.639668,-2e-5 11.279329,-5e-5 16.918984,-7e-5 4.39e-4,-2.64571 8.77e-4,-5.29143 0.0013,-7.93714 -0.03972,0 -0.07944,0 -0.119166,0 m 27.32549,-18.3087 -17.328906,7.36254 m 21.261656,1.45287 -0.93476,0.39715 m 0.92531,12.30443 14.19828,5.93971"+ id="text10004" />+ <path+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2a144d;stroke-width:0.46007127;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"+ d="m 115.22655,198.82177 c -2.33453,0.87014 -4.64195,1.77129 -6.92798,2.69686 1e-5,-0.001 -0.0471,7.64456 -0.0471,7.64318 2.40744,1.04231 4.78622,2.11139 7.12654,3.21253 m -3.89008,-11.93336 c -1.00663,0.39365 -2.00871,0.79253 -3.00671,1.19609 0,-9e-5 -0.0168,2.57292 -0.0168,2.57282 m 0.0857,-0.87568 c 10e-6,-4.6e-4 -0.0406,5.94694 -0.0406,5.94646 3.36011,1.45836 6.6636,2.96933 9.88376,4.5473 m -7.20478,-3.23662 c 5.79648,2.59181 11.3987,5.35494 16.66528,8.36545 0.32773,-0.6279 0.65819,-1.25494 0.99146,-1.88109 m -1.60443,1.53758 c 0.21377,0.12085 0.42701,0.24211 0.6397,0.36376 1.05492,-2.01971 2.13811,-4.03043 3.25201,-6.03131 -1.59952,-0.86761 -3.22505,-1.71188 -4.8732,-2.53483 m 0.29618,-0.0427 c -3.40715,-1.70793 -6.91152,-3.32401 -10.483,-4.86582 2.90365,-1.06488 5.84253,-2.0795 8.82804,-3.03035 m -4.30994,5.25285 c -1.44084,-0.66089 -2.89525,-1.30799 -4.36114,-1.9425 5.32305,-1.95032 10.76393,-3.73086 16.39321,-5.25805 -0.0526,-0.15243 -0.10543,-0.30483 -0.15839,-0.4572 m -16.346,5.71656 c -6e-5,-3e-5 -0.16464,-0.0711 -0.1647,-0.0711 5.32191,-1.95602 10.76115,-3.74365 16.38827,-5.27932 -0.64765,-1.86511 -1.31982,-3.72666 -2.01474,-5.58459 m -6.00177,7.65252 c 2.59724,-0.83545 5.22948,-1.62315 7.90424,-2.35414 -0.10412,-0.29859 -0.20887,-0.59709 -0.31423,-0.8955 m -0.14193,1.39572 c 0.18793,-0.052 0.37606,-0.10371 0.56441,-0.15515 -0.73132,-2.1078 -1.49395,-4.21107 -2.28537,-6.30972 -0.14277,0.0413 -0.28541,0.0828 -0.42792,0.12441 m 2.58573,5.86862 c -1e-5,0 0.0598,-0.0163 0.0598,-0.0163 -0.73446,-2.10743 -1.50012,-4.2103 -2.29447,-6.30856 -2.51058,0.72674 -4.98101,1.49943 -7.41727,2.31118 m 2.7274,-0.57192 c -5.49569,1.74707 -10.81091,3.70187 -16.01266,5.78726 m -0.10008,0.28407 c -0.1982,0.0796 -0.39625,0.15943 -0.59413,0.23942 0,-1.5e-4 -0.0188,2.695 -0.0188,2.69485 m -0.26343,-1.06335 c 0,-6.9e-4 -0.0362,5.97408 -0.0362,5.97348 4.5267,1.96098 8.95073,4.01666 13.20673,6.20223 m -1.19162,-0.94232 c 2.57116,1.29507 5.08466,2.63559 7.52645,4.02912 0.2451,-0.46951 0.49173,-0.93854 0.73992,-1.40707 m -3.71917,-0.16021 c 1.03465,0.56033 2.05792,1.12925 3.06882,1.7073 1.05517,-2.01991 2.13862,-4.0308 3.25279,-6.03186 -3.20163,-1.73679 -6.50739,-3.38013 -9.89002,-4.94595 m 0.73858,0.22701 c -2.02311,-0.94586 -4.0745,-1.86341 -6.14827,-2.75609 2.20426,-0.81044 4.42876,-1.59211 6.67851,-2.33909 m -1.44719,0.78416 c 3.68217,-1.25405 7.4293,-2.41757 11.26369,-3.46413 -0.62864,-1.81025 -1.28037,-3.61715 -1.95359,-5.42066 m 2.23455,5.42891 c 0,0 0.0174,-0.005 0.0174,-0.005 -0.72889,-2.1089 -1.48926,-4.21326 -2.27857,-6.31299 -3.40899,0.98048 -6.74388,2.04632 -10.0197,3.18021 m 11.03329,-0.34197 c -0.33808,-0.93185 -0.68206,-1.86279 -1.03172,-2.79283 -2.38449,0.68629 -4.73274,1.41434 -7.0499,2.17823 m 7.95135,0.32819 c -0.33935,-0.93163 -0.68458,-1.86236 -1.03546,-2.79218 -4.58328,1.32102 -9.03245,2.79572 -13.38399,4.38215 m 6.2801,-1.79408 c -1.65708,0.54838 -3.29832,1.11504 -4.92561,1.69781 m 3.20183,-1.43563 c -4.26843,1.45184 -8.43432,3.02127 -12.53045,4.67057 m -22.97746,-0.61053 c -0.854682,0.39452 -1.707863,0.7904 -2.559818,1.18742 -1.2e-5,-2.5e-4 0.117783,2.69178 0.117771,2.69152 m -0.268337,-2.29444 c -4e-6,0 -0.02307,0.0108 -0.02308,0.0108 -1.1e-4,-0.003 0.33467,7.63469 0.33456,7.63215 3.348442,1.24064 6.676356,2.49903 9.969061,3.78762 m -10.192384,-8.04094 c -2.8e-5,-6.9e-4 0.176276,4.01026 0.176248,4.00962 0.573877,0.21257 1.147161,0.42566 1.719779,0.63933 m -1.79414,-3.6187 c -1.4e-5,-2.3e-4 0.126798,2.89326 0.126782,2.89293 3.803508,1.40936 7.581027,2.84161 11.311057,4.315 m -11.501658,-5.89934 c -4e-6,-9e-5 0.06809,1.54588 0.06809,1.54578 4.990119,1.84741 9.935901,3.7339 14.788836,5.70061 m -12.821111,-5.12777 c 3.745274,1.39817 7.462077,2.82154 11.129754,4.28761 m -6.88663,-2.31774 c 3.011252,1.14993 5.998343,2.32071 8.950298,3.52165 1.133312,0.46173 2.261042,0.92737 3.382172,1.39749 m -9.790029,-4.2021 c 2.149828,0.83322 4.285773,1.67852 6.403797,2.53933 1.907982,0.77652 3.800322,1.5642 5.672182,2.36562 0.46253,-1.10901 0.92886,-2.21723 1.39934,-3.32452 m -6.232212,1.50664 c 1.556872,0.63838 3.102712,1.28447 4.634872,1.9397 0.88166,-2.11735 1.77703,-4.23184 2.68853,-6.34263 -0.61254,-0.24545 -1.2269,-0.48927 -1.84292,-0.73153 m -4.06553,5.7068 c -9e-5,-4e-5 0.16353,0.0679 0.16344,0.0679 m 0.0327,0.11268 c 1.03455,0.43018 2.06375,0.86401 3.08681,1.30192 m -2.3182,-0.91815 c 0.76015,0.31833 1.51729,0.63869 2.27109,0.96126 0.8812,-2.11731 1.7761,-4.23175 2.6871,-6.34251 -1.07693,-0.43177 -2.15952,-0.85847 -3.24694,-1.28059 m -0.79848,6.54886 c 0.57584,0.24283 1.14991,0.48687 1.72205,0.73222 0.88393,-2.11654 1.78182,-4.23012 2.69609,-6.3399 -2.85303,-1.14687 -5.74585,-2.25766 -8.6629,-3.34145 -0.878803,-0.32632 -1.759821,-0.65007 -2.642799,-0.97149 m 11.165339,4.97095 c -4e-5,9e-5 0.091,-0.21044 0.091,-0.21035 -2.83402,-1.13992 -5.7079,-2.24432 -8.60636,-3.32213 0,0 0,0 0,0 -4.6e-4,-1.5e-4 -0.366769,-0.1361 -0.367181,-0.13625 m 3.434061,1.21466 c -1.01916,-0.38852 -2.042074,-0.77332 -3.068051,-1.15478 -2.486904,-0.92406 -4.991852,-1.82752 -7.509019,-2.71568 0.829062,-0.36791 1.659434,-0.73416 2.49136,-1.09855 m 0.757017,2.04397 c -1.035358,-0.37277 -2.073205,-0.74255 -3.113132,-1.1097 2.413792,-1.07043 4.838848,-2.12667 7.281244,-3.164 1.533889,-0.65173 3.074841,-1.29637 4.624621,-1.93185 m -9.766347,6.08968 c -0.639713,-0.22895 -1.280335,-0.45681 -1.921771,-0.68365 0.812051,-0.35993 1.625365,-0.71824 2.440177,-1.07474 m -1.445123,0.25789 c 2.013297,-0.88721 4.035092,-1.76404 6.068896,-2.62776 1.427505,-0.60646 2.861118,-1.20679 4.302258,-1.7993 m -6.920229,3.15085 c 0.388763,-0.16799 0.777907,-0.33554 1.167461,-0.50263 m -0.853317,0.0623 c 0.765968,-0.33022 1.53347,-0.6587 2.302693,-0.98531 2.773222,-1.17798 5.569582,-2.33278 8.399432,-3.45216 -0.87864,-1.88537 -1.77123,-3.76736 -2.67569,-5.64593 m 1.76309,3.67895 c -0.61388,-1.30199 -1.23409,-2.60236 -1.85994,-3.90108 -1.41105,0.57981 -2.81257,1.16765 -4.205833,1.76203 m 5.026193,0.0549 c -0.27605,-0.57827 -0.55327,-1.15622 -0.83161,-1.73385 -1.25376,0.51547 -2.5,1.03727 -3.73965,1.56436 m 2.83755,-1.48965 c -1.54442,0.6398 -3.077627,1.28889 -4.601312,1.94531 m 1.201573,-0.32783 c -0.474262,0.2025 -0.94757,0.40576 -1.419976,0.60972 -4.914679,2.11735 -9.741183,4.30852 -14.528256,6.53678 m 16.826411,-7.45096 c -0.76819,0.32571 -1.533822,0.65348 -2.297101,0.98307 -3.24117,1.39662 -6.444057,2.82536 -9.622648,4.27567 m 7.852211,-3.474 c -3.117139,1.35987 -6.200983,2.7479 -9.264133,4.15461 m 9.009911,-4.25513 c -2.302633,1.00582 -4.587154,2.02686 -6.858643,3.05931 m 4.508413,-1.69638 c -3.57174,1.58495 -7.104087,3.20379 -10.616344,4.84198 -2.3e-5,-5.1e-4 0.161722,3.68636 0.161699,3.68584 m 0.201525,-4.18611 c -4.2e-5,2e-5 -0.08238,0.0384 -0.08242,0.0384 m 0.249474,0.18924 c -9.2e-4,4.4e-4 -0.389313,0.18139 -0.390267,0.18184 -3e-5,-6.7e-4 0.193575,4.4234 0.193547,4.42274 m 0.06248,-4.67199 c -1.7e-4,7e-5 -0.164222,0.0765 -0.164393,0.0766 -9.4e-5,-0.002 0.332519,7.63482 0.332427,7.63268 2.594887,0.96244 5.177421,1.93576 7.740766,2.92577 m -8.125629,-6.54994 c -2.5e-5,-4.6e-4 0.160641,3.66976 0.160618,3.6692 4.066678,1.50729 8.103281,3.04091 12.083516,4.62316 m -2.99684,-1.2604 c 1.529369,0.59494 3.051506,1.19616 4.564949,1.80488 m -3.344893,-1.26036 c 0.776458,0.30474 1.550935,0.61119 2.32324,0.91951 m -1.241217,-0.35875 c 1.195935,0.4731 2.386912,0.95046 3.572221,1.43269 1.840131,0.74969 3.665531,1.50974 5.471871,2.28248 0.822,-1.97423 1.6559,-3.94598 2.50368,-5.91456 m -11.121527,1.98454 c 1.05069,0.41661 2.097534,0.83657 3.140048,1.26028 1.965829,0.80009 3.915119,1.61201 5.842599,2.43862 0.44127,-1.057 0.88602,-2.11326 1.33455,-3.16868 m -9.552508,0.12237 c 0.79596,0.31766 1.589611,0.6373 2.38074,0.9591 1.914288,0.77978 3.812658,1.57076 5.690228,2.37559 0.88257,-2.11672 1.77896,-4.23052 2.69159,-6.34058 -1.36174,-0.54699 -2.73261,-1.08582 -4.1109,-1.61747 m 3.20992,1.00354 c -4.6e-4,-2.1e-4 -0.41393,-0.16425 -0.41444,-0.16445 m 0.0581,0.2923 c -2.38846,-0.94689 -4.80318,-1.86977 -7.235138,-2.77392 -2.430368,-0.903 -4.877973,-1.78633 -7.33738,-2.65492 -0.0031,0.001 0.836179,-0.36999 0.833122,-0.36863 m 11.056826,4.79542 c -1.08521,-0.41935 -2.17509,-0.83422 -3.268804,-1.2451 m 0.552314,-0.0558 c -0.611951,-0.23083 -1.225138,-0.46037 -1.839412,-0.68871 -2.397599,-0.89074 -4.811825,-1.76235 -7.237466,-2.61957 -0.0036,0.002 0.907279,-0.40118 0.903714,-0.3996 m 4.693778,2.54492 c -1.824261,-0.66932 -3.657459,-1.32826 -5.497316,-1.97887 1.167215,-0.51721 2.337056,-1.03107 3.510215,-1.54103 m -3.132218,1.53545 c -0.0021,-6.9e-4 -0.702658,-0.24839 -0.704659,-0.2491 2.444195,-1.08387 4.899913,-2.15325 7.373456,-3.20325 1.651238,-0.70123 3.310698,-1.39423 4.980548,-2.07644 m -2.03317,0.88961 c 1.81304,-0.75358 3.63737,-1.49555 5.47584,-2.22256 -0.2092,-0.44886 -0.4192,-0.89753 -0.62996,-1.34601 m 0.52067,0.71853 c -0.85056,-1.82046 -1.714,-3.63777 -2.58848,-5.45186 -1.96176,0.80486 -3.90498,1.6253 -5.833093,2.45734 -1.125801,0.48477 -2.246963,0.97342 -3.364066,1.46549 m -26.743025,7.15179 c 2.059712,-0.0964 0.572741,-0.0268 2.632452,-0.12318 m -2.374667,0.0391 c 3.988273,-0.18667 7.978754,-0.37463 11.971968,-0.54282 0,1e-5 -0.106426,-2.53116 -0.106426,-2.53115 m -10.549851,3.10776 c 2.511814,-0.11741 5.024455,-0.23441 7.538059,-0.34575 m -2.466268,-0.18978 c 1.855925,-0.0845 3.712463,-0.16687 5.569671,-0.24496 4.6e-4,0.0102 -0.306587,-7.27925 -0.306156,-7.26905 -1.51597,0.0638 -3.029675,0.13038 -4.54115,0.19859 m 0.519071,0.12322 c -1.688448,0.0755 -8.310835,0.38663 -9.999283,0.46211 m 8.229672,-0.20034 c -2.502666,0.11447 -7.305212,0.34259 -9.807878,0.45705 m 0.772856,-0.34604 c 0.09031,-0.004 -2.132148,0.0985 -2.041833,0.0943 -2.3e-4,-0.005 0.332597,7.2737 0.332362,7.26857 0.02374,-0.001 1.198389,-0.0549 1.222129,-0.056 m -0.04693,-7.07694 c 0.0466,-0.002 -1.592138,0.0732 -1.545538,0.0711 -2.25e-4,-0.005 0.331344,7.27291 0.331118,7.26792 0.04257,-0.002 1.586349,-0.073 1.628922,-0.0749 m -1.539587,-1.5644 c 0,0 0.07316,1.60165 0.07316,1.60165 0.05598,-0.003 1.772949,-0.0817 1.828928,-0.0843 m -1.921715,-0.31555 c 0,0 0.01902,0.41581 0.01902,0.41581 0.702064,-0.0321 5.140008,-0.2396 5.842074,-0.27172 m 4.725877,-0.27675 c 2.066675,-0.0948 4.134037,-0.18719 6.202159,-0.27432 4.6e-4,0.009 -0.306587,-7.27817 -0.306221,-7.26948 -2.339557,0.0984 -4.673816,0.20336 -7.002878,0.31075 m 7.058915,-0.16737 c -4.6931,0.19762 -9.365216,0.42182 -14.017203,0.63901 m 6.537511,-0.38739 c -0.971305,0.045 -4.569434,0.21391 -5.540739,0.25886 m 5.101201,-0.24571 c -5.216645,0.24225 -3.843468,0.18018 -9.06011,0.42243 -3.4e-5,-7.4e-4 0.123129,2.70558 0.123097,2.70486 m 7.426843,-3.24953 c -24.696934,1.15102 17.116174,-0.79865 -7.580762,0.35237 -2.3e-5,-4.8e-4 0.104089,2.27859 0.104066,2.2781 m 5.781832,-2.41986 c 2.637842,-0.12357 -8.440538,0.39347 -5.802694,0.2699 -2.3e-4,-0.005 0.331946,7.27375 0.331699,7.26835 1.524654,-0.0696 6.552862,-0.30601 8.077513,-0.37559 m -7.825568,0.35848 c 3.084591,-0.14101 7.08161,-0.33115 10.166201,-0.47216 m -2.201616,0.27963 c 2.955075,-0.13771 5.911325,-0.27295 8.868971,-0.39714 6.9e-4,0.0158 -0.276645,-6.60296 -0.275983,-6.58715 m -4.644838,19.50263 c -0.04853,0.002 1.943709,-0.0875 1.895186,-0.0853 m -1.936735,0.1142 c 1.792077,-0.0816 3.580063,-0.16108 5.364006,-0.23634 0.0016,0.0406 -0.334472,-7.97099 -0.33277,-7.93042 -1.663809,0.07 -3.328641,0.14352 -4.99454,0.21902 m 2.171407,7.93469 c 1.002125,-0.0446 2.002964,-0.0882 3.002526,-0.13056 6.9e-4,0.0151 -0.335332,-7.94584 -0.334692,-7.9307 -0.01302,4.6e-4 -1.283268,0.0548 -1.296293,0.0553 m 1.765494,6.57446 c 0,0 -0.09432,-2.24444 -0.09432,-2.24444 m 0.193403,1.55422 c 2.3e-4,0.008 -0.255952,-6.10558 -0.255618,-6.09764 -4.135875,0.1736 -8.27797,0.36923 -12.426879,0.56322 m 12.656588,5.47587 c 0.0014,0.0352 -0.196897,-4.70418 -0.195425,-4.669 m 0.05044,0.34855 c 7.3e-5,0.002 -0.08064,-1.92765 -0.08057,-1.92593 -2.430525,0.10176 -4.863062,0.21113 -7.297731,0.32331 m 2.088058,0.34949 c -3.929765,0.17863 -8.234153,0.3859 -12.163916,0.56453 -2.3e-4,-0.007 0.360901,7.93624 0.3606,7.92962 0.0133,-6.9e-4 0.959655,-0.0436 0.972954,-0.0442 m -1.147832,-4.57504 c -9e-5,-0.002 0.201748,4.43626 0.201661,4.4343 4.261743,-0.19359 8.13406,-0.38068 12.395803,-0.57426 m 2.714147,0.0438 c -0.03638,0.002 2.068462,-0.0889 2.032086,-0.0873 0,-1e-5 -0.330434,-7.848 -0.330434,-7.84802 m -0.390012,7.67174 c -0.006,2.3e-4 0.877945,-0.0373 0.871913,-0.037 0.0035,0.0846 -0.335601,-8.01541 -0.332058,-7.93079 -0.0049,2.1e-4 -0.807534,0.0341 -0.812456,0.0343 m 1.062674,4.39576 c 9.21e-4,0.0195 -0.180555,-4.31693 -0.17974,-4.29747 -5.644858,0.2368 -11.301805,0.51484 -16.97239,0.77385 m 16.883999,-0.84336 c 0,0 -0.0109,-0.25925 -0.0109,-0.25925 -2.055509,0.0861 -4.112471,0.17769 -6.170952,0.27176 m 3.485079,0.0291 c -0.05285,0.002 -2.212276,0.099 -2.26512,0.10135 m 0.349797,0.0794 c -3.760553,0.16942 -8.938361,0.41768 -12.698914,0.5871 -2.3e-4,-0.006 0.33907,7.46503 0.338819,7.45951 m 9.280111,-8.08922 c -5.88383,0.27258 -3.65478,0.17097 -9.538611,0.44355 -1.79e-4,-0.004 0.27812,6.1035 0.277943,6.09957 m 5.680987,-6.48244 c 2.157859,-0.10077 -8.201667,0.38044 -6.043811,0.27967 -2.3e-4,-0.007 0.361342,7.93519 0.361027,7.92831 0.01746,-6.9e-4 1.089212,-0.0498 1.10666,-0.0506 m -0.642245,-7.62892 c 0.0055,-2.3e-4 -0.59799,0.0273 -0.592459,0.027 -8.8e-5,-0.002 0.186492,4.0844 0.186404,4.0825 m -0.24246,-0.91094 c -9.4e-5,-0.002 0.205422,4.5051 0.205328,4.50301 0.02291,-0.001 1.239029,-0.0564 1.261934,-0.0575 m -0.07763,0.0678 c 4.16157,-0.19062 6.453312,-0.30131 10.614882,-0.49193 m -6.911472,0.22311 c 0.314236,-0.0147 1.410505,-0.066 1.724739,-0.0807 m -1.595265,0.30133 c 4.104645,-0.19166 8.18784,-0.38438 12.250149,-0.55525 2.3e-4,0.006 -0.205339,-4.89378 -0.205097,-4.88802 m 33.383164,-22.13887 c -5.49585,2.00143 -10.81413,4.16561 -16.02272,6.41445 -2.945114,1.26887 -5.858578,2.56425 -8.750882,3.87824 m 25.318552,-0.13017 c -0.44849,0.16829 -0.896,0.33771 -1.34256,0.50821 m -1.87856,11.0592 c 6.39169,2.87012 12.5429,5.95109 18.26331,9.34531"+ id="path10202" />+ <path+ id="path4728"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 111.80954,213.04909 c -0.26629,0.16448 -0.50119,0.30232 -0.6724,0.70346 -0.1712,0.40114 -0.10823,0.66612 -0.0428,0.97219 l 0.12706,-0.0258 c -0.0563,-0.29013 -0.0764,-0.51482 0.0782,-0.87703 0.15531,-0.3639 0.33078,-0.50311 0.57919,-0.66321 z" />+ <path+ id="path4730"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 112.44893,213.61011 c -0.26405,-0.1127 -0.57293,0.002 -0.74125,0.39595 -0.16759,0.39268 -0.0531,0.69166 0.22957,0.8123 0.1574,0.0672 0.29655,0.0506 0.38906,0.012 l -0.0362,-0.13551 c -0.087,0.0209 -0.17996,0.0372 -0.28998,-0.01 -0.18111,-0.0773 -0.26524,-0.26928 -0.12148,-0.6061 0.15025,-0.35206 0.34807,-0.40769 0.5241,-0.33256 0.0812,0.0347 0.14075,0.0921 0.18825,0.18244 l 0.13209,-0.0657 c -0.0613,-0.11423 -0.12691,-0.19023 -0.27416,-0.25307 z" />+ <path+ id="path4732"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 113.09042,213.59577 -0.12706,0.0258 c 0.0563,0.29012 0.0771,0.51313 -0.0782,0.87703 -0.15459,0.36221 -0.33078,0.50311 -0.57918,0.66321 l 0.0693,0.10959 c 0.26629,-0.16448 0.5012,-0.30232 0.67241,-0.70346 0.1712,-0.40114 0.10822,-0.66613 0.0428,-0.97219 z" />+ <path+ id="path4734"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 114.01162,214.30108 -0.24373,-0.10402 -0.49772,1.16618 0.27928,0.11919 c 0.25219,0.10764 0.59679,0.12065 0.79978,-0.35496 0.2066,-0.48407 -0.0397,-0.69924 -0.33761,-0.82639 z m -0.0194,0.14379 c 0.18619,0.0795 0.35432,0.21526 0.18601,0.60962 -0.16398,0.38422 -0.38001,0.38406 -0.5628,0.30604 l -0.13033,-0.0556 0.38864,-0.9106 z" />+ <path+ id="path4736"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 114.96573,216.0869 0.16926,0.0722 0.12536,-1.3251 -0.20311,-0.0867 -0.87179,1.00653 0.16249,0.0693 0.21299,-0.25525 0.44176,0.18854 z m -0.31025,-0.63263 0.44286,-0.53131 -0.079,0.68662 z" />+ <path+ id="path4738"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 116.5494,215.38421 -0.16249,-0.0693 -0.71613,0.86686 0.1305,-1.11681 -0.17264,-0.0737 -0.12197,1.32654 0.17264,0.0737 z" />+ <path+ id="path4740"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 116.89069,215.52987 -0.16079,-0.0686 -0.49773,1.16618 0.1608,0.0686 z" />+ <path+ id="path4742"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 117.4728,215.77831 -0.24373,-0.10402 -0.49772,1.16618 0.27928,0.11919 c 0.25219,0.10764 0.59679,0.12065 0.79978,-0.35496 0.2066,-0.48407 -0.0397,-0.69924 -0.33761,-0.82639 z m -0.0194,0.14379 c 0.18619,0.0795 0.35432,0.21526 0.18601,0.60962 -0.16398,0.38422 -0.38001,0.38406 -0.5628,0.30604 l -0.13033,-0.0556 0.38864,-0.9106 z" />+ <path+ id="path4744"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 118.7188,216.31011 -0.16079,-0.0686 -0.49773,1.16618 0.62118,0.26511 0.0785,-0.13255 -0.479,-0.20443 z" />+ <path+ id="path4746"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 120.03232,216.87072 -0.63133,-0.26946 -0.49773,1.16618 0.64488,0.27523 0.0549,-0.12863 -0.48408,-0.20661 0.17049,-0.39945 0.39267,0.1676 0.0549,-0.12864 -0.39267,-0.16759 0.16253,-0.38082 0.45192,0.19287 z" />+ <path+ id="path4748"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 120.99565,217.28186 -0.83274,-0.35541 -0.0585,0.13709 0.33175,0.14159 -0.43921,1.02909 0.1608,0.0686 0.43921,-1.02908 0.32328,0.13798 z" />+ <path+ id="path4750"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 121.8717,217.65576 -0.83275,-0.35541 -0.0585,0.13709 0.33174,0.14159 -0.43921,1.02908 0.16079,0.0686 0.43922,-1.02908 0.32327,0.13797 z" />+ <path+ id="path4752"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 122.21965,217.80427 -0.1608,-0.0686 -0.49772,1.16618 0.1608,0.0686 z" />+ <path+ id="path4754"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 123.18936,218.21814 -0.63133,-0.26945 -0.49772,1.16617 0.64487,0.27524 0.0549,-0.12864 -0.48407,-0.2066 0.17048,-0.39945 0.39268,0.16759 0.0549,-0.12863 -0.39268,-0.1676 0.16254,-0.38082 0.45192,0.19288 z" />+ <path+ id="path4756"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ d="m 123.58728,219.76657 0.19126,0.0816 -0.0916,-0.65737 c 0.18922,0.0207 0.31576,-0.0413 0.38583,-0.20548 0.0932,-0.21835 -0.0115,-0.39507 -0.30259,-0.51932 l -0.30636,-0.13075 -0.49772,1.16618 0.1608,0.0686 0.21093,-0.49422 0.18111,0.0773 z m -0.19671,-0.81427 0.18059,-0.42314 0.14387,0.0614 c 0.19127,0.0816 0.24892,0.17626 0.18679,0.32182 -0.0672,0.15742 -0.18628,0.17862 -0.34876,0.10927 z" />+ </g>+</svg>
+ src/data/fullscreen-icon.svg view
@@ -0,0 +1,147 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!-- Created with Inkscape (http://www.inkscape.org/) -->++<svg+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"+ width="15"+ height="15"+ viewBox="0 0 3.9687499 3.9687501"+ version="1.1"+ id="svg8"+ inkscape:version="0.92.2 2405546, 2018-03-11"+ sodipodi:docname="fullscreen-icon.svg">+ <defs+ id="defs2">+ <marker+ inkscape:isstock="true"+ style="overflow:visible;"+ id="marker23124"+ refX="0.0"+ refY="0.0"+ orient="auto"+ inkscape:stockid="Arrow2Send">+ <path+ transform="scale(0.3) rotate(180) translate(-2.3,0)"+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#ffffff;stroke-opacity:0.90196078;fill:#ffffff;fill-opacity:0.90196078"+ id="path23122" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Send"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow1Send"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path876"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#ffffff;stroke-width:1pt;stroke-opacity:0.90196078;fill:#ffffff;fill-opacity:0.90196078"+ transform="scale(0.2) rotate(180) translate(6,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Mend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow1Mend"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path870"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#ffffff;stroke-width:1pt;stroke-opacity:0.90196078;fill:#ffffff;fill-opacity:0.90196078"+ transform="scale(0.4) rotate(180) translate(10,0)" />+ </marker>+ </defs>+ <sodipodi:namedview+ id="base"+ pagecolor="#ff09e5"+ bordercolor="#666666"+ borderopacity="1.0"+ inkscape:pageopacity="0"+ inkscape:pageshadow="2"+ inkscape:zoom="22.627417"+ inkscape:cx="1.753672"+ inkscape:cy="12.195151"+ inkscape:document-units="px"+ inkscape:current-layer="layer1"+ showgrid="true"+ units="px"+ inkscape:measure-start="30,0"+ inkscape:measure-end="30,15"+ showguides="true"+ inkscape:guide-bbox="true"+ inkscape:window-width="1920"+ inkscape:window-height="1152"+ inkscape:window-x="0"+ inkscape:window-y="320"+ inkscape:window-maximized="1"+ inkscape:snap-global="false"+ inkscape:showpageshadow="false">+ <inkscape:grid+ type="xygrid"+ id="grid815" />+ <sodipodi:guide+ position="8.9958331,3.9687501"+ orientation="0,1"+ id="guide819"+ inkscape:locked="false" />+ <sodipodi:guide+ position="-3.9563476,0.73793947"+ orientation="0.70710678,0.70710678"+ id="guide23230"+ inkscape:locked="false" />+ <sodipodi:guide+ position="3.4106445,3.3072918"+ orientation="0.70710678,0.70710678"+ id="guide23301"+ inkscape:locked="false" />+ </sodipodi:namedview>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ inkscape:label="Layer 1"+ inkscape:groupmode="layer"+ id="layer1"+ transform="translate(0,-293.03123)">+ <g+ id="g23222"+ transform="matrix(1.0883098,0,0,1.1013122,4.8677154,-29.842988)">+ <path+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:0.90196078;fill-rule:evenodd;stroke:none;stroke-width:0.5291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1107.35998535;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"+ d="m -1.390625,293.46289 c -0.068648,0.002 -0.1651221,-1.7e-4 -0.2129795,0.0491 l -2.4429613,2.66237 c -0.2649166,0.24991 -0.034758,0.47803 0.2137696,0.21181 l 2.6583225,-2.45139 c 0.1715018,-0.16871 0.02432,-0.47898 -0.2161513,-0.4719 z"+ id="path23120"+ inkscape:connector-curvature="0"+ sodipodi:nodetypes="ccccccc" />+ <path+ id="path23228"+ style="fill:#ffffff;fill-opacity:0.90196078;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.09921876;stroke-linejoin:round;stroke-opacity:0.90196078"+ d="m -2.5582351,293.9976 1.67746674,-0.77547 -0.77546234,1.67747 c -0.070334,-0.46221 -0.4357684,-0.82538 -0.9020044,-0.902 z"+ inkscape:connector-curvature="0" />+ <path+ inkscape:connector-curvature="0"+ d="m -3.2578843,296.30294 -1.1648365,0.42381 0.4983491,-1.07802 c 0.0452,0.29704 0.3668619,0.60497 0.6664874,0.65421 z"+ style="fill:#ffffff;fill-opacity:0.90196078;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.09921876;stroke-linejoin:round;stroke-opacity:0.90196078"+ id="path23232"+ sodipodi:nodetypes="cccc" />+ </g>+ </g>+</svg>
src/data/gui.glade view
@@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?>-<!-- Generated with glade 3.20.0 +<!-- Generated with glade 3.20.4 Copyright (c) 2017 David Lettier All rights reserved.@@ -31,15 +31,16 @@ --> <interface> <requires lib="gtk+" version="3.10"/>+ <!-- interface-css-provider-path style.css --> <!-- interface-license-type bsd3c --> <!-- interface-name Movie Monad -->- <!-- interface-description A free and simple to use video player built with Haskell. -->+ <!-- interface-description A free and simple to use video player made with Haskell. --> <!-- interface-copyright 2017 David Lettier --> <!-- interface-authors David Lettier --> <object class="GtkImage" id="about-image"> <property name="visible">True</property> <property name="can_focus">False</property>- <property name="stock">gtk-dialog-question</property>+ <property name="pixbuf">about-icon.svg</property> </object> <object class="GtkButton" id="file-chooser-cancel-button"> <property name="label">gtk-cancel</property>@@ -60,30 +61,38 @@ <object class="GtkImage" id="fullscreen-image"> <property name="visible">True</property> <property name="can_focus">False</property>- <property name="stock">gtk-fullscreen</property>+ <property name="pixbuf">fullscreen-icon.svg</property> </object> <object class="GtkImage" id="pause-image">+ <property name="name">pause-image</property> <property name="visible">True</property> <property name="can_focus">False</property>- <property name="stock">gtk-media-pause</property>+ <property name="pixbuf">pause-icon.svg</property> </object> <object class="GtkImage" id="play-image">+ <property name="name">play-image</property> <property name="visible">True</property> <property name="can_focus">False</property>- <property name="stock">gtk-media-play</property>+ <property name="pixbuf">play-icon.svg</property> </object>+ <object class="GtkImage" id="repeat-check-button-image">+ <property name="visible">True</property>+ <property name="can_focus">False</property>+ <property name="pixbuf">repeat-icon.svg</property>+ </object> <object class="GtkAdjustment" id="seek-scale-adjustment"> <property name="upper">100</property> <property name="step_increment">1</property> <property name="page_increment">10</property> </object> <object class="GtkWindow" id="window">+ <property name="width_request">448</property> <property name="can_focus">True</property> <property name="title" translatable="yes">Movie Monad</property> <property name="window_position">center</property> <property name="default_width">800</property> <property name="default_height">600</property>- <property name="icon">movie-monad-icon.png</property>+ <property name="icon">movie-monad-icon.svg</property> <property name="gravity">center</property> <child> <object class="GtkBox" id="box-1">@@ -91,70 +100,69 @@ <property name="can_focus">False</property> <property name="orientation">vertical</property> <child>- <object class="GtkBox" id="box-2">+ <object class="GtkButton" id="file-chooser-button"> <property name="visible">True</property>- <property name="can_focus">False</property>+ <property name="app_paintable">True</property>+ <property name="can_focus">True</property>+ <property name="receives_default">True</property>+ <property name="tooltip_text" translatable="yes">Load a Video</property>+ <property name="valign">start</property> <property name="hexpand">True</property>- <property name="vexpand">True</property>- <property name="orientation">vertical</property>+ <property name="relief">half</property>+ <property name="image_position">right</property>+ <property name="always_show_image">True</property> <child>- <object class="GtkButton" id="file-chooser-button">+ <object class="GtkBox" id="box-2"> <property name="visible">True</property>- <property name="app_paintable">True</property>- <property name="can_focus">True</property>- <property name="receives_default">True</property>- <property name="tooltip_text" translatable="yes">Open a video file</property>- <property name="valign">start</property>- <property name="hexpand">True</property>- <property name="relief">half</property>- <property name="image_position">right</property>- <property name="always_show_image">True</property>+ <property name="can_focus">False</property> <child>- <object class="GtkBox" id="box-3">+ <object class="GtkLabel" id="file-chooser-button-label"> <property name="visible">True</property> <property name="can_focus">False</property>- <child>- <object class="GtkLabel" id="file-chooser-button-label">- <property name="visible">True</property>- <property name="can_focus">False</property>- <property name="label" translatable="yes">Open</property>- <property name="justify">fill</property>- <property name="ellipsize">end</property>- <property name="single_line_mode">True</property>- </object>- <packing>- <property name="expand">True</property>- <property name="fill">True</property>- <property name="position">0</property>- </packing>- </child>- <child>- <object class="GtkImage" id="open-image">- <property name="visible">True</property>- <property name="can_focus">False</property>- <property name="stock">gtk-open</property>- </object>- <packing>- <property name="expand">False</property>- <property name="fill">False</property>- <property name="pack_type">end</property>- <property name="position">2</property>- </packing>- </child>+ <property name="label" translatable="yes">Open</property>+ <property name="justify">fill</property>+ <property name="ellipsize">end</property>+ <property name="single_line_mode">True</property> </object>+ <packing>+ <property name="expand">True</property>+ <property name="fill">True</property>+ <property name="position">0</property>+ </packing> </child>+ <child>+ <object class="GtkImage" id="open-image">+ <property name="visible">True</property>+ <property name="can_focus">False</property>+ <property name="stock">gtk-open</property>+ </object>+ <packing>+ <property name="expand">False</property>+ <property name="fill">False</property>+ <property name="pack_type">end</property>+ <property name="position">2</property>+ </packing>+ </child> </object>- <packing>- <property name="expand">False</property>- <property name="fill">False</property>- <property name="position">0</property>- </packing> </child>+ </object>+ <packing>+ <property name="expand">False</property>+ <property name="fill">False</property>+ <property name="position">1</property>+ </packing>+ </child>+ <child>+ <object class="GtkOverlay" id="video-overlay">+ <property name="visible">True</property>+ <property name="can_focus">False</property>+ <property name="hexpand">True</property>+ <property name="vexpand">True</property> <child> <object class="GtkBox" id="video-widget-box"> <property name="visible">True</property> <property name="app_paintable">True</property>- <property name="can_focus">True</property>+ <property name="can_focus">False</property> <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="orientation">vertical</property>@@ -163,34 +171,32 @@ </child> </object> <packing>- <property name="expand">True</property>- <property name="fill">True</property>- <property name="position">1</property>+ <property name="index">-1</property> </packing> </child>- <child>+ <child type="overlay"> <object class="GtkBox" id="bottom-controls-gtk-box">+ <property name="name">bottom-controls-gtk-box</property>+ <property name="width_request">400</property> <property name="visible">True</property> <property name="can_focus">False</property>+ <property name="halign">center</property> <property name="valign">end</property>+ <property name="margin_bottom">10</property> <property name="orientation">vertical</property> <property name="baseline_position">bottom</property> <child> <object class="GtkScale" id="seek-scale">+ <property name="name">seek-scale</property> <property name="visible">True</property>- <property name="app_paintable">True</property>- <property name="can_focus">False</property>- <property name="valign">end</property>+ <property name="can_focus">True</property>+ <property name="valign">center</property> <property name="margin_left">5</property> <property name="margin_right">5</property>- <property name="hexpand">True</property>+ <property name="margin_top">5</property> <property name="adjustment">seek-scale-adjustment</property> <property name="show_fill_level">True</property> <property name="fill_level">100</property>- <property name="round_digits">0</property>- <property name="digits">-1</property>- <property name="draw_value">False</property>- <property name="value_pos">left</property> </object> <packing> <property name="expand">False</property>@@ -199,22 +205,25 @@ </packing> </child> <child>- <object class="GtkBox" id="box-4">+ <object class="GtkBox" id="box-3">+ <property name="name">box-3</property> <property name="visible">True</property> <property name="can_focus">False</property>- <property name="valign">end</property>+ <property name="valign">center</property>+ <property name="margin_left">5</property>+ <property name="margin_right">5</property> <property name="margin_top">5</property> <property name="margin_bottom">5</property>- <property name="hexpand">True</property>+ <property name="spacing">2</property> <child> <object class="GtkButton" id="play-pause-button">+ <property name="name">play-pause-button</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property>- <property name="tooltip_text" translatable="yes">Click to play</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property>+ <property name="tooltip_text" translatable="yes">Click to Play</property> <property name="image">play-image</property>+ <property name="relief">none</property> <property name="always_show_image">True</property> </object> <packing>@@ -224,16 +233,31 @@ </packing> </child> <child>+ <object class="GtkCheckButton" id="repeat-check-button">+ <property name="name">repeat-check-button</property>+ <property name="visible">True</property>+ <property name="can_focus">True</property>+ <property name="receives_default">False</property>+ <property name="tooltip_text" translatable="yes">Toggle Repeat On or Off</property>+ <property name="image">repeat-check-button-image</property>+ <property name="always_show_image">True</property>+ <property name="draw_indicator">False</property>+ </object>+ <packing>+ <property name="expand">False</property>+ <property name="fill">True</property>+ <property name="position">1</property>+ </packing>+ </child>+ <child> <object class="GtkVolumeButton" id="volume-button">+ <property name="name">volume-button</property> <property name="visible">True</property>- <property name="app_paintable">True</property> <property name="can_focus">True</property> <property name="focus_on_click">False</property> <property name="receives_default">True</property> <property name="double_buffered">False</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property>- <property name="relief">half</property>+ <property name="relief">none</property> <property name="orientation">vertical</property> <property name="value">0.5</property> <property name="size">button</property>@@ -242,7 +266,8 @@ audio-volume-low-symbolic audio-volume-medium-symbolic</property> <child internal-child="plus_button">- <object class="GtkButton" id="volume-up-button">+ <object class="GtkButton" id="volume-plus-button">+ <property name="name">volume-plus-button</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="halign">center</property>@@ -251,7 +276,8 @@ </object> </child> <child internal-child="minus_button">- <object class="GtkButton" id="volume-down-button">+ <object class="GtkButton" id="volume-minus-button">+ <property name="name">volume-minus-button</property> <property name="can_focus">True</property> <property name="receives_default">True</property> <property name="halign">center</property>@@ -263,22 +289,21 @@ <packing> <property name="expand">False</property> <property name="fill">False</property>- <property name="position">1</property>+ <property name="position">2</property> </packing> </child> <child>- <object class="GtkComboBoxText" id="video-width-selection-combo-box">+ <object class="GtkComboBoxText" id="window-width-selection-combo-box-text">+ <property name="name">window-width-selection-combo-box-text</property> <property name="visible">True</property>- <property name="app_paintable">True</property>- <property name="can_focus">False</property>- <property name="tooltip_text" translatable="yes">Set the window width</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property>+ <property name="can_focus">True</property>+ <property name="focus_on_click">False</property>+ <property name="tooltip_text" translatable="yes">Set the Window Width</property> <property name="active">1</property> <property name="has_frame">False</property> <property name="active_id">800</property> <items>- <item id="320" translatable="yes">320</item>+ <item id="448" translatable="yes">448</item> <item id="800" translatable="yes">800</item> <item id="1024" translatable="yes">1024</item> <item id="1152" translatable="yes">1152</item>@@ -298,15 +323,15 @@ <packing> <property name="expand">False</property> <property name="fill">False</property>- <property name="position">2</property>+ <property name="position">3</property> </packing> </child> <child>- <object class="GtkComboBoxText" id="subtitle-selection-combo-box">- <property name="can_focus">False</property>- <property name="tooltip_text" translatable="yes">Select the subtitle language</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property>+ <object class="GtkComboBoxText" id="subtitle-selection-combo-box-text">+ <property name="name">subtitle-selection-combo-box-text</property>+ <property name="can_focus">True</property>+ <property name="focus_on_click">False</property>+ <property name="tooltip_text" translatable="yes">Select the Subtitle Language</property> <property name="active_id">-1</property> <items> <item id="-1" translatable="yes">None</item>@@ -315,58 +340,53 @@ <packing> <property name="expand">False</property> <property name="fill">True</property>- <property name="position">3</property>+ <property name="position">4</property> </packing> </child> <child> <object class="GtkButton" id="fullscreen-button">- <property name="app_paintable">True</property>- <property name="can_focus">False</property>+ <property name="name">fullscreen-button</property>+ <property name="can_focus">True</property> <property name="receives_default">False</property>- <property name="tooltip_text" translatable="yes">Toggle on or off fullscreen</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property>+ <property name="tooltip_text" translatable="yes">Toggle On or Off Fullscreen</property> <property name="image">fullscreen-image</property>- <property name="relief">half</property>+ <property name="relief">none</property> <property name="always_show_image">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property>- <property name="position">4</property>+ <property name="position">5</property> </packing> </child> <child> <object class="GtkSpinner" id="buffering-spinner"> <property name="sensitive">False</property>- <property name="app_paintable">True</property> <property name="can_focus">False</property>- <property name="margin_left">5</property> </object> <packing> <property name="expand">False</property> <property name="fill">False</property>- <property name="position">5</property>+ <property name="position">6</property> </packing> </child> <child> <object class="GtkButton" id="about-button">+ <property name="name">about-button</property> <property name="visible">True</property>- <property name="app_paintable">True</property>- <property name="can_focus">False</property>+ <property name="can_focus">True</property>+ <property name="focus_on_click">False</property> <property name="receives_default">False</property> <property name="tooltip_text" translatable="yes">About Movie Monad</property>- <property name="margin_left">5</property>- <property name="margin_right">5</property> <property name="image">about-image</property>- <property name="relief">half</property>+ <property name="relief">none</property> <property name="always_show_image">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> <property name="pack_type">end</property>- <property name="position">6</property>+ <property name="position">7</property> </packing> </child> </object>@@ -378,17 +398,15 @@ </child> </object> <packing>- <property name="expand">False</property>- <property name="fill">False</property>- <property name="pack_type">end</property>- <property name="position">3</property>+ <property name="pass_through">True</property> </packing> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property>- <property name="position">0</property>+ <property name="pack_type">end</property>+ <property name="position">2</property> </packing> </child> </object>@@ -408,7 +426,7 @@ <property name="transient_for">window</property> <property name="attached_to">window</property> <property name="program_name">Movie Monad</property>- <property name="version">0.0.4.0</property>+ <property name="version">0.0.5.0</property> <property name="copyright" translatable="yes">(C) 2017 David Lettier lettier.com</property> <property name="website">https://github.com/lettier/movie-monad</property>@@ -446,7 +464,7 @@ <property name="logo">movie-monad-logo.svg</property> <property name="license_type">custom</property> <child internal-child="vbox">- <object class="GtkBox" id="box-5">+ <object class="GtkBox" id="box-4"> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property>@@ -486,7 +504,7 @@ Thank you.</property> <property name="secondary_use_markup">True</property> <child internal-child="vbox">- <object class="GtkBox" id="box-6">+ <object class="GtkBox" id="box-5"> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property>@@ -514,7 +532,7 @@ <property name="type_hint">dialog</property> <property name="transient_for">window</property> <child internal-child="vbox">- <object class="GtkBox" id="box-7">+ <object class="GtkBox" id="box-6"> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property>@@ -541,7 +559,7 @@ <object class="GtkEntry" id="file-chooser-entry"> <property name="visible">True</property> <property name="can_focus">True</property>- <property name="tooltip_text" translatable="yes">Type in the path to a local file or URL</property>+ <property name="tooltip_text" translatable="yes">Type in a File Path or a URL</property> <property name="has_frame">False</property> <property name="truncate_multiline">True</property> <property name="primary_icon_stock">gtk-edit</property>
− src/data/movie-monad-icon.png
binary file changed (24223 → absent bytes)
+ src/data/movie-monad-icon.svg view
@@ -0,0 +1,267 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<svg+ xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:xlink="http://www.w3.org/1999/xlink"+ id="svg8"+ version="1.1"+ viewBox="0 0 74.20314 74.20314"+ height="74.20314mm"+ width="74.20314mm">+ <defs+ id="defs2">+ <linearGradient+ id="linearGradient5445">+ <stop+ id="stop5441"+ offset="0"+ style="stop-color:#57ace3;stop-opacity:1;" />+ <stop+ id="stop5443"+ offset="1"+ style="stop-color:#57ace3;stop-opacity:0;" />+ </linearGradient>+ <marker+ style="overflow:visible"+ id="Arrow1Mend"+ refX="0"+ refY="0"+ orient="auto">+ <path+ transform="matrix(-0.4,0,0,-0.4,-4,0)"+ style="fill:#57ace3;fill-opacity:1;fill-rule:evenodd;stroke:#57ace3;stroke-width:1.00000003pt;stroke-opacity:1"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ id="path10335" />+ </marker>+ <marker+ style="overflow:visible"+ id="marker10589"+ refX="0"+ refY="0"+ orient="auto">+ <path+ transform="matrix(0.8,0,0,0.8,10,0)"+ style="fill:#57ace3;fill-opacity:1;fill-rule:evenodd;stroke:#57ace3;stroke-width:1.00000003pt;stroke-opacity:1"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ id="path10326" />+ </marker>+ <linearGradient+ id="linearGradient10200">+ <stop+ style="stop-color:#57ace3;stop-opacity:1"+ offset="0"+ id="stop10196" />+ <stop+ style="stop-color:#e0437f;stop-opacity:0.89019608"+ offset="1"+ id="stop10198" />+ </linearGradient>+ <linearGradient+ osb:paint="solid"+ id="linearGradient8935">+ <stop+ id="stop8933"+ offset="0"+ style="stop-color:#373737;stop-opacity:1;" />+ </linearGradient>+ <linearGradient+ id="linearGradient5282">+ <stop+ id="stop5278"+ offset="0"+ style="stop-color:#814dd2;stop-opacity:1;" />+ <stop+ id="stop5280"+ offset="1"+ style="stop-color:#b46bd3;stop-opacity:0.89019608" />+ </linearGradient>+ <marker+ style="overflow:visible"+ id="Arrow1Lend"+ refX="0"+ refY="0"+ orient="auto">+ <path+ transform="matrix(-0.8,0,0,-0.8,-10,0)"+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ id="path4997" />+ </marker>+ <marker+ style="overflow:visible"+ id="Arrow1Lstart"+ refX="0"+ refY="0"+ orient="auto">+ <path+ transform="matrix(0.8,0,0,0.8,10,0)"+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt"+ d="M 0,0 5,-5 -12.5,0 5,5 Z"+ id="path4994" />+ </marker>+ <linearGradient+ gradientUnits="userSpaceOnUse"+ y2="53.285694"+ x2="-64.290207"+ y1="53.642838"+ x1="-119.13808"+ id="linearGradient5284"+ xlink:href="#linearGradient5282" />+ <linearGradient+ y2="55.071407"+ x2="-58.218777"+ y1="53.642838"+ x1="-119.13808"+ gradientUnits="userSpaceOnUse"+ id="linearGradient5300"+ xlink:href="#linearGradient5282" />+ <linearGradient+ y2="55.071407"+ x2="-58.218777"+ y1="53.642838"+ x1="-119.13808"+ gradientUnits="userSpaceOnUse"+ id="linearGradient5352"+ xlink:href="#linearGradient5282" />+ <linearGradient+ y2="53.285694"+ x2="-64.290207"+ y1="53.642838"+ x1="-119.13808"+ gradientUnits="userSpaceOnUse"+ id="linearGradient5354"+ xlink:href="#linearGradient5282" />+ <linearGradient+ gradientTransform="matrix(1.1521699,0,0,1.1943224,-10.9053,-54.269335)"+ gradientUnits="userSpaceOnUse"+ y2="250.69791"+ x2="128.98438"+ y1="250.69791"+ x1="61.251041"+ id="linearGradient5260"+ xlink:href="#linearGradient10200" />+ <clipPath+ id="clipPath5388"+ clipPathUnits="userSpaceOnUse">+ <g+ id="g5394">+ <path+ id="path5390"+ d="m 125.5315,249.78764 c -3.34965,-1.30393 -6.69931,-2.60787 -10.04896,-3.9118 5.21848,-2.15262 10.43696,-4.30525 15.65545,-6.45787 -0.92835,-2.01253 -1.85669,-4.02505 -2.78504,-6.03758 -6.83922,2.90641 -13.67843,5.81282 -20.51763,8.71921 0.0104,2.54721 0.0208,5.09442 0.0312,7.64163 6.86079,2.8724 13.7216,5.74479 20.58242,8.61717 0.90892,-2.11466 1.81783,-4.22931 2.72675,-6.34397 -1.76975,-0.68894 -3.53951,-1.37789 -5.30926,-2.06683 m -2.62477,-4.90221 c 3.04901,-1.25752 6.09801,-2.51505 9.14702,-3.77257 -0.92751,-2.01274 -1.85501,-4.02549 -2.78252,-6.03823 -2.59416,1.10259 -5.18831,2.20519 -7.78247,3.30778 m 5.56493,-1.53082 c -5.40972,2.29966 -10.81943,4.59932 -16.22916,6.89899 0.0117,2.54697 0.0234,5.09394 0.0352,7.64091 6.86463,2.8717 13.72924,5.74341 20.59384,8.61511 0.91009,-2.11486 1.82018,-4.22973 2.73027,-6.3446 -5.23684,-2.04024 -10.47368,-4.08049 -15.71053,-6.12073 0.75831,-0.31271 1.51662,-0.62542 2.27492,-0.93812 m -14.17992,-7.36348 c -0.76309,-1.65493 -1.52619,-3.30987 -2.28928,-4.9648 -6.839321,2.90343 -13.678636,5.80688 -20.517944,8.71032 0.01054,2.5462 0.02107,5.0924 0.03161,7.6386 6.860547,2.86946 13.721102,5.73892 20.581665,8.60838 0.90903,-2.11556 1.81807,-4.23112 2.72711,-6.34668 -5.23993,-2.04195 -10.479854,-4.08389 -15.719772,-6.12583 3.538493,-1.46115 7.076989,-2.9223 10.615482,-4.38345 m -9.578035,6.75815 c -0.379995,-0.14802 -0.759989,-0.29603 -1.139983,-0.44404 5.220982,-2.15291 10.441958,-4.30583 15.662928,-6.45875 -0.54602,-1.18498 -1.09203,-2.36995 -1.63805,-3.55493 m -30.759591,4.52156 c 2.327107,-4.2e-4 4.654213,-8.4e-4 6.981318,-0.001 4.72e-4,-2.42569 9.42e-4,-4.85139 0.0014,-7.27708 -5.608879,-0.001 -11.217765,-0.002 -16.826659,-0.003 4.62e-4,2.42483 9.24e-4,4.84967 0.0014,7.2745 5.611028,-9.8e-4 11.22205,-0.002 16.833063,-0.003 4.54e-4,-2.42568 9.07e-4,-4.85135 0.0014,-7.27703 -1.723988,-3e-4 -3.447976,-5.9e-4 -5.171966,-8.9e-4 m -2.024007,22.444 c 2.816132,-1e-5 5.632262,-2e-5 8.448391,-3e-5 4.56e-4,-2.64572 9.1e-4,-5.29144 0.0014,-7.93716 -5.637754,-2e-5 -11.275514,-5e-5 -16.913281,-7e-5 4.48e-4,2.6457 8.94e-4,5.29139 0.0013,7.93709 5.639668,-2e-5 11.279329,-5e-5 16.918984,-7e-5 4.39e-4,-2.64571 8.77e-4,-5.29143 0.0013,-7.93714 -0.03972,0 -0.07944,0 -0.119166,0 m 27.325498,-18.3087 -17.328914,7.36254 m 21.261664,1.45287 -0.93476,0.39715 m 0.9253,12.30443 14.19828,5.93971"+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.23003563;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />+ <path+ transform="matrix(0.23003563,0,0,0.23003563,-34.32847,220.35427)"+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke"+ d="m 650.1385,82.874465 c -10.14856,3.782654 -20.17926,7.700083 -30.11698,11.72366 3e-5,-0.006 -0.20482,33.232065 -0.20478,33.226075 10.46549,4.53108 20.80642,9.17856 30.98016,13.96537 M 633.88611,89.913445 c -4.37599,1.711249 -8.73217,3.445238 -13.07064,5.199586 10e-6,-4.22e-4 -0.0731,11.184859 -0.0731,11.184439 m 0.3725,-3.80674 c 2e-5,-0.002 -0.17666,25.85227 -0.17665,25.8502 14.60689,6.33968 28.96767,12.90811 42.96621,19.76778 m -31.32028,-14.07007 c 25.19819,11.26699 49.55187,23.27873 72.44648,36.3659 1.42471,-2.72961 2.86128,-5.45544 4.31003,-8.17738 m -6.9747,6.68407 c 0.92932,0.52537 1.85629,1.05248 2.78088,1.58133 4.58589,-8.78001 9.29471,-17.52088 14.13698,-26.21901 -6.95333,-3.77163 -14.01978,-7.44184 -21.18454,-11.01929 m 1.28755,-0.18569 c -14.81139,-7.42465 -30.04545,-14.44997 -45.57119,-21.15245 12.62262,-4.62919 25.39834,-9.03993 38.37684,-13.17341 m -18.736,22.83496 c -6.26352,-2.87301 -12.58606,-5.68603 -18.95852,-8.44437 23.14013,-8.47831 46.79246,-16.218619 71.2638,-22.85755 -0.22881,-0.662606 -0.45833,-1.325109 -0.68856,-1.987508 M 654.01463,113.139 c -2.7e-4,-1.2e-4 -0.7157,-0.30906 -0.71597,-0.30917 23.13517,-8.5031 46.78037,-16.274199 71.2423,-22.950019 -2.81543,-8.107892 -5.73743,-16.200324 -8.75838,-24.277065 m -26.0906,33.266668 C 700.9826,95.2376 712.42531,91.81337 724.05294,88.63561 723.6003,87.337599 723.14495,86.039985 722.6869,84.742768 m -0.61698,6.067377 c 0.81695,-0.226028 1.6348,-0.450842 2.45357,-0.674428 -3.17915,-9.162957 -6.49443,-18.306184 -9.93482,-27.429347 -0.62065,0.179639 -1.24074,0.359926 -1.86026,0.540855 m 11.24057,25.511777 c -3e-5,7e-6 0.25989,-0.07102 0.25987,-0.07101 -3.19279,-9.161294 -6.52126,-18.302817 -9.97442,-27.424233 -10.91387,3.159213 -21.65318,6.518244 -32.24401,10.04705 m 11.85645,-2.486221 c -23.89063,7.594747 -46.99669,16.092552 -69.6095,25.158099 m -0.43504,1.234896 c -0.86163,0.346106 -1.72255,0.693034 -2.58277,1.040765 0,-6.34e-4 -0.0817,11.715584 -0.0816,11.714954 m -1.1452,-4.62256 c 2e-5,-0.003 -0.15748,25.97022 -0.15747,25.96764 19.67826,8.52466 38.91018,17.46103 57.41168,26.96201 m -5.18017,-4.09637 c 11.17724,5.62986 22.1038,11.4573 32.71864,17.51516 1.06549,-2.04103 2.13762,-4.07996 3.21651,-6.11673 m -16.16776,-0.69646 c 4.49775,2.43586 8.94607,4.90905 13.34063,7.42189 4.58695,-8.78083 9.2969,-17.5225 14.14034,-26.22142 -13.91794,-7.55008 -28.28862,-14.69392 -42.99342,-21.50079 m 3.21074,0.98686 c -8.79479,-4.11181 -17.71249,-8.10054 -26.7275,-11.98114 9.58226,-3.52312 19.25253,-6.92117 29.03252,-10.1684 m -6.29117,3.40887 c 16.00699,-5.451544 32.29632,-10.509546 48.965,-15.059102 -2.7328,-7.869445 -5.56598,-15.724327 -8.49254,-23.564436 m 9.71391,23.600286 c 0,0 0.0757,-0.02053 0.0757,-0.02053 -3.16863,-9.16775 -6.47406,-18.315717 -9.90529,-27.443567 -14.81942,4.262317 -29.3167,8.895683 -43.55719,13.824889 m 47.96342,-1.486613 c -1.4697,-4.050884 -2.96505,-8.097851 -4.48508,-12.14087 -10.36572,2.9834 -20.57391,6.148352 -30.64696,9.469099 m 34.56573,1.426708 c -1.47522,-4.049947 -2.97598,-8.095973 -4.5013,-12.138051 -19.92422,5.742688 -39.26545,12.153458 -58.18225,19.049877 m 27.30054,-7.799146 c -7.20357,2.383909 -14.33829,4.847277 -21.41236,7.380658 m 13.91885,-6.240903 c -18.55555,6.311359 -36.66528,13.133939 -54.4718,20.303685 M 522.52817,91.33976 c -3.71543,1.71506 -7.42434,3.436 -11.12792,5.16192 -5e-5,-0.0011 0.51202,11.70155 0.51197,11.70043 m -1.1665,-9.974259 c -2e-5,7e-6 -0.1003,0.04677 -0.10032,0.04678 -4.8e-4,-0.01106 1.45486,33.189163 1.45438,33.178103 14.55619,5.39325 29.02314,10.86367 43.33703,16.46536 m -44.30747,-34.95594 c -1.2e-4,-0.003 0.7663,17.43323 0.76618,17.43044 2.49473,0.92408 4.98688,1.85041 7.47614,2.77928 m -7.7994,-15.73106 c -6e-5,-0.001 0.55121,12.57744 0.55114,12.57602 16.53443,6.12668 32.95588,12.35293 49.17089,18.75796 m -49.99946,-25.64531 c -2e-5,-4.2e-4 0.29602,6.72016 0.296,6.71974 21.69281,8.03096 43.19288,16.23183 64.28933,24.78141 m -55.73533,-22.29122 c 16.28128,6.07809 32.43879,12.26569 48.38274,18.6389 m -29.93723,-10.07554 c 13.09037,4.99891 26.07571,10.08848 38.90831,15.30914 4.92668,2.00718 9.8291,4.03142 14.70284,6.07511 m -42.55877,-18.2672 c 9.34563,3.62215 18.63091,7.2968 27.83828,11.03885 8.29429,3.37568 16.52059,6.79982 24.65785,10.28374 2.01069,-4.82106 4.0379,-9.63863 6.08313,-14.45221 m -27.09237,6.5496 c 6.76797,2.77515 13.48798,5.5838 20.1485,8.43215 3.83273,-9.20444 7.72504,-18.39642 11.68744,-27.57238 -2.66279,-1.06701 -5.33349,-2.1269 -8.01145,-3.18005 m -17.67348,24.80831 c -4e-4,-1.7e-4 0.71089,0.29523 0.71049,0.29506 m 0.1423,0.48985 c 4.49734,1.87003 8.97142,3.75596 13.41882,5.65962 m -10.07756,-3.99132 c 3.3045,1.3838 6.59589,2.77646 9.8728,4.17875 3.83071,-9.20427 7.72094,-18.39609 11.68121,-27.57188 -4.68156,-1.87698 -9.38775,-3.73191 -14.11494,-5.56693 m -3.47113,28.46889 c 2.5033,1.05562 4.99884,2.11653 7.48603,3.18308 3.84259,-9.20093 7.74586,-18.38896 11.72032,-27.56052 -12.40258,-4.98562 -24.97809,-9.81439 -37.65896,-14.52577 -3.82029,-1.41856 -7.65021,-2.82596 -11.48865,-4.22321 m 48.53743,21.60948 c -1.7e-4,3.9e-4 0.39562,-0.91482 0.39545,-0.91442 -12.31989,-4.95543 -24.81309,-9.75643 -37.41315,-14.4418 0,0 0,0 0,0 -0.002,-6.7e-4 -1.5944,-0.59165 -1.59619,-0.59232 m 14.92841,5.28033 c -4.43048,-1.68898 -8.87723,-3.36174 -13.33731,-5.02001 -10.81095,-4.01704 -21.70034,-7.94452 -32.64285,-11.80547 3.60406,-1.59938 7.21381,-3.19151 10.83032,-4.77558 m 3.29087,8.88546 c -4.50086,-1.62052 -9.01254,-3.22799 -13.53326,-4.82404 10.49312,-4.65332 21.03521,-9.24496 31.65268,-13.754413 6.66805,-2.833165 13.36682,-5.635506 20.10392,-8.398021 M 554.26188,116.4854 c -2.78093,-0.99529 -5.56581,-1.98581 -8.35423,-2.97194 3.53011,-1.56467 7.06571,-3.12228 10.60782,-4.67206 m -6.28217,1.12112 c 8.75211,-3.85687 17.54116,-7.66857 26.38242,-11.423276 6.20558,-2.636402 12.43772,-5.246109 18.70256,-7.821867 M 565.235,104.41462 c 1.69001,-0.73028 3.38168,-1.45864 5.07513,-2.185 m -3.7095,0.27093 c 3.32978,-1.43549 6.66623,-2.863461 10.01016,-4.283286 12.05562,-5.120857 24.21185,-10.14093 36.5136,-15.007053 -3.81958,-8.195982 -7.69977,-16.37731 -11.6316,-24.543711 m 7.66441,15.992954 c -2.66865,-5.659947 -5.36479,-11.312843 -8.08546,-16.958599 -6.13403,2.520537 -12.22664,5.07595 -18.28339,7.659824 m 21.84963,0.238651 c -1.20001,-2.513838 -2.40514,-5.026273 -3.61513,-7.537296 -5.45027,2.240821 -10.8679,4.509159 -16.25681,6.80051 m 12.33523,-6.475731 c -6.71383,2.781303 -13.37891,5.602978 -20.0026,8.456552 m 5.22342,-1.425141 c -2.06169,0.880321 -4.11923,1.763923 -6.17285,2.650552 -21.36486,9.204436 -42.34641,18.729808 -63.15655,28.416385 m 73.147,-32.390491 c -3.33946,1.415917 -6.66778,2.840803 -9.98587,4.27359 -14.08986,6.07131 -28.0133,12.282249 -41.83112,18.58698 m 34.13476,-15.102029 c -13.55068,5.91156 -26.95662,11.945573 -40.2726,18.06074 m 39.16746,-18.497686 c -10.0099,4.372426 -19.94106,8.811076 -29.81557,13.299296 m 19.59876,-7.374448 c -15.5269,6.890006 -30.88255,13.927354 -46.15087,21.048813 -1e-4,-0.0022 0.70303,16.025174 0.70293,16.022934 m 0.87606,-18.197656 c -1.8e-4,8.6e-5 -0.35811,0.166728 -0.35829,0.166814 m 1.0845,0.822688 c -0.004,0.0019 -1.6924,0.788526 -1.69655,0.790459 -1.3e-4,-0.0029 0.8415,19.229225 0.84138,19.226345 m 0.27161,-20.309876 c -7.4e-4,3.43e-4 -0.7139,0.332478 -0.71464,0.332822 -4.1e-4,-0.0093 1.44551,33.189744 1.44511,33.180454 11.28037,4.18384 22.50704,8.41503 33.65029,12.71877 m -35.32335,-28.4736 c -1.1e-4,-0.002 0.69833,15.95299 0.69823,15.95058 17.67847,6.5524 35.2262,13.2193 52.52889,20.09755 m -13.02772,-5.47913 c 6.6484,2.58631 13.26536,5.19988 19.84453,7.84608 m -14.54076,-5.47895 c 3.37538,1.32474 6.74215,2.65692 10.09948,3.99724 m -5.39576,-1.55957 c 5.19891,2.05665 10.37627,4.13181 15.52899,6.22812 7.99932,3.25904 15.93464,6.56309 23.78707,9.92231 3.57334,-8.58229 7.19846,-17.15376 10.88388,-25.71151 m -48.34699,8.62713 c 4.56751,1.81107 9.1183,3.63669 13.65027,5.47863 8.54576,3.47808 17.01964,7.00763 25.39866,10.60104 1.91828,-4.59494 3.85169,-9.18667 5.80151,-13.77474 m -41.52622,0.53198 c 3.46016,1.38089 6.91028,2.77041 10.34944,4.16935 8.32169,3.38981 16.57422,6.82834 24.73632,10.32703 3.83666,-9.20168 7.7334,-18.39069 11.70074,-27.56344 -5.91972,-2.37789 -11.87907,-4.72026 -17.87072,-7.03142 m 13.95401,4.36254 c -0.002,-8.8e-4 -1.79942,-0.71399 -1.80164,-0.71487 m 0.2527,1.27065 c -10.383,-4.11626 -20.88016,-8.12817 -31.45225,-12.05866 -10.56518,-3.92547 -21.20529,-7.76542 -31.89671,-11.54133 -0.0133,0.006 3.635,-1.60838 3.62171,-1.60249 m 48.06573,20.84643 c -4.71759,-1.82299 -9.45546,-3.6265 -14.21001,-5.41264 m 2.40102,-0.24272 c -2.66027,-1.00343 -5.32589,-2.00128 -7.99623,-2.99393 -10.42273,-3.87217 -20.91774,-7.66119 -31.46237,-11.38766 -0.0155,0.007 3.94408,-1.74398 3.92858,-1.73711 m 20.40457,11.06315 c -7.93034,-2.90965 -15.89953,-5.77414 -23.89767,-8.60246 5.07406,-2.24838 10.15954,-4.48219 15.25944,-6.69909 m -13.61623,6.67486 c -0.009,-0.003 -3.05456,-1.0798 -3.06326,-1.08288 10.62529,-4.71174 21.30067,-9.36051 32.05354,-13.925016 7.17818,-3.048345 14.3921,-6.060956 21.6512,-9.026612 m -8.83851,3.867272 c 7.88156,-3.275909 15.81224,-6.50137 23.80435,-9.661803 -0.90946,-1.951272 -1.82236,-3.901714 -2.73857,-5.851321 m 2.26344,3.123577 c -3.69749,-7.913834 -7.45102,-15.813948 -11.25251,-23.700094 -8.52807,3.498878 -16.97554,7.065434 -25.35735,10.682462 -4.89403,2.107372 -9.76789,4.231576 -14.62411,6.370693 M 445.26039,104.95921 c 8.95388,-0.41892 2.48979,-0.11655 11.44367,-0.53548 m -10.32304,0.17021 c 17.33763,-0.81148 34.68486,-1.62857 52.04397,-2.35972 0,2e-5 -0.46265,-11.003332 -0.46265,-11.003312 m -45.86181,13.509922 c 10.91924,-0.51039 21.84207,-1.01902 32.76909,-1.50304 m -10.72124,-0.82499 c 8.06799,-0.36738 16.13864,-0.72541 24.21221,-1.06487 0.002,0.0443 -1.33278,-31.644013 -1.33091,-31.599662 -6.59015,0.277373 -13.17046,0.56677 -19.74107,0.863273 m 2.25648,0.535649 c -7.33994,0.328149 -36.12847,1.680751 -43.46841,2.0089 m 35.77564,-0.870908 c -10.87947,0.497595 -31.75687,1.489268 -42.63634,1.986863 m 3.35972,-1.504318 c 0.3926,-0.01824 -9.26877,0.428031 -8.87616,0.409785 -0.001,-0.02231 1.44585,31.619878 1.44483,31.597578 0.10319,-0.005 5.20958,-0.23887 5.31278,-0.24357 m -0.204,-30.764537 c 0.20259,-0.0094 -6.92127,0.318259 -6.71869,0.308893 -9.8e-4,-0.02167 1.4404,31.616444 1.43942,31.594774 0.18506,-0.008 6.8961,-0.31721 7.08117,-0.32567 m -6.69282,-6.800653 c 0,-4e-6 0.31803,6.962623 0.31803,6.962613 0.24334,-0.0111 7.70728,-0.35517 7.95063,-0.3663 m -8.35399,-1.37173 c 0,0 0.0827,1.80758 0.0827,1.80758 3.05198,-0.1396 22.3444,-1.0416 25.39639,-1.1812 m 20.54411,-1.2031 c 8.98415,-0.412 17.97129,-0.81375 26.96173,-1.19252 0.002,0.0378 -1.33278,-31.63929 -1.33119,-31.601527 -10.17041,0.427735 -20.31779,0.884055 -30.44258,1.350874 m 30.68618,-0.727576 c -20.40162,0.859073 -40.71202,1.833698 -60.93492,2.777862 m 28.41956,-1.684043 c -4.22241,0.195401 -19.86403,0.929934 -24.08644,1.125334 m 22.1757,-1.068146 c -22.67755,1.053109 -16.70814,0.783245 -39.38568,1.836354 -1.5e-4,-0.0032 0.53526,11.761592 0.53512,11.758434 M 456.1832,71.641038 c -107.36134,5.003653 74.40662,-3.471827 -32.95473,1.531826 -1e-4,-0.0021 0.45249,9.905361 0.45239,9.903239 m 25.13451,-10.51949 c 11.4671,-0.537186 -36.69231,1.710473 -25.2252,1.173287 -0.001,-0.02348 1.44302,31.62008 1.44195,31.5966 6.6279,-0.30246 28.48629,-1.33026 35.11418,-1.63271 m -34.01894,1.55836 c 13.40919,-0.61298 30.78484,-1.43956 44.19403,-2.05254 m -9.57076,1.21557 c 12.84616,-0.59866 25.69743,-1.18654 38.55477,-1.72643 0.003,0.0687 -1.20262,-28.704057 -1.19974,-28.635325 m -20.19182,84.780915 c -0.21095,0.01 8.4496,-0.38049 8.23866,-0.3709 m -8.41928,0.49644 c 7.79043,-0.35497 15.56308,-0.70026 23.31815,-1.02742 0.007,0.17634 -1.454,-34.6511 -1.4466,-34.47476 -7.23283,0.30431 -14.47011,0.62392 -21.71203,0.95211 m 9.43944,34.49334 c 4.35639,-0.19382 8.70719,-0.3835 13.05244,-0.56757 0.003,0.0658 -1.45774,-34.5418 -1.45496,-34.47597 -0.0566,0.002 -5.57856,0.23811 -5.63518,0.2405 m 7.67487,28.58015 c 0,0 -0.41001,-9.7569 -0.41001,-9.7569 m 0.84075,6.75642 c 0.001,0.0345 -1.11266,-26.54189 -1.11121,-26.50737 -17.97928,0.75466 -35.9856,1.60511 -54.02154,2.44839 m 55.02012,23.80444 c 0.006,0.15291 -0.85594,-20.44976 -0.84954,-20.29685 m 0.21926,1.51521 c 3.2e-4,0.007 -0.35057,-8.37981 -0.35026,-8.37231 -10.56586,0.44235 -21.14047,0.91781 -31.72435,1.40548 m 9.07711,1.51928 c -17.08329,0.77653 -35.79512,1.67755 -52.8784,2.45408 -0.001,-0.0288 1.56889,34.50005 1.56758,34.4713 0.0578,-0.003 4.17177,-0.18968 4.22958,-0.1923 m -4.9898,-19.88838 c -3.9e-4,-0.009 0.87703,19.28511 0.87665,19.27657 18.52645,-0.84154 35.36,-1.65485 53.88645,-2.49639 m 11.79881,0.19044 c -0.15813,0.007 8.99192,-0.38652 8.83379,-0.37961 0,-8e-5 -1.43645,-34.11648 -1.43645,-34.11656 m -1.69544,33.35022 c -0.0262,0.001 3.81656,-0.16211 3.79034,-0.16098 0.0154,0.36787 -1.45891,-34.8442 -1.44351,-34.47633 -0.0214,9e-4 -3.51047,0.14833 -3.53187,0.14923 m 4.61961,19.10903 c 0.004,0.0846 -0.7849,-18.76637 -0.78136,-18.68176 -24.53906,1.02942 -49.13067,2.23808 -73.78157,3.36404 m 73.39732,-3.66621 c 0,0 -0.0474,-1.127 -0.0474,-1.127 -8.93561,0.37444 -17.87754,0.77245 -26.82607,1.18138 m 15.15017,0.12669 c -0.22973,0.0101 -9.6171,0.43046 -9.84682,0.44058 m 1.52062,0.345 c -16.3477,0.7365 -38.85642,1.81571 -55.20412,2.55222 -0.001,-0.024 1.47399,32.4516 1.4729,32.4276 m 40.34206,-35.16508 c -25.57791,1.18495 -15.88789,0.74325 -41.4658,1.92819 -7.8e-4,-0.0171 1.20903,26.53287 1.20826,26.51578 m 24.69612,-28.18016 c 9.38054,-0.43806 -35.6539,1.65382 -26.27337,1.21576 -0.001,-0.0299 1.57081,34.49549 1.56944,34.46557 0.0759,-0.003 4.73497,-0.21628 4.81082,-0.21973 m -2.79194,-33.16411 c 0.024,-0.001 -2.59955,0.11863 -2.57551,0.11753 -3.8e-4,-0.008 0.81071,17.75552 0.81033,17.74722 m -1.05401,-3.95996 c -4.1e-4,-0.009 0.893,19.58434 0.89259,19.57526 0.0996,-0.005 5.38625,-0.24533 5.48582,-0.24984 m -0.33746,0.29461 c 18.09098,-0.82865 28.05353,-1.30984 46.14451,-2.13849 m -30.04522,0.96991 c 1.36603,-0.0638 6.13168,-0.28688 7.4977,-0.35072 m -6.93486,1.30994 c 17.84352,-0.83316 35.59379,-1.67094 53.25327,-2.41376 0.001,0.025 -0.89264,-21.27401 -0.89159,-21.24898 M 645.80356,40.256829 c -23.8913,8.70051 -47.01068,18.108537 -69.65321,27.884575 -12.80286,5.515966 -25.46813,11.14719 -38.04142,16.859298 m 110.06361,-0.565846 c -1.94967,0.731567 -3.89505,1.468057 -5.83632,2.209266 m -8.16639,48.076008 c 27.78565,12.47688 54.52593,25.87031 79.39341,40.62548"+ id="path5392" />+ </g>+ </clipPath>+ <linearGradient+ gradientUnits="userSpaceOnUse"+ y2="171.69249"+ x2="208.0477"+ y1="171.69249"+ x1="194.11444"+ id="linearGradient5447"+ xlink:href="#linearGradient5445" />+ </defs>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ style="display:inline"+ transform="translate(-61.468328,-167.44508)"+ id="layer1">+ <rect+ transform="translate(2.9514358e-6,-40.596579)"+ clip-path="url(#clipPath5388)"+ ry="2.3587098"+ y="206.27705"+ x="59.818722"+ height="77.735466"+ width="77.735458"+ id="rect5250"+ style="display:inline;opacity:1;fill:url(#linearGradient5260);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.31037128;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke" />+ <path+ id="text10004"+ d="m 125.5315,209.19106 c -3.34965,-1.30393 -6.69931,-2.60787 -10.04896,-3.9118 5.21848,-2.15262 10.43696,-4.30525 15.65545,-6.45787 -0.92835,-2.01253 -1.85669,-4.02505 -2.78504,-6.03758 -6.83922,2.90641 -13.67843,5.81282 -20.51763,8.71921 0.0104,2.54721 0.0208,5.09442 0.0312,7.64163 6.86079,2.8724 13.7216,5.74479 20.58242,8.61717 0.90892,-2.11466 1.81783,-4.22931 2.72675,-6.34397 -1.76975,-0.68894 -3.53951,-1.37789 -5.30926,-2.06683 m -2.62477,-4.90221 c 3.04901,-1.25752 6.09801,-2.51505 9.14702,-3.77257 -0.92751,-2.01274 -1.85501,-4.02549 -2.78252,-6.03823 -2.59416,1.10259 -5.18831,2.20519 -7.78247,3.30778 m 5.56493,-1.53082 c -5.40972,2.29966 -10.81943,4.59932 -16.22916,6.89899 0.0117,2.54697 0.0234,5.09394 0.0352,7.64091 6.86463,2.8717 13.72924,5.74341 20.59384,8.61511 0.91009,-2.11486 1.82018,-4.22973 2.73027,-6.3446 -5.23684,-2.04024 -10.47368,-4.08049 -15.71053,-6.12073 0.75831,-0.31271 1.51662,-0.62542 2.27492,-0.93812 m -14.17992,-7.36348 c -0.76309,-1.65493 -1.52619,-3.30987 -2.28928,-4.9648 -6.839318,2.90343 -13.678633,5.80688 -20.517941,8.71032 0.01054,2.5462 0.02107,5.0924 0.03161,7.6386 6.860547,2.86946 13.721102,5.73892 20.581661,8.60838 0.90903,-2.11556 1.81807,-4.23112 2.72711,-6.34668 -5.23993,-2.04195 -10.47985,-4.08389 -15.719768,-6.12583 3.538493,-1.46115 7.076989,-2.9223 10.615478,-4.38345 m -9.578031,6.75815 c -0.379995,-0.14802 -0.759989,-0.29603 -1.139983,-0.44404 5.220982,-2.15291 10.441954,-4.30583 15.662924,-6.45875 -0.54602,-1.18498 -1.09203,-2.36995 -1.63805,-3.55493 m -30.759587,4.52156 c 2.327107,-4.2e-4 4.654213,-8.4e-4 6.981318,-0.001 4.72e-4,-2.42569 9.42e-4,-4.85139 0.0014,-7.27708 -5.608879,-0.001 -11.217765,-0.002 -16.826659,-0.003 4.62e-4,2.42483 9.24e-4,4.84967 0.0014,7.2745 5.611028,-9.8e-4 11.22205,-0.002 16.833063,-0.003 4.54e-4,-2.42568 9.07e-4,-4.85135 0.0014,-7.27703 -1.723988,-3e-4 -3.447976,-5.9e-4 -5.171966,-8.9e-4 m -2.024007,22.444 c 2.816132,-1e-5 5.632262,-2e-5 8.448391,-3e-5 4.56e-4,-2.64572 9.1e-4,-5.29144 0.0014,-7.93716 -5.637754,-2e-5 -11.275514,-5e-5 -16.913281,-7e-5 4.48e-4,2.6457 8.94e-4,5.29139 0.0013,7.93709 5.639668,-2e-5 11.279329,-5e-5 16.918984,-7e-5 4.39e-4,-2.64571 8.77e-4,-5.29143 0.0013,-7.93714 -0.03972,0 -0.07944,0 -0.119166,0 m 27.32549,-18.3087 -17.328906,7.36254 m 21.261656,1.45287 -0.93476,0.39715 m 0.92531,12.30443 14.19828,5.93971"+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2a144d;stroke-width:0.23003563;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />+ <path+ id="path10202"+ d="m 115.22655,198.82177 c -2.33453,0.87014 -4.64195,1.77129 -6.92798,2.69686 1e-5,-0.001 -0.0471,7.64456 -0.0471,7.64318 2.40744,1.04231 4.78622,2.11139 7.12654,3.21253 m -3.89008,-11.93336 c -1.00663,0.39365 -2.00871,0.79253 -3.00671,1.19609 0,-9e-5 -0.0168,2.57292 -0.0168,2.57282 m 0.0857,-0.87568 c 10e-6,-4.6e-4 -0.0406,5.94694 -0.0406,5.94646 3.36011,1.45836 6.6636,2.96933 9.88376,4.5473 m -7.20478,-3.23662 c 5.79648,2.59181 11.3987,5.35494 16.66528,8.36545 0.32773,-0.6279 0.65819,-1.25494 0.99146,-1.88109 m -1.60443,1.53758 c 0.21377,0.12085 0.42701,0.24211 0.6397,0.36376 1.05492,-2.01971 2.13811,-4.03043 3.25201,-6.03131 -1.59952,-0.86761 -3.22505,-1.71188 -4.8732,-2.53483 m 0.29618,-0.0427 c -3.40715,-1.70793 -6.91152,-3.32401 -10.483,-4.86582 2.90365,-1.06488 5.84253,-2.0795 8.82804,-3.03035 m -4.30994,5.25285 c -1.44084,-0.66089 -2.89525,-1.30799 -4.36114,-1.9425 5.32305,-1.95032 10.76393,-3.73086 16.39321,-5.25805 -0.0526,-0.15243 -0.10543,-0.30483 -0.15839,-0.4572 m -16.346,5.71656 c -6e-5,-3e-5 -0.16464,-0.0711 -0.1647,-0.0711 5.32191,-1.95602 10.76115,-3.74365 16.38827,-5.27932 -0.64765,-1.86511 -1.31982,-3.72666 -2.01474,-5.58459 m -6.00177,7.65252 c 2.59724,-0.83545 5.22948,-1.62315 7.90424,-2.35414 -0.10412,-0.29859 -0.20887,-0.59709 -0.31423,-0.8955 m -0.14193,1.39572 c 0.18793,-0.052 0.37606,-0.10371 0.56441,-0.15515 -0.73132,-2.1078 -1.49395,-4.21107 -2.28537,-6.30972 -0.14277,0.0413 -0.28541,0.0828 -0.42792,0.12441 m 2.58573,5.86862 c -1e-5,0 0.0598,-0.0163 0.0598,-0.0163 -0.73446,-2.10743 -1.50012,-4.2103 -2.29447,-6.30856 -2.51058,0.72674 -4.98101,1.49943 -7.41727,2.31118 m 2.7274,-0.57192 c -5.49569,1.74707 -10.81091,3.70187 -16.01266,5.78726 m -0.10008,0.28407 c -0.1982,0.0796 -0.39625,0.15943 -0.59413,0.23942 0,-1.5e-4 -0.0188,2.695 -0.0188,2.69485 m -0.26343,-1.06335 c 0,-6.9e-4 -0.0362,5.97408 -0.0362,5.97348 4.5267,1.96098 8.95073,4.01666 13.20673,6.20223 m -1.19162,-0.94232 c 2.57116,1.29507 5.08466,2.63559 7.52645,4.02912 0.2451,-0.46951 0.49173,-0.93854 0.73992,-1.40707 m -3.71917,-0.16021 c 1.03465,0.56033 2.05792,1.12925 3.06882,1.7073 1.05517,-2.01991 2.13862,-4.0308 3.25279,-6.03186 -3.20163,-1.73679 -6.50739,-3.38013 -9.89002,-4.94595 m 0.73858,0.22701 c -2.02311,-0.94586 -4.0745,-1.86341 -6.14827,-2.75609 2.20426,-0.81044 4.42876,-1.59211 6.67851,-2.33909 m -1.44719,0.78416 c 3.68217,-1.25405 7.4293,-2.41757 11.26369,-3.46413 -0.62864,-1.81025 -1.28037,-3.61715 -1.95359,-5.42066 m 2.23455,5.42891 c 0,0 0.0174,-0.005 0.0174,-0.005 -0.72889,-2.1089 -1.48926,-4.21326 -2.27857,-6.31299 -3.40899,0.98048 -6.74388,2.04632 -10.0197,3.18021 m 11.03329,-0.34197 c -0.33808,-0.93185 -0.68206,-1.86279 -1.03172,-2.79283 -2.38449,0.68629 -4.73274,1.41434 -7.0499,2.17823 m 7.95135,0.32819 c -0.33935,-0.93163 -0.68458,-1.86236 -1.03546,-2.79218 -4.58328,1.32102 -9.03245,2.79572 -13.38399,4.38215 m 6.2801,-1.79408 c -1.65708,0.54838 -3.29832,1.11504 -4.92561,1.69781 m 3.20183,-1.43563 c -4.26843,1.45184 -8.43432,3.02127 -12.53045,4.67057 m -22.97746,-0.61053 c -0.854682,0.39452 -1.707863,0.7904 -2.559818,1.18742 -1.2e-5,-2.5e-4 0.117783,2.69178 0.117771,2.69152 m -0.268337,-2.29444 c -4e-6,0 -0.02307,0.0108 -0.02308,0.0108 -1.1e-4,-0.003 0.33467,7.63469 0.33456,7.63215 3.348442,1.24064 6.676356,2.49903 9.969061,3.78762 m -10.192384,-8.04094 c -2.8e-5,-6.9e-4 0.176276,4.01026 0.176248,4.00962 0.573877,0.21257 1.147161,0.42566 1.719779,0.63933 m -1.79414,-3.6187 c -1.4e-5,-2.3e-4 0.126798,2.89326 0.126782,2.89293 3.803508,1.40936 7.581027,2.84161 11.311057,4.315 m -11.501658,-5.89934 c -4e-6,-9e-5 0.06809,1.54588 0.06809,1.54578 4.990119,1.84741 9.935901,3.7339 14.788836,5.70061 m -12.821111,-5.12777 c 3.745274,1.39817 7.462077,2.82154 11.129754,4.28761 m -6.88663,-2.31774 c 3.011252,1.14993 5.998343,2.32071 8.950298,3.52165 1.133312,0.46173 2.261042,0.92737 3.382172,1.39749 m -9.790029,-4.2021 c 2.149828,0.83322 4.285773,1.67852 6.403797,2.53933 1.907982,0.77652 3.800322,1.5642 5.672182,2.36562 0.46253,-1.10901 0.92886,-2.21723 1.39934,-3.32452 m -6.232212,1.50664 c 1.556872,0.63838 3.102712,1.28447 4.634872,1.9397 0.88166,-2.11735 1.77703,-4.23184 2.68853,-6.34263 -0.61254,-0.24545 -1.2269,-0.48927 -1.84292,-0.73153 m -4.06553,5.7068 c -9e-5,-4e-5 0.16353,0.0679 0.16344,0.0679 m 0.0327,0.11268 c 1.03455,0.43018 2.06375,0.86401 3.08681,1.30192 m -2.3182,-0.91815 c 0.76015,0.31833 1.51729,0.63869 2.27109,0.96126 0.8812,-2.11731 1.7761,-4.23175 2.6871,-6.34251 -1.07693,-0.43177 -2.15952,-0.85847 -3.24694,-1.28059 m -0.79848,6.54886 c 0.57584,0.24283 1.14991,0.48687 1.72205,0.73222 0.88393,-2.11654 1.78182,-4.23012 2.69609,-6.3399 -2.85303,-1.14687 -5.74585,-2.25766 -8.6629,-3.34145 -0.878803,-0.32632 -1.759821,-0.65007 -2.642799,-0.97149 m 11.165339,4.97095 c -4e-5,9e-5 0.091,-0.21044 0.091,-0.21035 -2.83402,-1.13992 -5.7079,-2.24432 -8.60636,-3.32213 0,0 0,0 0,0 -4.6e-4,-1.5e-4 -0.366769,-0.1361 -0.367181,-0.13625 m 3.434061,1.21466 c -1.01916,-0.38852 -2.042074,-0.77332 -3.068051,-1.15478 -2.486904,-0.92406 -4.991852,-1.82752 -7.509019,-2.71568 0.829062,-0.36791 1.659434,-0.73416 2.49136,-1.09855 m 0.757017,2.04397 c -1.035358,-0.37277 -2.073205,-0.74255 -3.113132,-1.1097 2.413792,-1.07043 4.838848,-2.12667 7.281244,-3.164 1.533889,-0.65173 3.074841,-1.29637 4.624621,-1.93185 m -9.766347,6.08968 c -0.639713,-0.22895 -1.280335,-0.45681 -1.921771,-0.68365 0.812051,-0.35993 1.625365,-0.71824 2.440177,-1.07474 m -1.445123,0.25789 c 2.013297,-0.88721 4.035092,-1.76404 6.068896,-2.62776 1.427505,-0.60646 2.861118,-1.20679 4.302258,-1.7993 m -6.920229,3.15085 c 0.388763,-0.16799 0.777907,-0.33554 1.167461,-0.50263 m -0.853317,0.0623 c 0.765968,-0.33022 1.53347,-0.6587 2.302693,-0.98531 2.773222,-1.17798 5.569582,-2.33278 8.399432,-3.45216 -0.87864,-1.88537 -1.77123,-3.76736 -2.67569,-5.64593 m 1.76309,3.67895 c -0.61388,-1.30199 -1.23409,-2.60236 -1.85994,-3.90108 -1.41105,0.57981 -2.81257,1.16765 -4.205833,1.76203 m 5.026193,0.0549 c -0.27605,-0.57827 -0.55327,-1.15622 -0.83161,-1.73385 -1.25376,0.51547 -2.5,1.03727 -3.73965,1.56436 m 2.83755,-1.48965 c -1.54442,0.6398 -3.077627,1.28889 -4.601312,1.94531 m 1.201573,-0.32783 c -0.474262,0.2025 -0.94757,0.40576 -1.419976,0.60972 -4.914679,2.11735 -9.741183,4.30852 -14.528256,6.53678 m 16.826411,-7.45096 c -0.76819,0.32571 -1.533822,0.65348 -2.297101,0.98307 -3.24117,1.39662 -6.444057,2.82536 -9.622648,4.27567 m 7.852211,-3.474 c -3.117139,1.35987 -6.200983,2.7479 -9.264133,4.15461 m 9.009911,-4.25513 c -2.302633,1.00582 -4.587154,2.02686 -6.858643,3.05931 m 4.508413,-1.69638 c -3.57174,1.58495 -7.104087,3.20379 -10.616344,4.84198 -2.3e-5,-5.1e-4 0.161722,3.68636 0.161699,3.68584 m 0.201525,-4.18611 c -4.2e-5,2e-5 -0.08238,0.0384 -0.08242,0.0384 m 0.249474,0.18924 c -9.2e-4,4.4e-4 -0.389313,0.18139 -0.390267,0.18184 -3e-5,-6.7e-4 0.193575,4.4234 0.193547,4.42274 m 0.06248,-4.67199 c -1.7e-4,7e-5 -0.164222,0.0765 -0.164393,0.0766 -9.4e-5,-0.002 0.332519,7.63482 0.332427,7.63268 2.594887,0.96244 5.177421,1.93576 7.740766,2.92577 m -8.125629,-6.54994 c -2.5e-5,-4.6e-4 0.160641,3.66976 0.160618,3.6692 4.066678,1.50729 8.103281,3.04091 12.083516,4.62316 m -2.99684,-1.2604 c 1.529369,0.59494 3.051506,1.19616 4.564949,1.80488 m -3.344893,-1.26036 c 0.776458,0.30474 1.550935,0.61119 2.32324,0.91951 m -1.241217,-0.35875 c 1.195935,0.4731 2.386912,0.95046 3.572221,1.43269 1.840131,0.74969 3.665531,1.50974 5.471871,2.28248 0.822,-1.97423 1.6559,-3.94598 2.50368,-5.91456 m -11.121527,1.98454 c 1.05069,0.41661 2.097534,0.83657 3.140048,1.26028 1.965829,0.80009 3.915119,1.61201 5.842599,2.43862 0.44127,-1.057 0.88602,-2.11326 1.33455,-3.16868 m -9.552508,0.12237 c 0.79596,0.31766 1.589611,0.6373 2.38074,0.9591 1.914288,0.77978 3.812658,1.57076 5.690228,2.37559 0.88257,-2.11672 1.77896,-4.23052 2.69159,-6.34058 -1.36174,-0.54699 -2.73261,-1.08582 -4.1109,-1.61747 m 3.20992,1.00354 c -4.6e-4,-2.1e-4 -0.41393,-0.16425 -0.41444,-0.16445 m 0.0581,0.2923 c -2.38846,-0.94689 -4.80318,-1.86977 -7.235138,-2.77392 -2.430368,-0.903 -4.877973,-1.78633 -7.33738,-2.65492 -0.0031,0.001 0.836179,-0.36999 0.833122,-0.36863 m 11.056826,4.79542 c -1.08521,-0.41935 -2.17509,-0.83422 -3.268804,-1.2451 m 0.552314,-0.0558 c -0.611951,-0.23083 -1.225138,-0.46037 -1.839412,-0.68871 -2.397599,-0.89074 -4.811825,-1.76235 -7.237466,-2.61957 -0.0036,0.002 0.907279,-0.40118 0.903714,-0.3996 m 4.693778,2.54492 c -1.824261,-0.66932 -3.657459,-1.32826 -5.497316,-1.97887 1.167215,-0.51721 2.337056,-1.03107 3.510215,-1.54103 m -3.132218,1.53545 c -0.0021,-6.9e-4 -0.702658,-0.24839 -0.704659,-0.2491 2.444195,-1.08387 4.899913,-2.15325 7.373456,-3.20325 1.651238,-0.70123 3.310698,-1.39423 4.980548,-2.07644 m -2.03317,0.88961 c 1.81304,-0.75358 3.63737,-1.49555 5.47584,-2.22256 -0.2092,-0.44886 -0.4192,-0.89753 -0.62996,-1.34601 m 0.52067,0.71853 c -0.85056,-1.82046 -1.714,-3.63777 -2.58848,-5.45186 -1.96176,0.80486 -3.90498,1.6253 -5.833093,2.45734 -1.125801,0.48477 -2.246963,0.97342 -3.364066,1.46549 m -26.743025,7.15179 c 2.059712,-0.0964 0.572741,-0.0268 2.632452,-0.12318 m -2.374667,0.0391 c 3.988273,-0.18667 7.978754,-0.37463 11.971968,-0.54282 0,1e-5 -0.106426,-2.53116 -0.106426,-2.53115 m -10.549851,3.10776 c 2.511814,-0.11741 5.024455,-0.23441 7.538059,-0.34575 m -2.466268,-0.18978 c 1.855925,-0.0845 3.712463,-0.16687 5.569671,-0.24496 4.6e-4,0.0102 -0.306587,-7.27925 -0.306156,-7.26905 -1.51597,0.0638 -3.029675,0.13038 -4.54115,0.19859 m 0.519071,0.12322 c -1.688448,0.0755 -8.310835,0.38663 -9.999283,0.46211 m 8.229672,-0.20034 c -2.502666,0.11447 -7.305212,0.34259 -9.807878,0.45705 m 0.772856,-0.34604 c 0.09031,-0.004 -2.132148,0.0985 -2.041833,0.0943 -2.3e-4,-0.005 0.332597,7.2737 0.332362,7.26857 0.02374,-0.001 1.198389,-0.0549 1.222129,-0.056 m -0.04693,-7.07694 c 0.0466,-0.002 -1.592138,0.0732 -1.545538,0.0711 -2.25e-4,-0.005 0.331344,7.27291 0.331118,7.26792 0.04257,-0.002 1.586349,-0.073 1.628922,-0.0749 m -1.539587,-1.5644 c 0,0 0.07316,1.60165 0.07316,1.60165 0.05598,-0.003 1.772949,-0.0817 1.828928,-0.0843 m -1.921715,-0.31555 c 0,0 0.01902,0.41581 0.01902,0.41581 0.702064,-0.0321 5.140008,-0.2396 5.842074,-0.27172 m 4.725877,-0.27675 c 2.066675,-0.0948 4.134037,-0.18719 6.202159,-0.27432 4.6e-4,0.009 -0.306587,-7.27817 -0.306221,-7.26948 -2.339557,0.0984 -4.673816,0.20336 -7.002878,0.31075 m 7.058915,-0.16737 c -4.6931,0.19762 -9.365216,0.42182 -14.017203,0.63901 m 6.537511,-0.38739 c -0.971305,0.045 -4.569434,0.21391 -5.540739,0.25886 m 5.101201,-0.24571 c -5.216645,0.24225 -3.843468,0.18018 -9.06011,0.42243 -3.4e-5,-7.4e-4 0.123129,2.70558 0.123097,2.70486 m 7.426843,-3.24953 c -24.696934,1.15102 17.116174,-0.79865 -7.580762,0.35237 -2.3e-5,-4.8e-4 0.104089,2.27859 0.104066,2.2781 m 5.781832,-2.41986 c 2.637842,-0.12357 -8.440538,0.39347 -5.802694,0.2699 -2.3e-4,-0.005 0.331946,7.27375 0.331699,7.26835 1.524654,-0.0696 6.552862,-0.30601 8.077513,-0.37559 m -7.825568,0.35848 c 3.084591,-0.14101 7.08161,-0.33115 10.166201,-0.47216 m -2.201616,0.27963 c 2.955075,-0.13771 5.911325,-0.27295 8.868971,-0.39714 6.9e-4,0.0158 -0.276645,-6.60296 -0.275983,-6.58715 m -4.644838,19.50263 c -0.04853,0.002 1.943709,-0.0875 1.895186,-0.0853 m -1.936735,0.1142 c 1.792077,-0.0816 3.580063,-0.16108 5.364006,-0.23634 0.0016,0.0406 -0.334472,-7.97099 -0.33277,-7.93042 -1.663809,0.07 -3.328641,0.14352 -4.99454,0.21902 m 2.171407,7.93469 c 1.002125,-0.0446 2.002964,-0.0882 3.002526,-0.13056 6.9e-4,0.0151 -0.335332,-7.94584 -0.334692,-7.9307 -0.01302,4.6e-4 -1.283268,0.0548 -1.296293,0.0553 m 1.765494,6.57446 c 0,0 -0.09432,-2.24444 -0.09432,-2.24444 m 0.193403,1.55422 c 2.3e-4,0.008 -0.255952,-6.10558 -0.255618,-6.09764 -4.135875,0.1736 -8.27797,0.36923 -12.426879,0.56322 m 12.656588,5.47587 c 0.0014,0.0352 -0.196897,-4.70418 -0.195425,-4.669 m 0.05044,0.34855 c 7.3e-5,0.002 -0.08064,-1.92765 -0.08057,-1.92593 -2.430525,0.10176 -4.863062,0.21113 -7.297731,0.32331 m 2.088058,0.34949 c -3.929765,0.17863 -8.234153,0.3859 -12.163916,0.56453 -2.3e-4,-0.007 0.360901,7.93624 0.3606,7.92962 0.0133,-6.9e-4 0.959655,-0.0436 0.972954,-0.0442 m -1.147832,-4.57504 c -9e-5,-0.002 0.201748,4.43626 0.201661,4.4343 4.261743,-0.19359 8.13406,-0.38068 12.395803,-0.57426 m 2.714147,0.0438 c -0.03638,0.002 2.068462,-0.0889 2.032086,-0.0873 0,-1e-5 -0.330434,-7.848 -0.330434,-7.84802 m -0.390012,7.67174 c -0.006,2.3e-4 0.877945,-0.0373 0.871913,-0.037 0.0035,0.0846 -0.335601,-8.01541 -0.332058,-7.93079 -0.0049,2.1e-4 -0.807534,0.0341 -0.812456,0.0343 m 1.062674,4.39576 c 9.21e-4,0.0195 -0.180555,-4.31693 -0.17974,-4.29747 -5.644858,0.2368 -11.301805,0.51484 -16.97239,0.77385 m 16.883999,-0.84336 c 0,0 -0.0109,-0.25925 -0.0109,-0.25925 -2.055509,0.0861 -4.112471,0.17769 -6.170952,0.27176 m 3.485079,0.0291 c -0.05285,0.002 -2.212276,0.099 -2.26512,0.10135 m 0.349797,0.0794 c -3.760553,0.16942 -8.938361,0.41768 -12.698914,0.5871 -2.3e-4,-0.006 0.33907,7.46503 0.338819,7.45951 m 9.280111,-8.08922 c -5.88383,0.27258 -3.65478,0.17097 -9.538611,0.44355 -1.79e-4,-0.004 0.27812,6.1035 0.277943,6.09957 m 5.680987,-6.48244 c 2.157859,-0.10077 -8.201667,0.38044 -6.043811,0.27967 -2.3e-4,-0.007 0.361342,7.93519 0.361027,7.92831 0.01746,-6.9e-4 1.089212,-0.0498 1.10666,-0.0506 m -0.642245,-7.62892 c 0.0055,-2.3e-4 -0.59799,0.0273 -0.592459,0.027 -8.8e-5,-0.002 0.186492,4.0844 0.186404,4.0825 m -0.24246,-0.91094 c -9.4e-5,-0.002 0.205422,4.5051 0.205328,4.50301 0.02291,-0.001 1.239029,-0.0564 1.261934,-0.0575 m -0.07763,0.0678 c 4.16157,-0.19062 6.453312,-0.30131 10.614882,-0.49193 m -6.911472,0.22311 c 0.314236,-0.0147 1.410505,-0.066 1.724739,-0.0807 m -1.595265,0.30133 c 4.104645,-0.19166 8.18784,-0.38438 12.250149,-0.55525 2.3e-4,0.006 -0.205339,-4.89378 -0.205097,-4.88802 m 33.383164,-22.13887 c -5.49585,2.00143 -10.81413,4.16561 -16.02272,6.41445 -2.945114,1.26887 -5.858578,2.56425 -8.750882,3.87824 m 25.318552,-0.13017 c -0.44849,0.16829 -0.896,0.33771 -1.34256,0.50821 m -1.87856,11.0592 c 6.39169,2.87012 12.5429,5.95109 18.26331,9.34531"+ style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:57.54236603px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Ultra-Bold';text-align:start;letter-spacing:-1.70070565px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#2a144d;stroke-width:0.46007127;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers fill stroke" />+ <path+ d="m 111.80954,213.04909 c -0.26629,0.16448 -0.50119,0.30232 -0.6724,0.70346 -0.1712,0.40114 -0.10823,0.66612 -0.0428,0.97219 l 0.12706,-0.0258 c -0.0563,-0.29013 -0.0764,-0.51482 0.0782,-0.87703 0.15531,-0.3639 0.33078,-0.50311 0.57919,-0.66321 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4728" />+ <path+ d="m 112.44893,213.61011 c -0.26405,-0.1127 -0.57293,0.002 -0.74125,0.39595 -0.16759,0.39268 -0.0531,0.69166 0.22957,0.8123 0.1574,0.0672 0.29655,0.0506 0.38906,0.012 l -0.0362,-0.13551 c -0.087,0.0209 -0.17996,0.0372 -0.28998,-0.01 -0.18111,-0.0773 -0.26524,-0.26928 -0.12148,-0.6061 0.15025,-0.35206 0.34807,-0.40769 0.5241,-0.33256 0.0812,0.0347 0.14075,0.0921 0.18825,0.18244 l 0.13209,-0.0657 c -0.0613,-0.11423 -0.12691,-0.19023 -0.27416,-0.25307 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4730" />+ <path+ d="m 113.09042,213.59577 -0.12706,0.0258 c 0.0563,0.29012 0.0771,0.51313 -0.0782,0.87703 -0.15459,0.36221 -0.33078,0.50311 -0.57918,0.66321 l 0.0693,0.10959 c 0.26629,-0.16448 0.5012,-0.30232 0.67241,-0.70346 0.1712,-0.40114 0.10822,-0.66613 0.0428,-0.97219 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4732" />+ <path+ d="m 114.01162,214.30108 -0.24373,-0.10402 -0.49772,1.16618 0.27928,0.11919 c 0.25219,0.10764 0.59679,0.12065 0.79978,-0.35496 0.2066,-0.48407 -0.0397,-0.69924 -0.33761,-0.82639 z m -0.0194,0.14379 c 0.18619,0.0795 0.35432,0.21526 0.18601,0.60962 -0.16398,0.38422 -0.38001,0.38406 -0.5628,0.30604 l -0.13033,-0.0556 0.38864,-0.9106 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4734" />+ <path+ d="m 114.96573,216.0869 0.16926,0.0722 0.12536,-1.3251 -0.20311,-0.0867 -0.87179,1.00653 0.16249,0.0693 0.21299,-0.25525 0.44176,0.18854 z m -0.31025,-0.63263 0.44286,-0.53131 -0.079,0.68662 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4736" />+ <path+ d="m 116.5494,215.38421 -0.16249,-0.0693 -0.71613,0.86686 0.1305,-1.11681 -0.17264,-0.0737 -0.12197,1.32654 0.17264,0.0737 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4738" />+ <path+ d="m 116.89069,215.52987 -0.16079,-0.0686 -0.49773,1.16618 0.1608,0.0686 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4740" />+ <path+ d="m 117.4728,215.77831 -0.24373,-0.10402 -0.49772,1.16618 0.27928,0.11919 c 0.25219,0.10764 0.59679,0.12065 0.79978,-0.35496 0.2066,-0.48407 -0.0397,-0.69924 -0.33761,-0.82639 z m -0.0194,0.14379 c 0.18619,0.0795 0.35432,0.21526 0.18601,0.60962 -0.16398,0.38422 -0.38001,0.38406 -0.5628,0.30604 l -0.13033,-0.0556 0.38864,-0.9106 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4742" />+ <path+ d="m 118.7188,216.31011 -0.16079,-0.0686 -0.49773,1.16618 0.62118,0.26511 0.0785,-0.13255 -0.479,-0.20443 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4744" />+ <path+ d="m 120.03232,216.87072 -0.63133,-0.26946 -0.49773,1.16618 0.64488,0.27523 0.0549,-0.12863 -0.48408,-0.20661 0.17049,-0.39945 0.39267,0.1676 0.0549,-0.12864 -0.39267,-0.16759 0.16253,-0.38082 0.45192,0.19287 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4746" />+ <path+ d="m 120.99565,217.28186 -0.83274,-0.35541 -0.0585,0.13709 0.33175,0.14159 -0.43921,1.02909 0.1608,0.0686 0.43921,-1.02908 0.32328,0.13798 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4748" />+ <path+ d="m 121.8717,217.65576 -0.83275,-0.35541 -0.0585,0.13709 0.33174,0.14159 -0.43921,1.02908 0.16079,0.0686 0.43922,-1.02908 0.32327,0.13797 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4750" />+ <path+ d="m 122.21965,217.80427 -0.1608,-0.0686 -0.49772,1.16618 0.1608,0.0686 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4752" />+ <path+ d="m 123.18936,218.21814 -0.63133,-0.26945 -0.49772,1.16617 0.64487,0.27524 0.0549,-0.12864 -0.48407,-0.2066 0.17048,-0.39945 0.39268,0.16759 0.0549,-0.12863 -0.39268,-0.1676 0.16254,-0.38082 0.45192,0.19288 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4754" />+ <path+ d="m 123.58728,219.76657 0.19126,0.0816 -0.0916,-0.65737 c 0.18922,0.0207 0.31576,-0.0413 0.38583,-0.20548 0.0932,-0.21835 -0.0115,-0.39507 -0.30259,-0.51932 l -0.30636,-0.13075 -0.49772,1.16618 0.1608,0.0686 0.21093,-0.49422 0.18111,0.0773 z m -0.19671,-0.81427 0.18059,-0.42314 0.14387,0.0614 c 0.19127,0.0816 0.24892,0.17626 0.18679,0.32182 -0.0672,0.15742 -0.18628,0.17862 -0.34876,0.10927 z"+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:1.84028506px;line-height:125%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans';text-align:start;letter-spacing:0px;word-spacing:-0.23003563px;writing-mode:lr-tb;text-anchor:start;fill:#6c6c6c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.23003563px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"+ id="path4756" />+ </g>+</svg>
+ src/data/pause-icon.svg view
@@ -0,0 +1,83 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!-- Created with Inkscape (http://www.inkscape.org/) -->++<svg+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"+ width="15"+ height="15"+ viewBox="0 0 3.9687499 3.9687501"+ version="1.1"+ id="svg8"+ inkscape:version="0.92.2 2405546, 2018-03-11"+ sodipodi:docname="pause-icon.svg">+ <defs+ id="defs2" />+ <sodipodi:namedview+ id="base"+ pagecolor="#ff09e5"+ bordercolor="#666666"+ borderopacity="1.0"+ inkscape:pageopacity="0"+ inkscape:pageshadow="2"+ inkscape:zoom="32"+ inkscape:cx="-0.82421836"+ inkscape:cy="8.9565174"+ inkscape:document-units="px"+ inkscape:current-layer="layer1"+ showgrid="true"+ units="px"+ inkscape:measure-start="30,0"+ inkscape:measure-end="30,15"+ showguides="true"+ inkscape:guide-bbox="true"+ inkscape:window-width="1920"+ inkscape:window-height="1152"+ inkscape:window-x="0"+ inkscape:window-y="320"+ inkscape:window-maximized="1"+ inkscape:snap-global="false"+ inkscape:showpageshadow="false">+ <inkscape:grid+ type="xygrid"+ id="grid815" />+ <sodipodi:guide+ position="8.9958331,3.9687501"+ orientation="0,1"+ id="guide819"+ inkscape:locked="false" />+ </sodipodi:namedview>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ inkscape:label="Layer 1"+ inkscape:groupmode="layer"+ id="layer1"+ transform="translate(0,-293.03123)">+ <path+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.49469224;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1107.35998535;stroke-opacity:0.90196078"+ d="m 1.0583333,296.74984 v -3.46847"+ id="path22947"+ inkscape:connector-curvature="0" />+ <path+ inkscape:connector-curvature="0"+ id="path22972"+ d="m 2.9104167,296.74984 v -3.46847"+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.49469224;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1107.35998535;stroke-opacity:0.90196078" />+ </g>+</svg>
+ src/data/play-icon.svg view
@@ -0,0 +1,77 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!-- Created with Inkscape (http://www.inkscape.org/) -->++<svg+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"+ width="15"+ height="15"+ viewBox="0 0 3.9687499 3.9687501"+ version="1.1"+ id="svg8"+ inkscape:version="0.92.2 2405546, 2018-03-11"+ sodipodi:docname="play-icon.svg">+ <defs+ id="defs2" />+ <sodipodi:namedview+ id="base"+ pagecolor="#ff09e5"+ bordercolor="#666666"+ borderopacity="1.0"+ inkscape:pageopacity="0"+ inkscape:pageshadow="2"+ inkscape:zoom="16"+ inkscape:cx="1.665001"+ inkscape:cy="15.661218"+ inkscape:document-units="px"+ inkscape:current-layer="layer1"+ showgrid="true"+ units="px"+ inkscape:measure-start="30,0"+ inkscape:measure-end="30,15"+ showguides="true"+ inkscape:guide-bbox="true"+ inkscape:window-width="1920"+ inkscape:window-height="1152"+ inkscape:window-x="0"+ inkscape:window-y="320"+ inkscape:window-maximized="1">+ <inkscape:grid+ type="xygrid"+ id="grid815" />+ <sodipodi:guide+ position="8.9958331,3.9687501"+ orientation="0,1"+ id="guide819"+ inkscape:locked="false" />+ </sodipodi:namedview>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ inkscape:label="Layer 1"+ inkscape:groupmode="layer"+ id="layer1"+ transform="translate(0,-293.03123)">+ <path+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:0.49019608;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.60342592;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1107.35998535;stroke-opacity:0.90196078;paint-order:fill markers stroke"+ d="m 0.30171295,293.33292 v 3.36536 l 3.36536195,-1.68267 z"+ id="path817"+ inkscape:connector-curvature="0"+ sodipodi:nodetypes="cccc" />+ </g>+</svg>
+ src/data/repeat-icon.svg view
@@ -0,0 +1,193 @@+<?xml version="1.0" encoding="UTF-8" standalone="no"?>+<!-- Created with Inkscape (http://www.inkscape.org/) -->++<svg+ xmlns:dc="http://purl.org/dc/elements/1.1/"+ xmlns:cc="http://creativecommons.org/ns#"+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"+ xmlns:svg="http://www.w3.org/2000/svg"+ xmlns="http://www.w3.org/2000/svg"+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"+ width="15"+ height="15"+ viewBox="0 0 3.9687499 3.9687501"+ version="1.1"+ id="svg8"+ inkscape:version="0.92.2 2405546, 2018-03-11"+ sodipodi:docname="repeat-icon.svg">+ <defs+ id="defs2">+ <marker+ inkscape:stockid="Arrow2Lend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow2Lend"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path882"+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#ffffff;stroke-opacity:0.90196078;fill:#ffffff;fill-opacity:1"+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "+ transform="scale(1.1) rotate(180) translate(1,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Mend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="marker6275"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path6273"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#ffffff;stroke-width:1pt;stroke-opacity:0.90196078;fill:#ffffff;fill-opacity:0.90196078"+ transform="scale(0.4) rotate(180) translate(10,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow2Mstart"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow2Mstart"+ style="overflow:visible"+ inkscape:isstock="true">+ <path+ id="path885"+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round;stroke:#000000;stroke-opacity:1;fill:#000000;fill-opacity:1"+ d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "+ transform="scale(0.6) translate(0,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Lstart"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow1Lstart"+ style="overflow:visible"+ inkscape:isstock="true">+ <path+ id="path861"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"+ transform="scale(0.8) translate(12.5,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Mend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="marker1171"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path1169"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"+ transform="scale(0.4) rotate(180) translate(10,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Mend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow1Mend"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path870"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"+ transform="scale(0.4) rotate(180) translate(10,0)" />+ </marker>+ <marker+ inkscape:stockid="Arrow1Lend"+ orient="auto"+ refY="0.0"+ refX="0.0"+ id="Arrow1Lend"+ style="overflow:visible;"+ inkscape:isstock="true">+ <path+ id="path864"+ d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"+ transform="scale(0.8) rotate(180) translate(12.5,0)" />+ </marker>+ </defs>+ <sodipodi:namedview+ id="base"+ pagecolor="#ff09e5"+ bordercolor="#666666"+ borderopacity="1.0"+ inkscape:pageopacity="0"+ inkscape:pageshadow="2"+ inkscape:zoom="45.254834"+ inkscape:cx="5.8605315"+ inkscape:cy="5.9160394"+ inkscape:document-units="px"+ inkscape:current-layer="layer1"+ showgrid="true"+ units="px"+ inkscape:measure-start="30,0"+ inkscape:measure-end="30,15"+ showguides="true"+ inkscape:guide-bbox="true"+ inkscape:window-width="1920"+ inkscape:window-height="1152"+ inkscape:window-x="0"+ inkscape:window-y="320"+ inkscape:window-maximized="1"+ inkscape:snap-global="false">+ <inkscape:grid+ type="xygrid"+ id="grid815" />+ <sodipodi:guide+ position="8.9958331,3.9687501"+ orientation="0,1"+ id="guide819"+ inkscape:locked="false" />+ </sodipodi:namedview>+ <metadata+ id="metadata5">+ <rdf:RDF>+ <cc:Work+ rdf:about="">+ <dc:format>image/svg+xml</dc:format>+ <dc:type+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />+ <dc:title></dc:title>+ </cc:Work>+ </rdf:RDF>+ </metadata>+ <g+ inkscape:label="Layer 1"+ inkscape:groupmode="layer"+ id="layer1"+ transform="translate(0,-293.03123)">+ <g+ id="g22945"+ transform="matrix(1.0076325,0,0,1.0076325,-0.00105415,-2.266855)">+ <path+ sodipodi:nodetypes="cc"+ inkscape:connector-curvature="0"+ id="path6259"+ d="m 3.051295,296.07098 0.6553377,-0.25987"+ style="opacity:1;vector-effect:none;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.14188077;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1107.35998535;stroke-opacity:0.90196078;marker-end:url(#Arrow2Lend)" />+ <path+ d="m 2.5531352,296.27574 a 1.6266046,1.5149276 0 0 1 -2.02684103,-0.85056 1.6266046,1.5149276 0 0 1 0.77738413,-1.93975 1.6266046,1.5149276 0 0 1 2.1295431,0.5943"+ sodipodi:open="true"+ sodipodi:end="5.7558666"+ sodipodi:start="1.2417907"+ sodipodi:ry="1.5149276"+ sodipodi:rx="1.6266046"+ sodipodi:cy="294.84207"+ sodipodi:cx="2.0275757"+ sodipodi:type="arc"+ id="path15490"+ style="opacity:1;fill:none;fill-opacity:0.49019608;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.5291667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.90196078;paint-order:fill markers stroke" />+ </g>+ </g>+</svg>
+ src/data/style-3-18.css view
@@ -0,0 +1,40 @@+/*+ Movie Monad+ (C) 2018 David Lettier+ lettier.com+*/++#play-pause-button image,+#about-button image,+#volume-button image,+#repeat-check-button image,+#repeat-check-button check,+#fullscreen-button image,+#play-pause-button image:hover,+#about-button image:hover,+#volume-button image:hover,+#repeat-check-button image:hover,+#fullscreen-button image:hover {+ text-decoration-color: transparent;+}++#repeat-check-button:checked {+ background-color: rgba(255, 255, 255, 0.1);+}++combobox button,+GtkComboBox .button {+ text-decoration: none;+}++menuitem,+GtkMenuItem,+menuitem:hover,+GtkMenuItem:hover {+ text-decoration: none;+}++menuitem cellview,+GtkMenuItem GtkCellView {+ text-decoration-color: transparent;+}
+ src/data/style-3-20.css view
@@ -0,0 +1,24 @@+/*+ Movie Monad+ (C) 2018 David Lettier+ lettier.com+*/++slider {+ min-width: 15px;+ min-height: 15px;+}++#play-pause-button image,+#about-button image,+#volume-button image,+#repeat-check-button image,+#repeat-check-button check,+#fullscreen-button image,+#play-pause-button image:hover,+#about-button image:hover,+#volume-button image:hover,+#repeat-check-button image:hover,+#fullscreen-button image:hover {+ -gtk-icon-shadow: none;+}
+ src/data/style.css view
@@ -0,0 +1,299 @@+/*+ Movie Monad+ (C) 2018 David Lettier+ lettier.com+*/++@define-color _movie_monad_black rgba(10, 10, 10, 0.8);+@define-color _movie_monad_white_nine rgba(255, 255, 255, 0.9);+@define-color _movie_monad_white_five rgba(255, 255, 255, 0.5);+@define-color _movie_monad_blue rgba(87, 172, 227, 1.0);+@define-color _movie_monad_pink rgba(224, 67, 127, 1.0);++@keyframes movie_monad_fade_in {+ from { opacity: 0; }+ to { opacity: 1; }+}++#bottom-controls-gtk-box {+ background-color: @_movie_monad_black;+ border-color: @_movie_monad_black;+ border-width: 1px;+ border-radius: 5px;+ padding: 5px;+ padding-left: 10px;+ padding-right: 10px;+ margin-bottom: 0px;+}++#play-pause-button,+#about-button,+#volume-button,+#volume-plus-button,+#volume-minus-button,+#repeat-check-button,+#fullscreen-button,+#window-width-selection-combo-box-text button.combo,+#subtitle-selection-combo-box-text button.combo,+#bottom-controls-gtk-box .button {+ background-color: transparent;+ border-color: transparent;+ border-width: 0px;+ border-radius: 5px;+ margin: 5px;+ background-image: none;+ color: white;+ box-shadow: none;+ text-shadow: none;+ border-image-source: none;+}++GtkBox#bottom-controls-gtk-box .button {+ padding-left: 7.5px;+ padding-right: 7.5px;+}++#play-pause-button image,+#about-button image,+#volume-button image,+#repeat-check-button image,+#repeat-check-button check,+#fullscreen-button image,+#play-pause-button image:hover,+#about-button image:hover,+#volume-button image:hover,+#repeat-check-button image:hover,+#fullscreen-button image:hover {+ text-shadow: none;+ border-color: transparent;+ border-top-color: transparent;+ border-bottom-color: transparent;+ border-left-color: transparent;+ border-right-color: transparent;+ background-image: none;+}++#play-pause-button:focus,+#about-button:focus,+#volume-button:focus,+#volume-plus-button:focus,+#volume-minus-button:focus,+#repeat-check-button:focus,+#fullscreen-button:focus,+#window-width-selection-combo-box-text button.combo:focus,+#subtitle-selection-combo-box-text button.combo:focus,+#play-pause-button image:focus,+#about-button image:focus,+#volume-button image:focus,+#repeat-check-button image:focus,+#repeat-check-button check:focus,+#fullscreen-button image:focus,+#play-pause-button image:focus,+#about-button image:focus,+#volume-button image:focus,+#repeat-check-button image:focus,+#fullscreen-button image:focus {+ outline-color: transparent;+ outline-offset: 0px;+ outline-width: 0px;+ outline-style: none;+ outline: none;+}++#play-pause-button:hover,+#about-button:hover,+#volume-button:hover,+#volume-plus-button:hover,+#volume-minus-button:hover,+#repeat-check-button:hover,+#repeat-check-button:active,+#fullscreen-button:hover,+#window-width-selection-combo-box-text button.combo:hover,+#subtitle-selection-combo-box-text button.combo:hover,+#window-width-selection-combo-box-text .button:hover {+ background-color: rgba(255, 255, 255, 0.1);+}++GtkScale {+ background-color: @_movie_monad_black;+ background-image: none;+ border-color: black;+ border: none;+ color: @_movie_monad_white_five;+}++GtkScale.horizontal {+ margin-left: 10px;+ margin-right: 10px;+}++scale slider {+ background-color: @_movie_monad_white_nine;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ background-image: none;+ box-shadow: none;+ border-radius: 100%;+ margin: -5px;+ padding: 0px;+}++#seek-scale .slider,+GtkPopover .slider {+ background-color: @_movie_monad_white_nine;+ margin: -3px;+}++GtkBox#bottom-controls-gtk-box .trough {+ margin-right: 10px;+ margin-left: 10px;+}++scale trough,+GtkScale .trough {+ background-color: rgba(0, 0, 0, 0.1);+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border-image: none;+ border: none;+ background-image: none;+}++scale trough:focus,+GtkScale .trough {+ outline-color: transparent;+ outline-offset: 0px;+ outline-width: 0px;+ outline-style: none;+ outline: none;+}++scale fill {+ background-color: rgba(0, 0, 0, 0.1);+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+}++scale highlight,+.highlight {+ background-color: @_movie_monad_blue;+ background-image: none;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+}++scale value {+ color: @_movie_monad_white_five;+ margin-bottom: 5px;+}++scale#seek-scale highlight,+GtkScale#seek-scale .highlight {+ background-image: linear-gradient(to right, @_movie_monad_blue 0%, @_movie_monad_pink 100%);+}++popover highlight,+GtkPopover .highlight {+ background-image: linear-gradient(to top, @_movie_monad_blue 0%, @_movie_monad_pink 100%);+}++combobox button,+GtkComboBox .button {+ color: white;+ text-shadow: none;+}++.scale-popup,+combobox menu,+GtkComboBox .menu {+ background-color: @_movie_monad_black;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+ box-shadow: none;+}++combobox window,+combobox decoration,+combobox arrow,+GtkComboBox .arrow {+ background-color: transparent;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ box-shadow: none;+}++menuitem,+GtkMenuItem {+ background-color: transparent;+ color: white;+ background-image: none;+ text-shadow: none;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+ box-shadow: none;+}++menuitem:hover,+GtkMenuItem:hover {+ background-color: @_movie_monad_white_nine;+ color: black;+ background-image: none;+ text-shadow: none;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+ box-shadow: none;+}++menuitem:focus,+GtkMenuItem:focus {+ outline-color: transparent;+ outline-offset: 0px;+ outline-width: 0px;+ outline-style: none;+ outline: none;+}++menuitem cellview,+GtkMenuItem GtkCellView {+ color: inherit;+}++arrow,+GtkMenu .arrow {+ text-shadow: none;+ color: white;+}++tooltip,+.tooltip {+ color: white;+ background-image: none;+ background-color: @_movie_monad_black;+ border-radius: 0px;+ border-color: @_movie_monad_black;+ border-width: 0px;+ border-style: none;+ border-image-source: none;+ border: none;+ box-shadow: none;+}++.movie-monad-fade-in {+ animation-name: movie_monad_fade_in;+ animation-duration: 1s;+ animation-timing-function: linear;+ animation-iteration-count: 1;+}
src/dev/Paths_movie_monad.hs view
@@ -1,6 +1,6 @@ {- Movie Monad- (C) 2017 David lettier+ (C) 2017 David Lettier lettier.com -}
stack.yaml view
@@ -1,14 +1,34 @@-flags: {}-extra-package-dbs: []+resolver: lts-9.1+compiler-check: match-exact packages: - '.'+extra-package-dbs: [] explicit-setup-deps: ! '*': true extra-deps:-- gi-gst-1.0.14-- gi-gtk-3.0.18+- haskell-gi-base-0.21.0+- haskell-gi-overloading-1.0+- haskell-gi-0.21.0+- gi-gobject-2.0.16+- gi-glib-2.0.16+- gi-gdk-3.0.15+- gi-gdkpixbuf-2.0.15+- gi-gst-1.0.15 - gi-gstbase-1.0.15-- gi-gstvideo-1.0.14-- haskell-gi-base-0.20.8-resolver: lts-9.1-compiler-check: match-exact+- gi-gstvideo-1.0.15+- gi-gtk-3.0.21+flags:+ gi-gobject:+ enable-overloading: false+ gi-glib:+ enable-overloading: false+ gi-gdk:+ enable-overloading: false+ gi-gdkpixbuf:+ enable-overloading: false+ gi-gst:+ enable-overloading: false+ gi-gstvideo:+ enable-overloading: false+ gi-gtk:+ enable-overloading: false